From 92b79696a37859898728f5f287e1dca1abe98b64 Mon Sep 17 00:00:00 2001 From: Ethan Dickson <ethan@coder.com> Date: Thu, 3 Apr 2025 21:06:15 +1100 Subject: [PATCH 1/4] fix: improve file sync agent picker --- .../Views/FileSync/FileSyncConfig.swift | 4 +--- .../Views/FileSync/FileSyncSessionModal.swift | 17 +++++++++-------- .../Coder-Desktop/Views/VPN/VPNMenu.swift | 9 +++++++++ 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift index 345928b..a3fac2b 100644 --- a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift +++ b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift @@ -107,9 +107,7 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View { // When the Window is visible, poll for session updates every // two seconds. while !Task.isCancelled { - if !fileSync.state.isFailed { - await fileSync.refreshSessions() - } + await fileSync.refreshSessions() try? await Task.sleep(for: .seconds(2)) } }.onAppear { diff --git a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift index d398172..065eeb5 100644 --- a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift +++ b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift @@ -8,7 +8,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { @EnvironmentObject private var fileSync: FS @State private var localPath: String = "" - @State private var workspace: Agent? + @State private var chosenAgent: String? @State private var remotePath: String = "" @State private var loading: Bool = false @@ -37,12 +37,12 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { } } Section { - Picker("Workspace", selection: $workspace) { + Picker("Workspace", selection: $chosenAgent) { ForEach(agents, id: \.id) { agent in - Text(agent.primaryHost!).tag(agent) + Text(agent.primaryHost!).tag(agent.primaryHost!) } // HACK: Silence error logs for no-selection. - Divider().tag(nil as Agent?) + Divider().tag(nil as String?) } } Section { @@ -55,15 +55,16 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { Button("Cancel", action: { dismiss() }).keyboardShortcut(.cancelAction) Button(existingSession == nil ? "Add" : "Save") { Task { await submit() }} .keyboardShortcut(.defaultAction) + .disabled(localPath.isEmpty || remotePath.isEmpty || chosenAgent == nil) }.padding(20) }.onAppear { if let existingSession { localPath = existingSession.alphaPath - workspace = agents.first { $0.primaryHost == existingSession.agentHost } + chosenAgent = agents.first { $0.primaryHost == existingSession.agentHost }?.primaryHost remotePath = existingSession.betaPath } else { // Set the picker to the first agent by default - workspace = agents.first + chosenAgent = agents.first?.primaryHost } }.disabled(loading) .alert("Error", isPresented: Binding( @@ -76,7 +77,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { func submit() async { createError = nil - guard let workspace else { + guard let chosenAgent else { return } loading = true @@ -87,7 +88,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { } try await fileSync.createSession( localPath: localPath, - agentHost: workspace.primaryHost!, + agentHost: chosenAgent, remotePath: remotePath ) } catch { diff --git a/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift b/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift index 207f0d9..c1da06d 100644 --- a/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift +++ b/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift @@ -116,6 +116,15 @@ struct VPNMenu<VPN: VPNService, FS: FileSyncDaemon>: View { .environmentObject(vpn) .environmentObject(state) .onReceive(inspection.notice) { inspection.visit(self, $0) } // ViewInspector + .task { + // If there's a file sync session error, an icon will be displayed + // next to the file sync button. The file sync window polls more + // frequently when it's open. + while !Task.isCancelled { + await fileSync.refreshSessions() + try? await Task.sleep(for: .seconds(15)) + } + } } private var vpnDisabled: Bool { From 0997c9d63195739520abc777f19c9133818c2b62 Mon Sep 17 00:00:00 2001 From: Ethan Dickson <ethan@coder.com> Date: Fri, 4 Apr 2025 13:43:54 +1100 Subject: [PATCH 2/4] review --- .../Coder-Desktop/Views/FileSync/FileSyncConfig.swift | 7 ------- Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift | 5 +---- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift index a3fac2b..dc946c8 100644 --- a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift +++ b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncConfig.swift @@ -103,13 +103,6 @@ struct FileSyncConfig<VPN: VPNService, FS: FileSyncDaemon>: View { // Opens the log file in Console NSWorkspace.shared.open(fileSync.logFile) } - }.task { - // When the Window is visible, poll for session updates every - // two seconds. - while !Task.isCancelled { - await fileSync.refreshSessions() - try? await Task.sleep(for: .seconds(2)) - } }.onAppear { isVisible = true }.onDisappear { diff --git a/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift b/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift index c1da06d..83757ef 100644 --- a/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift +++ b/Coder-Desktop/Coder-Desktop/Views/VPN/VPNMenu.swift @@ -117,12 +117,9 @@ struct VPNMenu<VPN: VPNService, FS: FileSyncDaemon>: View { .environmentObject(state) .onReceive(inspection.notice) { inspection.visit(self, $0) } // ViewInspector .task { - // If there's a file sync session error, an icon will be displayed - // next to the file sync button. The file sync window polls more - // frequently when it's open. while !Task.isCancelled { await fileSync.refreshSessions() - try? await Task.sleep(for: .seconds(15)) + try? await Task.sleep(for: .seconds(2)) } } } From 3c12680d9b73392f38a037bc995ce239e533da5f Mon Sep 17 00:00:00 2001 From: Ethan Dickson <ethan@coder.com> Date: Mon, 7 Apr 2025 12:48:01 +1000 Subject: [PATCH 3/4] review --- .../Views/FileSync/FileSyncSessionModal.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift index 065eeb5..160c94b 100644 --- a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift +++ b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift @@ -8,7 +8,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { @EnvironmentObject private var fileSync: FS @State private var localPath: String = "" - @State private var chosenAgent: String? + @State private var remoteHostName: String? @State private var remotePath: String = "" @State private var loading: Bool = false @@ -37,7 +37,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { } } Section { - Picker("Workspace", selection: $chosenAgent) { + Picker("Workspace", selection: $remoteHostName) { ForEach(agents, id: \.id) { agent in Text(agent.primaryHost!).tag(agent.primaryHost!) } @@ -55,16 +55,16 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { Button("Cancel", action: { dismiss() }).keyboardShortcut(.cancelAction) Button(existingSession == nil ? "Add" : "Save") { Task { await submit() }} .keyboardShortcut(.defaultAction) - .disabled(localPath.isEmpty || remotePath.isEmpty || chosenAgent == nil) + .disabled(localPath.isEmpty || remotePath.isEmpty || remoteHostName == nil) }.padding(20) }.onAppear { if let existingSession { localPath = existingSession.alphaPath - chosenAgent = agents.first { $0.primaryHost == existingSession.agentHost }?.primaryHost + remoteHostName = agents.first { $0.primaryHost == existingSession.agentHost }?.primaryHost remotePath = existingSession.betaPath } else { // Set the picker to the first agent by default - chosenAgent = agents.first?.primaryHost + remoteHostName = agents.first?.primaryHost } }.disabled(loading) .alert("Error", isPresented: Binding( @@ -77,7 +77,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { func submit() async { createError = nil - guard let chosenAgent else { + guard let remoteHostName else { return } loading = true @@ -88,7 +88,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { } try await fileSync.createSession( localPath: localPath, - agentHost: chosenAgent, + agentHost: remoteHostName, remotePath: remotePath ) } catch { From a3518f2d48d6bb620dc122d08877be258ecbf6ae Mon Sep 17 00:00:00 2001 From: Ethan Dickson <ethan@coder.com> Date: Mon, 7 Apr 2025 16:47:07 +1000 Subject: [PATCH 4/4] review --- .../Views/FileSync/FileSyncSessionModal.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift index 160c94b..0e42ea0 100644 --- a/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift +++ b/Coder-Desktop/Coder-Desktop/Views/FileSync/FileSyncSessionModal.swift @@ -8,7 +8,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { @EnvironmentObject private var fileSync: FS @State private var localPath: String = "" - @State private var remoteHostName: String? + @State private var remoteHostname: String? @State private var remotePath: String = "" @State private var loading: Bool = false @@ -37,7 +37,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { } } Section { - Picker("Workspace", selection: $remoteHostName) { + Picker("Workspace", selection: $remoteHostname) { ForEach(agents, id: \.id) { agent in Text(agent.primaryHost!).tag(agent.primaryHost!) } @@ -55,16 +55,16 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { Button("Cancel", action: { dismiss() }).keyboardShortcut(.cancelAction) Button(existingSession == nil ? "Add" : "Save") { Task { await submit() }} .keyboardShortcut(.defaultAction) - .disabled(localPath.isEmpty || remotePath.isEmpty || remoteHostName == nil) + .disabled(localPath.isEmpty || remotePath.isEmpty || remoteHostname == nil) }.padding(20) }.onAppear { if let existingSession { localPath = existingSession.alphaPath - remoteHostName = agents.first { $0.primaryHost == existingSession.agentHost }?.primaryHost + remoteHostname = agents.first { $0.primaryHost == existingSession.agentHost }?.primaryHost remotePath = existingSession.betaPath } else { // Set the picker to the first agent by default - remoteHostName = agents.first?.primaryHost + remoteHostname = agents.first?.primaryHost } }.disabled(loading) .alert("Error", isPresented: Binding( @@ -77,7 +77,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { func submit() async { createError = nil - guard let remoteHostName else { + guard let remoteHostname else { return } loading = true @@ -88,7 +88,7 @@ struct FileSyncSessionModal<VPN: VPNService, FS: FileSyncDaemon>: View { } try await fileSync.createSession( localPath: localPath, - agentHost: remoteHostName, + agentHost: remoteHostname, remotePath: remotePath ) } catch {