Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit85fb12e

Browse files
committed
feat: support restarting file sync sessions
1 parent8d3ca31 commit85fb12e

File tree

5 files changed

+79
-28
lines changed

5 files changed

+79
-28
lines changed

‎Coder-Desktop/Coder-Desktop/Preview Content/PreviewFileSync.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ final class PreviewFileSync: FileSyncDaemon {
2727
func pauseSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
2828

2929
func resumeSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
30+
31+
func resetSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
3032
}

‎Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
1010
@StateprivatevareditingSession:FileSyncSession?
1111

1212
@Stateprivatevarloading:Bool=false
13-
@StateprivatevardeleteError:DaemonError?
13+
@StateprivatevaractionError:DaemonError?
1414
@StateprivatevarisVisible:Bool=false
1515
@StateprivatevardontRetry:Bool=false
1616

@@ -50,14 +50,14 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
5050
FileSyncSessionModal<VPN,FS>(existingSession: session)
5151
.frame(width:700)
5252
}.alert("Error", isPresented:Binding(
53-
get:{deleteError!=nil},
53+
get:{actionError!=nil},
5454
set:{ isPresentedin
5555
if !isPresented{
56-
deleteError=nil
56+
actionError=nil
5757
}
5858
}
5959
)){} message:{
60-
Text(deleteError?.description??"An unknown error occurred.")
60+
Text(actionError?.description??"An unknown error occurred.")
6161
}.alert("Error", isPresented:Binding(
6262
// We only show the alert if the file config window is open
6363
// 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 {
118118
addingNewSession=true
119119
} label:{
120120
Image(systemName:"plus")
121-
.frame(width:24, height:24)
121+
.frame(width:24, height:24).help("Create")
122122
}.disabled(vpn.menuState.agents.isEmpty)
123123
Divider()
124124
Button{
@@ -133,43 +133,72 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View {
133133
await fileSync.stop()
134134
}
135135
} catch{
136-
deleteError= error
136+
actionError= error
137137
}
138138
selection=nil
139139
}
140140
} label:{
141-
Image(systemName:"minus").frame(width:24, height:24)
141+
Image(systemName:"minus").frame(width:24, height:24).help("Delete")
142142
}.disabled(selection==nil)
143-
iflet selection{
144-
iflet 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+
varsessionControls:someView{
152+
Group{
153+
iflet selection{
154+
iflet 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+
dothrows(DaemonError){
151162
switch selectedSession.status{
152-
case.paused:
163+
case.paused,.error(.haltedOnRootEmptied),
164+
.error(.haltedOnRootDeletion),
165+
.error(.haltedOnRootTypeChange):
153166
tryawait fileSync.resumeSessions(ids:[selectedSession.id])
154167
default:
155168
tryawait fileSync.pauseSessions(ids:[selectedSession.id])
156169
}
170+
} catch{
171+
actionError= error
157172
}
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+
dothrows(DaemonError){
191+
tryawait fileSync.resetSessions(ids:[selectedSession.id])
192+
} catch{
193+
actionError= error
164194
}
165195
}
196+
} label:{
197+
Image(systemName:"arrow.clockwise").frame(width:24, height:24).help("Reset")
166198
}
167199
}
168200
}
169-
.buttonStyle(.borderless)
170201
}
171-
.background(.primary.opacity(0.04))
172-
.fixedSize(horizontal:false, vertical:true)
173202
}
174203
}
175204

‎Coder-Desktop/Coder-DesktopTests/Util.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class MockFileSyncDaemon: FileSyncDaemon {
5252
func pauseSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
5353

5454
func resumeSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
55+
56+
func resetSessions(ids _:[String])asyncthrows(VPNLib.DaemonError){}
5557
}
5658

5759
extensionInspection:@uncheckedSendable,@retroactiveInspectionEmissary{}

‎Coder-Desktop/VPNLib/FileSync/FileSyncDaemon.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public protocol FileSyncDaemon: ObservableObject {
1818
func deleteSessions(ids:[String])asyncthrows(DaemonError)
1919
func pauseSessions(ids:[String])asyncthrows(DaemonError)
2020
func resumeSessions(ids:[String])asyncthrows(DaemonError)
21+
func resetSessions(ids:[String])asyncthrows(DaemonError)
2122
}
2223

2324
@MainActor

‎Coder-Desktop/VPNLib/FileSync/FileSyncManagement.swift

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,8 @@ public extension MutagenDaemon {
100100
}
101101

102102
func resumeSessions(ids:[String])asyncthrows(DaemonError){
103-
// Resuming sessions does not require prompting, according to the
104-
// Mutagen CLI
105-
let(stream, promptID)=tryawaithost(allowPrompts:false)
103+
// Resuming sessions does use prompting, as it may start a new SSH connection
104+
let(stream, promptID)=tryawaithost(allowPrompts:true)
106105
defer{ stream.cancel()}
107106
guard case.running= stateelse{return}
108107
do{
@@ -117,4 +116,22 @@ public extension MutagenDaemon {
117116
}
118117
awaitrefreshSessions()
119118
}
119+
120+
func resetSessions(ids:[String])asyncthrows(DaemonError){
121+
// Resetting a session involves pausing & resuming, so it does use prompting
122+
let(stream, promptID)=tryawaithost(allowPrompts:true)
123+
defer{ stream.cancel()}
124+
guard case.running= stateelse{return}
125+
do{
126+
_=tryawait client!.sync.reset(Synchronization_ResetRequest.with{ reqin
127+
req.prompter= promptID
128+
req.selection=.with{ selectionin
129+
selection.specifications= ids
130+
}
131+
}, callOptions:.init(timeLimit:.timeout(sessionMgmtReqTimeout)))
132+
}catch{
133+
throw.grpcFailure(error)
134+
}
135+
awaitrefreshSessions()
136+
}
120137
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp