Skip to content

Commit e63fd07

Browse files
committed
impl: confirmation dialog for workspace deletion
Users are now required to confirm the workspace name if they want to delete a workspace. This is in order to avoid any accidental removals.
1 parent 05be524 commit e63fd07

File tree

5 files changed

+63
-39
lines changed

5 files changed

+63
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
### Changed
66

77
- workspaces status is now refresh every time Coder Toolbox becomes visible
8-
- improved workspace delete confirmation dialog
8+
- workspaces can no longer be removed by accident - users are now required to input the workspace name.
99

1010
### Fixed
1111

src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,18 @@ import com.coder.toolbox.sdk.v2.models.WorkspaceAgent
1212
import com.coder.toolbox.util.waitForFalseWithTimeout
1313
import com.coder.toolbox.util.withPath
1414
import com.coder.toolbox.views.Action
15+
import com.coder.toolbox.views.CoderDelimiter
1516
import com.coder.toolbox.views.EnvironmentView
1617
import com.jetbrains.toolbox.api.localization.LocalizableString
1718
import com.jetbrains.toolbox.api.remoteDev.AfterDisconnectHook
1819
import com.jetbrains.toolbox.api.remoteDev.BeforeConnectionHook
19-
import com.jetbrains.toolbox.api.remoteDev.DeleteEnvironmentConfirmationParams
2020
import com.jetbrains.toolbox.api.remoteDev.EnvironmentVisibilityState
2121
import com.jetbrains.toolbox.api.remoteDev.RemoteProviderEnvironment
2222
import com.jetbrains.toolbox.api.remoteDev.environments.EnvironmentContentsView
2323
import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentDescription
2424
import com.jetbrains.toolbox.api.remoteDev.states.RemoteEnvironmentState
2525
import com.jetbrains.toolbox.api.ui.actions.ActionDescription
26+
import com.jetbrains.toolbox.api.ui.components.TextType
2627
import com.squareup.moshi.Moshi
2728
import kotlinx.coroutines.Job
2829
import kotlinx.coroutines.delay
@@ -78,7 +79,7 @@ class CoderRemoteEnvironment(
7879
fun asPairOfWorkspaceAndAgent(): Pair<Workspace, WorkspaceAgent> = Pair(workspace, agent)
7980

8081
private fun getAvailableActions(): List<ActionDescription> {
81-
val actions = mutableListOf<Action>()
82+
val actions = mutableListOf<ActionDescription>()
8283
if (wsRawStatus.canStop()) {
8384
actions.add(Action(context.i18n.ptrl("Open web terminal")) {
8485
context.cs.launch {
@@ -143,6 +144,24 @@ class CoderRemoteEnvironment(
143144
}
144145
})
145146
}
147+
actions.add(CoderDelimiter(context.i18n.pnotr("")))
148+
actions.add(Action(context.i18n.ptrl("Delete workspace")) {
149+
context.cs.launch {
150+
val confirmation = context.ui.showTextInputPopup(
151+
if (wsRawStatus.canStop()) context.i18n.ptrl("Delete running workspace?") else context.i18n.ptrl("Delete workspace?"),
152+
if (wsRawStatus.canStop()) context.i18n.ptrl("This will close the workspace and remove all its information, including files, unsaved changes, history, and usage data.")
153+
else context.i18n.ptrl("This will remove all information from the workspace, including files, unsaved changes, history, and usage data."),
154+
context.i18n.ptrl("Workspace name"),
155+
TextType.General,
156+
context.i18n.ptrl("OK"),
157+
context.i18n.ptrl("Cancel")
158+
)
159+
if (confirmation != workspace.name) {
160+
return@launch
161+
}
162+
deleteWorkspace()
163+
}
164+
})
146165
return actions
147166
}
148167

@@ -272,43 +291,32 @@ class CoderRemoteEnvironment(
272291
return false
273292
}
274293

275-
override fun getDeleteEnvironmentConfirmationParams(): DeleteEnvironmentConfirmationParams? {
276-
return object : DeleteEnvironmentConfirmationParams {
277-
override val cancelButtonText: String = "Cancel"
278-
override val confirmButtonText: String = "Delete"
279-
override val message: String =
280-
if (wsRawStatus.canStop()) "This will close the workspace and remove all its information, including files, unsaved changes, history, and usage data."
281-
else "This will remove all information from the workspace, including files, unsaved changes, history, and usage data."
282-
override val title: String = if (wsRawStatus.canStop()) "Delete running workspace?" else "Delete workspace?"
283-
}
284-
}
294+
override val deleteActionFlow: StateFlow<(() -> Unit)?> = MutableStateFlow(null)
285295

286-
override val deleteActionFlow: StateFlow<(() -> Unit)?> = MutableStateFlow {
287-
context.cs.launch {
288-
try {
289-
client.removeWorkspace(workspace)
290-
// mark the env as deleting otherwise we will have to
291-
// wait for the poller to update the status in the next 5 seconds
292-
state.update {
293-
WorkspaceAndAgentStatus.DELETING.toRemoteEnvironmentState(context)
294-
}
296+
suspend fun deleteWorkspace() {
297+
try {
298+
client.removeWorkspace(workspace)
299+
// mark the env as deleting otherwise we will have to
300+
// wait for the poller to update the status in the next 5 seconds
301+
state.update {
302+
WorkspaceAndAgentStatus.DELETING.toRemoteEnvironmentState(context)
303+
}
295304

296-
context.cs.launch {
297-
withTimeout(5.minutes) {
298-
var workspaceStillExists = true
299-
while (context.cs.isActive && workspaceStillExists) {
300-
if (wsRawStatus == WorkspaceAndAgentStatus.DELETING || wsRawStatus == WorkspaceAndAgentStatus.DELETED) {
301-
workspaceStillExists = false
302-
context.envPageManager.showPluginEnvironmentsPage()
303-
} else {
304-
delay(1.seconds)
305-
}
305+
context.cs.launch {
306+
withTimeout(5.minutes) {
307+
var workspaceStillExists = true
308+
while (context.cs.isActive && workspaceStillExists) {
309+
if (wsRawStatus == WorkspaceAndAgentStatus.DELETING || wsRawStatus == WorkspaceAndAgentStatus.DELETED) {
310+
workspaceStillExists = false
311+
context.envPageManager.showPluginEnvironmentsPage()
312+
} else {
313+
delay(1.seconds)
306314
}
307315
}
308316
}
309-
} catch (e: APIResponseException) {
310-
context.ui.showErrorInfoPopup(e)
311317
}
318+
} catch (e: APIResponseException) {
319+
context.ui.showErrorInfoPopup(e)
312320
}
313321
}
314322

src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.coder.toolbox.util.waitForTrue
1111
import com.coder.toolbox.util.withPath
1212
import com.coder.toolbox.views.Action
1313
import com.coder.toolbox.views.CoderCliSetupWizardPage
14+
import com.coder.toolbox.views.CoderDelimiter
1415
import com.coder.toolbox.views.CoderSettingsPage
1516
import com.coder.toolbox.views.NewEnvironmentPage
1617
import com.coder.toolbox.views.state.CoderCliSetupWizardState
@@ -21,7 +22,6 @@ import com.jetbrains.toolbox.api.core.util.LoadableState
2122
import com.jetbrains.toolbox.api.localization.LocalizableString
2223
import com.jetbrains.toolbox.api.remoteDev.ProviderVisibilityState
2324
import com.jetbrains.toolbox.api.remoteDev.RemoteProvider
24-
import com.jetbrains.toolbox.api.ui.actions.ActionDelimiter
2525
import com.jetbrains.toolbox.api.ui.actions.ActionDescription
2626
import com.jetbrains.toolbox.api.ui.components.UiPage
2727
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -416,6 +416,4 @@ class CoderRemoteProvider(
416416
LoadableState.Loading
417417
}
418418
}
419-
}
420-
421-
private class CoderDelimiter(override val label: LocalizableString) : ActionDelimiter
419+
}

src/main/kotlin/com/coder/toolbox/views/CoderPage.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.coder.toolbox.CoderToolboxContext
44
import com.jetbrains.toolbox.api.core.ui.icons.SvgIcon
55
import com.jetbrains.toolbox.api.core.ui.icons.SvgIcon.IconType
66
import com.jetbrains.toolbox.api.localization.LocalizableString
7+
import com.jetbrains.toolbox.api.ui.actions.ActionDelimiter
78
import com.jetbrains.toolbox.api.ui.actions.RunnableActionDescription
89
import com.jetbrains.toolbox.api.ui.components.UiPage
910
import kotlinx.coroutines.flow.MutableStateFlow
@@ -67,3 +68,5 @@ class Action(
6768
actionBlock()
6869
}
6970
}
71+
72+
class CoderDelimiter(override val label: LocalizableString) : ActionDelimiter

src/main/resources/localization/defaultMessages.po

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,19 @@ msgid "Headers"
179179
msgstr ""
180180

181181
msgid "Body"
182-
msgstr ""
182+
msgstr ""
183+
184+
msgid "Delete workspace"
185+
msgstr ""
186+
187+
msgid "Delete running workspace?"
188+
msgstr ""
189+
190+
msgid "This will close the workspace and remove all its information, including files, unsaved changes, history, and usage data."
191+
msgstr ""
192+
193+
msgid "This will remove all information from the workspace, including files, unsaved changes, history, and usage data."
194+
msgstr ""
195+
196+
msgid "Workspace name"
197+
msgstr ""

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy