From aa5b536942e6af26f88e7ccc3a1435ff94cdf348 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Thu, 29 Jan 2026 23:34:32 -0800 Subject: [PATCH] delete modal --- src/client/index.tsx | 83 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/src/client/index.tsx b/src/client/index.tsx index f58513c..2454785 100644 --- a/src/client/index.tsx +++ b/src/client/index.tsx @@ -403,6 +403,11 @@ const FormActions = define('FormActions', { let newAppError = '' let newAppCreating = false +// Delete App confirmation +let deleteAppError = '' +let deleteAppDeleting = false +let deleteAppTarget: App | null = null + async function createNewApp(input: HTMLInputElement) { const name = input.value.trim().toLowerCase().replace(/\s+/g, '-') @@ -484,6 +489,82 @@ function openNewAppModal() { )) } +// Delete App confirmation modal +async function deleteApp(input: HTMLInputElement) { + if (!deleteAppTarget) return + + const expected = `sudo rm ${deleteAppTarget.name}` + const value = input.value.trim() + + if (value !== expected) { + deleteAppError = `Type "${expected}" to confirm` + rerenderModal() + return + } + + deleteAppDeleting = true + deleteAppError = '' + rerenderModal() + + try { + const res = await fetch(`/api/sync/apps/${deleteAppTarget.name}`, { + method: 'DELETE', + }) + if (!res.ok) { + throw new Error(`Failed to delete app: ${res.statusText}`) + } + + // Success - close modal and clear selection + if (selectedApp === deleteAppTarget.name) { + selectedApp = null + localStorage.removeItem('selectedApp') + } + closeModal() + } catch (err) { + deleteAppError = err instanceof Error ? err.message : 'Failed to delete app' + deleteAppDeleting = false + rerenderModal() + } +} + +function openDeleteAppModal(app: App) { + deleteAppError = '' + deleteAppDeleting = false + deleteAppTarget = app + + const expected = `sudo rm ${app.name}` + + openModal('Delete App', () => ( +
{ + e.preventDefault() + const input = (e.target as HTMLFormElement).querySelector('input') as HTMLInputElement + deleteApp(input) + }}> +

+ This will permanently delete {app.name} from the server. +

+ + Type "{expected}" to confirm + + {deleteAppError && {deleteAppError}} + + + + + +
+ )) +} + // Actions - call API then let SSE update the state const startApp = (name: string) => fetch(`/api/apps/${name}/start`, { method: 'POST' }) const stopApp = (name: string) => fetch(`/api/apps/${name}/stop`, { method: 'POST' }) @@ -525,7 +606,7 @@ const AppDetail = ({ app }: { app: App }) => ( - +