@@ -10,7 +10,7 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
10
10
@State private var editingSession : FileSyncSession ?
11
11
12
12
@State private var loading : Bool = false
13
- @State private var deleteError : DaemonError ?
13
+ @State private var actionError : DaemonError ?
14
14
@State private var isVisible : Bool = false
15
15
@State private var dontRetry : Bool = false
16
16
@@ -50,14 +50,14 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
50
50
FileSyncSessionModal < VPN , FS > ( existingSession: session)
51
51
. frame ( width: 700 )
52
52
} . alert ( " Error " , isPresented: Binding (
53
- get: { deleteError != nil } ,
53
+ get: { actionError != nil } ,
54
54
set: { isPresented in
55
55
if !isPresented {
56
- deleteError = nil
56
+ actionError = nil
57
57
}
58
58
}
59
59
) ) { } message: {
60
- Text ( deleteError ? . description ?? " An unknown error occurred. " )
60
+ Text ( actionError ? . description ?? " An unknown error occurred. " )
61
61
} . alert ( " Error " , isPresented: Binding (
62
62
// We only show the alert if the file config window is open
63
63
// Users will see the alert symbol on the menu bar to prompt them to
@@ -118,7 +118,7 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
118
118
addingNewSession = true
119
119
} label: {
120
120
Image ( systemName: " plus " )
121
- . frame ( width: 24 , height: 24 )
121
+ . frame ( width: 24 , height: 24 ) . help ( " Create " )
122
122
} . disabled ( vpn. menuState. agents. isEmpty)
123
123
Divider ( )
124
124
Button {
@@ -133,43 +133,72 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
133
133
await fileSync. stop ( )
134
134
}
135
135
} catch {
136
- deleteError = error
136
+ actionError = error
137
137
}
138
138
selection = nil
139
139
}
140
140
} label: {
141
- Image ( systemName: " minus " ) . frame ( width: 24 , height: 24 )
141
+ Image ( systemName: " minus " ) . frame ( width: 24 , height: 24 ) . help ( " Delete " )
142
142
} . disabled ( selection == nil )
143
- if let selection {
144
- if let selectedSession = fileSync. sessionState. first ( where: { $0. id == selection } ) {
145
- Divider ( )
146
- Button {
147
- Task {
148
- // TODO: Support pausing & resuming multiple sessions at once
149
- loading = true
150
- defer { loading = false }
143
+ sessionControls
144
+ }
145
+ . buttonStyle ( . borderless)
146
+ }
147
+ . background ( . primary. opacity ( 0.04 ) )
148
+ . fixedSize ( horizontal: false , vertical: true )
149
+ }
150
+
151
+ var sessionControls : some View {
152
+ Group {
153
+ if let selection {
154
+ if let selectedSession = fileSync. sessionState. first ( where: { $0. id == selection } ) {
155
+ Divider ( )
156
+ Button {
157
+ Task {
158
+ // TODO: Support pausing & resuming multiple sessions at once
159
+ loading = true
160
+ defer { loading = false }
161
+ do throws ( DaemonError) {
151
162
switch selectedSession. status {
152
- case . paused:
163
+ case . paused, . error( . haltedOnRootEmptied) ,
164
+ . error( . haltedOnRootDeletion) ,
165
+ . error( . haltedOnRootTypeChange) :
153
166
try await fileSync. resumeSessions ( ids: [ selectedSession. id] )
154
167
default :
155
168
try await fileSync. pauseSessions ( ids: [ selectedSession. id] )
156
169
}
170
+ } catch {
171
+ actionError = error
157
172
}
158
- } label: {
159
- switch selectedSession. status {
160
- case . paused:
161
- Image ( systemName: " play " ) . frame ( width: 24 , height: 24 )
162
- default :
163
- Image ( systemName: " pause " ) . frame ( width: 24 , height: 24 )
173
+ }
174
+ } label: {
175
+ switch selectedSession. status {
176
+ case . paused, . error( . haltedOnRootEmptied) ,
177
+ . error( . haltedOnRootDeletion) ,
178
+ . error( . haltedOnRootTypeChange) :
179
+ Image ( systemName: " play " ) . frame ( width: 24 , height: 24 ) . help ( " Pause " )
180
+ default :
181
+ Image ( systemName: " pause " ) . frame ( width: 24 , height: 24 ) . help ( " Resume " )
182
+ }
183
+ }
184
+ Divider ( )
185
+ Button {
186
+ Task {
187
+ // TODO: Support restarting multiple sessions at once
188
+ loading = true
189
+ defer { loading = false }
190
+ do throws ( DaemonError) {
191
+ try await fileSync. resetSessions ( ids: [ selectedSession. id] )
192
+ } catch {
193
+ actionError = error
164
194
}
165
195
}
196
+ } label: {
197
+ Image ( systemName: " arrow.clockwise " ) . frame ( width: 24 , height: 24 ) . help ( " Reset " )
166
198
}
167
199
}
168
200
}
169
- . buttonStyle ( . borderless)
170
201
}
171
- . background ( . primary. opacity ( 0.04 ) )
172
- . fixedSize ( horizontal: false , vertical: true )
173
202
}
174
203
}
175
204
0 commit comments