From 8f619fb79145518fad073ffd4b7334626fffba51 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Mon, 13 Jul 2026 21:26:39 +0800 Subject: [PATCH] fix(editor): confirm unsaved structure changes --- apps/desktop/src/App.vue | 21 +++- .../src/components/layout/ContentArea.vue | 8 +- .../structure/TableStructureEditor.vue | 11 +- .../queryStore.structure-close.spec.ts | 107 ++++++++++++++++++ apps/desktop/src/stores/queryStore.ts | 25 +++- apps/desktop/src/types/database.ts | 1 + 6 files changed, 161 insertions(+), 12 deletions(-) create mode 100644 apps/desktop/src/stores/__tests__/queryStore.structure-close.spec.ts diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index aaa0779108..b6cf52dfef 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -687,9 +687,15 @@ async function saveExternalSqlPath(tab: QueryTab, options: { closeAfterSave?: bo async function saveTabForCloseAll(tabId: string): Promise { const tab = queryStore.tabs.find((t) => t.id === tabId); - if (!tab || !canSaveSqlTab(tab)) return true; + if (!tab) return true; queryStore.activeTabId = tabId; + if (tab.mode === "structure") { + await nextTick(); + return (await contentAreaRef.value?.applyTableStructureChanges?.()) === true; + } + if (!canSaveSqlTab(tab)) return true; + if (tab.objectSource) return saveActiveObjectSource(tab); if (await saveExternalSqlPath(tab)) return !queryStore.isTabDirty(tab); @@ -735,7 +741,18 @@ async function handleSaveAllPendingTabClose() { async function handleSaveTab(tabId: string) { const tab = queryStore.tabs.find((t) => t.id === tabId); - if (!tab || !canSaveSqlTab(tab)) return; + if (!tab) return; + if (tab.mode === "structure") { + queryStore.activeTabId = tabId; + await nextTick(); + if (await contentAreaRef.value?.applyTableStructureChanges?.()) { + completePendingTabSave(tabId); + } else { + queryStore.resumeCloseConfirm(); + } + return; + } + if (!canSaveSqlTab(tab)) return; const closeAfterSave = pendingAppCloseAction.value === null; pendingSaveShouldCloseTab.value = closeAfterSave; if (tab.objectSource) { diff --git a/apps/desktop/src/components/layout/ContentArea.vue b/apps/desktop/src/components/layout/ContentArea.vue index e579eae727..837392b303 100644 --- a/apps/desktop/src/components/layout/ContentArea.vue +++ b/apps/desktop/src/components/layout/ContentArea.vue @@ -192,6 +192,7 @@ const columnInfoLoading = ref(false); const columnInfoError = ref(undefined); const dataGridRef = ref(); const queryEditorRef = ref>(); +const tableStructureEditorRef = ref<{ applyChanges: () => Promise }>(); const standaloneResultToolbarRef = ref(null); const standaloneResultToolbarWidth = ref(0); const resultTabsScrollerRef = ref(null); @@ -754,7 +755,11 @@ function pasteClipboardAsSqlInCondition() { return queryEditorRef.value?.pasteClipboardAsSqlInCondition(); } -defineExpose({ focusSearch, refreshData, handleModRTarget, requestQueryEditorExecute, pasteClipboardAsSqlInCondition }); +function applyTableStructureChanges() { + return tableStructureEditorRef.value?.applyChanges() ?? Promise.resolve(false); +} + +defineExpose({ focusSearch, refreshData, handleModRTarget, requestQueryEditorExecute, pasteClipboardAsSqlInCondition, applyTableStructureChanges });