From ef3392bab9fd0b253dbb5391ae7fc9c03f379ba8 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Wed, 2 Apr 2025 23:20:36 +0300 Subject: [PATCH 1/4] fix: override default delete confirmation dialog - right now there are two confirmation dialogs when removing a workspace from Toolbox - with this patch we force Toolbox to discard its default dialog and show a custom one with the Coder titles and messages. --- CHANGELOG.md | 1 + .../coder/toolbox/CoderRemoteEnvironment.kt | 55 +++++++++---------- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd981fe..669afa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Fixed - SSH config is regenerated correctly when Workspaces are added or removed +- only one confirmation dialog is shown when removing a Workspace ## 0.1.0 - 2025-04-01 diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt index 8319cdc..77b0df3 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt @@ -9,6 +9,7 @@ import com.coder.toolbox.sdk.v2.models.WorkspaceAgent import com.coder.toolbox.util.withPath import com.coder.toolbox.views.Action import com.coder.toolbox.views.EnvironmentView +import com.jetbrains.toolbox.api.remoteDev.DeleteEnvironmentConfirmationParams import com.jetbrains.toolbox.api.remoteDev.EnvironmentVisibilityState import com.jetbrains.toolbox.api.remoteDev.RemoteProviderEnvironment import com.jetbrains.toolbox.api.remoteDev.environments.EnvironmentContentsView @@ -149,42 +150,36 @@ class CoderRemoteEnvironment( } } + override fun getDeleteEnvironmentConfirmationParams(): DeleteEnvironmentConfirmationParams? { + return object : DeleteEnvironmentConfirmationParams { + override val cancelButtonText: String = "Cancel" + override val confirmButtonText: String = "Delete" + override val message: String = + if (wsRawStatus.canStop()) "Workspace will be closed and all the information will be lost, including all files, unsaved changes, historical info and usage data." + else "All the information in this workspace will be lost, including all files, unsaved changes, historical info and usage data." + override val title: String = if (wsRawStatus.canStop()) "Delete running workspace?" else "Delete workspace?" + } + } + override fun onDelete() { context.cs.launch { - val shouldDelete = if (wsRawStatus.canStop()) { - context.ui.showOkCancelPopup( - context.i18n.ptrl("Delete running workspace?"), - context.i18n.ptrl("Workspace will be closed and all the information in this workspace will be lost, including all files, unsaved changes and historical."), - context.i18n.ptrl("Delete"), - context.i18n.ptrl("Cancel") - ) - } else { - context.ui.showOkCancelPopup( - context.i18n.ptrl("Delete workspace?"), - context.i18n.ptrl("All the information in this workspace will be lost, including all files, unsaved changes and historical."), - context.i18n.ptrl("Delete"), - context.i18n.ptrl("Cancel") - ) - } - if (shouldDelete) { - try { - client.removeWorkspace(workspace) - context.cs.launch { - withTimeout(5.minutes) { - var workspaceStillExists = true - while (context.cs.isActive && workspaceStillExists) { - if (wsRawStatus == WorkspaceAndAgentStatus.DELETING || wsRawStatus == WorkspaceAndAgentStatus.DELETED) { - workspaceStillExists = false - context.envPageManager.showPluginEnvironmentsPage() - } else { - delay(1.seconds) - } + try { + client.removeWorkspace(workspace) + context.cs.launch { + withTimeout(5.minutes) { + var workspaceStillExists = true + while (context.cs.isActive && workspaceStillExists) { + if (wsRawStatus == WorkspaceAndAgentStatus.DELETING || wsRawStatus == WorkspaceAndAgentStatus.DELETED) { + workspaceStillExists = false + context.envPageManager.showPluginEnvironmentsPage() + } else { + delay(1.seconds) } } } - } catch (e: APIResponseException) { - context.ui.showErrorInfoPopup(e) } + } catch (e: APIResponseException) { + context.ui.showErrorInfoPopup(e) } } } From 5cd6e73c4ebac43cb7ba99ca7fb22ebe4dddb41d Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Wed, 2 Apr 2025 23:24:33 +0300 Subject: [PATCH 2/4] chore: remove unused i18n strings - no longer valid after delete confirmation dialog is using the new api --- .../resources/localization/defaultMessages.po | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/main/resources/localization/defaultMessages.po b/src/main/resources/localization/defaultMessages.po index f109f4f..c3ac778 100644 --- a/src/main/resources/localization/defaultMessages.po +++ b/src/main/resources/localization/defaultMessages.po @@ -28,24 +28,9 @@ msgstr "" msgid "Save" msgstr "" -msgid "Delete" -msgstr "" - msgid "Cancel" msgstr "" -msgid "Delete running workspace?" -msgstr "" - -msgid "Delete workspace?" -msgstr "" - -msgid "Workspace will be closed and all the information in this workspace will be lost, including all files, unsaved changes and historical." -msgstr "" - -msgid "All the information in this workspace will be lost, including all files, unsaved changes and historical." -msgstr "" - msgid "Session Token" msgstr "" From 7091e3ba46f886ac2fc1efb433ff0a6e1d391073 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Wed, 2 Apr 2025 23:50:09 +0300 Subject: [PATCH 3/4] fix: immediately mark the workspace as deleting - workspace status is usually updated every 5 seconds by the polling loop. - that's a bit problematic because when we delete a workspace we have to wait a couple of seconds until we have some visual feedback. - with this patch we force the workspace status to be in "deleting" if the REST api call was succesfull. --- src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt index 77b0df3..ccdf622 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt @@ -165,6 +165,12 @@ class CoderRemoteEnvironment( context.cs.launch { try { client.removeWorkspace(workspace) + // mark the env as deleting otherwise we will have to + // wait for the poller to update the status in the next 5 seconds + state.update { + WorkspaceAndAgentStatus.DELETING.toRemoteEnvironmentState(context) + } + context.cs.launch { withTimeout(5.minutes) { var workspaceStillExists = true From c9c67cc13d3a8185e1399172787c76c22f866477 Mon Sep 17 00:00:00 2001 From: Faur Ioan-Aurel Date: Wed, 2 Apr 2025 23:54:10 +0300 Subject: [PATCH 4/4] fix: always show the workspaces in the same order - right now we depend on the underlying okhttp/moshi marshaller on which order the workspaces are listed. - instead we can sort them by name and guarantee some consistency --- src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt index 4ce1bc7..9939645 100644 --- a/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt +++ b/src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt @@ -131,7 +131,7 @@ class CoderRemoteProvider( } lastEnvironments.apply { clear() - addAll(resolvedEnvironments) + addAll(resolvedEnvironments.sortedBy { it.id }) } } catch (_: CancellationException) { context.logger.debug("${client.url} polling loop canceled")