From 426ab2dd213979758ba8915a8bc7814bf3d31a77 Mon Sep 17 00:00:00 2001 From: tristantr Date: Thu, 30 Oct 2025 11:13:12 +0100 Subject: [PATCH 1/4] Add destructive props for Delete workspace action --- .../src/routes/(root)/(logged)/workspace_settings/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte index fd4780ebb09a4..f232570c390e8 100644 --- a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte @@ -755,7 +755,7 @@ {#if $superadmin} @@ -759,13 +759,7 @@ disabled={$workspaceStore === 'admins' || $workspaceStore === 'starter'} size="sm" btnClasses="mt-2" - on:click={async () => { - await WorkspaceService.deleteWorkspace({ workspace: $workspaceStore ?? '' }) - sendUserToast(`Deleted workspace ${$workspaceStore}`) - workspaceStore.set(undefined) - usersWorkspaceStore.set(undefined) - goto('/user/workspaces') - }} + on:click={() => (deleteModalOpen = true)} > Delete workspace (superadmin) @@ -1050,5 +1044,60 @@ tabMode={true} /> + { + isProcessingWorkspaceDeletion = true + try { + await WorkspaceService.archiveWorkspace({ workspace: $workspaceStore ?? '' }) + sendUserToast(`Archived workspace ${$workspaceStore}`) + workspaceStore.set(undefined) + usersWorkspaceStore.set(undefined) + goto('/user/workspaces') + } finally { + isProcessingWorkspaceDeletion = false + archiveModalOpen = false + } + }} + onCanceled={() => (archiveModalOpen = false)} +> + + Are you sure you want to archive workspace {$workspaceStore}? This action can be reversed by a superadmin. + + + + { + isProcessingWorkspaceDeletion = true + try { + await WorkspaceService.deleteWorkspace({ workspace: $workspaceStore ?? '' }) + sendUserToast(`Deleted workspace ${$workspaceStore}`) + workspaceStore.set(undefined) + usersWorkspaceStore.set(undefined) + goto('/user/workspaces') + } finally { + isProcessingWorkspaceDeletion = false + deleteModalOpen = false + } + }} + onCanceled={() => (deleteModalOpen = false)} +> + + Are you sure you want to permanently delete workspace {$workspaceStore}? + +

+ This action is irreversible and will permanently delete all data in this workspace. +

+
+ From 4b7b8ba281e3615cf21d12937b19e2e75d11a110 Mon Sep 17 00:00:00 2001 From: tristantr Date: Thu, 30 Oct 2025 11:49:44 +0100 Subject: [PATCH 3/4] Make one loading state per modal --- .../(logged)/workspace_settings/+page.svelte | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte index bd85d8e879c1a..cc17aa9a50dfe 100644 --- a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte @@ -60,10 +60,11 @@ import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte' import TextInput from '$lib/components/text_input/TextInput.svelte' - // Modal state for workspace deletion + // Modal state for workspace operations let archiveModalOpen = $state(false) let deleteModalOpen = $state(false) - let isProcessingWorkspaceDeletion = $state(false) + let isProcessingArchive = $state(false) + let isProcessingDelete = $state(false) let slackInitialPath: string = $state('') let slackScriptPath: string = $state('') @@ -1049,9 +1050,9 @@ title="Archive workspace" confirmationText="Archive" type="danger" - loading={isProcessingWorkspaceDeletion} + loading={isProcessingArchive} onConfirmed={async () => { - isProcessingWorkspaceDeletion = true + isProcessingArchive = true try { await WorkspaceService.archiveWorkspace({ workspace: $workspaceStore ?? '' }) sendUserToast(`Archived workspace ${$workspaceStore}`) @@ -1059,7 +1060,7 @@ usersWorkspaceStore.set(undefined) goto('/user/workspaces') } finally { - isProcessingWorkspaceDeletion = false + isProcessingArchive = false archiveModalOpen = false } }} @@ -1075,9 +1076,9 @@ title="Delete workspace permanently" confirmationText="Delete" type="danger" - loading={isProcessingWorkspaceDeletion} + loading={isProcessingDelete} onConfirmed={async () => { - isProcessingWorkspaceDeletion = true + isProcessingDelete = true try { await WorkspaceService.deleteWorkspace({ workspace: $workspaceStore ?? '' }) sendUserToast(`Deleted workspace ${$workspaceStore}`) @@ -1085,7 +1086,7 @@ usersWorkspaceStore.set(undefined) goto('/user/workspaces') } finally { - isProcessingWorkspaceDeletion = false + isProcessingDelete = false deleteModalOpen = false } }} From 484350cd100e36759cd6d0df60f533243e7cee05 Mon Sep 17 00:00:00 2001 From: tristantr Date: Fri, 31 Oct 2025 18:15:59 +0100 Subject: [PATCH 4/4] Handle error on modals --- .../(root)/(logged)/workspace_settings/+page.svelte | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte index cc17aa9a50dfe..64a93f6733b47 100644 --- a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte @@ -60,7 +60,6 @@ import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte' import TextInput from '$lib/components/text_input/TextInput.svelte' - // Modal state for workspace operations let archiveModalOpen = $state(false) let deleteModalOpen = $state(false) let isProcessingArchive = $state(false) @@ -1059,9 +1058,11 @@ workspaceStore.set(undefined) usersWorkspaceStore.set(undefined) goto('/user/workspaces') + archiveModalOpen = false + } catch (error) { + sendUserToast(`Failed to archive workspace: ${error}`, true) } finally { isProcessingArchive = false - archiveModalOpen = false } }} onCanceled={() => (archiveModalOpen = false)} @@ -1085,9 +1086,11 @@ workspaceStore.set(undefined) usersWorkspaceStore.set(undefined) goto('/user/workspaces') + deleteModalOpen = false + } catch (error) { + sendUserToast(`Failed to delete workspace: ${error}`, true) } finally { isProcessingDelete = false - deleteModalOpen = false } }} onCanceled={() => (deleteModalOpen = false)}