From 9e7d0a541b60cb87282ace6dd247b358b2737498 Mon Sep 17 00:00:00 2001 From: Guilhem Lemouel Date: Tue, 11 Aug 2026 11:41:46 +0200 Subject: [PATCH] fix(frontend): confirm before dismissing the data table wizard mid-setup Closing was guarded while a run was in flight and unguarded before one, which is backwards: a run leaves a row to resume from, whereas a backdrop click on the review step threw away the project, the pasted password and the folder with nothing to recover them from. Backdrop, Escape and the close button now go through one path that asks first. It only asks when there is something to lose -- no provider chosen yet, or a run that already produced a result, closes immediately -- so the dialog does not become something to click through. Continue in the background still leaves in one click; that exit was always the deliberate one. Co-Authored-By: Claude Opus 5 (1M context) --- .../AddDataTableWizard.svelte | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/components/workspaceSettings/AddDataTableWizard.svelte b/frontend/src/lib/components/workspaceSettings/AddDataTableWizard.svelte index 04de723d00..5e1769b4eb 100644 --- a/frontend/src/lib/components/workspaceSettings/AddDataTableWizard.svelte +++ b/frontend/src/lib/components/workspaceSettings/AddDataTableWizard.svelte @@ -312,6 +312,34 @@ onDone() } + /** + * Whether closing would throw away work. Nothing is written before Finish, so the loss is + * only what was typed -- but that includes a pasted database password and a project about + * to be created, and a backdrop click is easy to do by accident. Once a run has produced a + * result there is nothing left to lose: it either finished, or left a row to resume from. + */ + function hasUnfinishedIntent(): boolean { + return wiz.provider !== undefined && !run.running && !run.result + } + + /** Backdrop, Escape and the close button all arrive here. */ + async function requestClose() { + if (preventClose) return + if (!hasUnfinishedIntent()) { + close() + return + } + // Held while the dialog is up so a second dismissal cannot stack another one. + preventClose = true + const confirmed = await confirmationModal.ask({ + title: 'Leave without adding a database?', + children: 'Nothing has been created yet, and what you have filled in here will be lost.', + confirmationText: 'Discard' + }) + preventClose = false + if (confirmed) close() + } + function close() { opened = false if (rowCreated && !run.result?.ok) { @@ -389,8 +417,7 @@ bind:isOpen={ () => opened, (v) => { - if (!v && preventClose) return - if (!v) close() + if (!v) requestClose() else opened = v } }