From 801434e423e94f4c93d6966bfcda4838ec83c804 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Sun, 24 May 2026 21:17:07 +0800 Subject: [PATCH] refactor: convert table structure editor from modal dialog to tab Replace the dialog-based TableStructureEditorDialog with a tab-based TableStructureEditor, making it consistent with query editors, data viewers, and object browsers. Users can now switch between editing table structure and running queries freely. --- apps/desktop/src/App.vue | 11 +- .../src/components/layout/AppDialogs.vue | 13 - .../src/components/layout/AppTabBar.vue | 5 +- .../src/components/layout/ContentArea.vue | 16 + .../src/components/objects/ObjectBrowser.vue | 7 +- .../src/components/sidebar/TreeItem.vue | 14 +- .../structure/TableStructureEditor.vue | 918 +++++++++++++++++ .../structure/TableStructureEditorDialog.vue | 951 ------------------ .../src/composables/useDialogSources.ts | 24 - .../src/composables/useNavigationTargets.ts | 20 +- apps/desktop/src/i18n/locales/en.ts | 1 + apps/desktop/src/i18n/locales/es.ts | 1 + apps/desktop/src/i18n/locales/zh-CN.ts | 1 + apps/desktop/src/stores/connectionStore.ts | 7 - apps/desktop/src/stores/queryStore.ts | 37 + apps/desktop/src/types/database.ts | 3 +- 16 files changed, 998 insertions(+), 1031 deletions(-) create mode 100644 apps/desktop/src/components/structure/TableStructureEditor.vue delete mode 100644 apps/desktop/src/components/structure/TableStructureEditorDialog.vue diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 50902f418..0e2cb5454 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -918,6 +918,16 @@ onUnmounted(() => { }) " @object-schema-change="(schema) => activeTab && queryStore.updateSchema(activeTab.id, schema)" + @structure-editor-saved=" + activeTab && + onStructureEditorSaved(onReloadData, toast, { + connectionId: activeTab.connectionId, + database: activeTab.database, + schema: activeTab.schema, + tableName: activeTab.structureTableName || '', + }) + " + @structure-editor-close="activeTab && queryStore.closeTab(activeTab.id)" /> @@ -1000,7 +1010,6 @@ onUnmounted(() => { setConnectionDialogOpen(false); showDriverStore = true; " - @structure-editor-saved="onStructureEditorSaved(onReloadData, toast)" @open-lineage-target="openLineageTarget" @open-database-search-target="openDatabaseSearchTarget" /> diff --git a/apps/desktop/src/components/layout/AppDialogs.vue b/apps/desktop/src/components/layout/AppDialogs.vue index dd9af6ae3..32f5686b9 100644 --- a/apps/desktop/src/components/layout/AppDialogs.vue +++ b/apps/desktop/src/components/layout/AppDialogs.vue @@ -12,9 +12,6 @@ const DataCompareDialog = defineAsyncComponent(() => import("@/components/diff/D const SqlFileExecutionDialog = defineAsyncComponent(() => import("@/components/sql-file/SqlFileExecutionDialog.vue")); const SchemaDiagramDialog = defineAsyncComponent(() => import("@/components/diagram/SchemaDiagramDialog.vue")); const TableImportDialog = defineAsyncComponent(() => import("@/components/import/TableImportDialog.vue")); -const TableStructureEditorDialog = defineAsyncComponent( - () => import("@/components/structure/TableStructureEditorDialog.vue"), -); const FieldLineageDialog = defineAsyncComponent(() => import("@/components/lineage/FieldLineageDialog.vue")); const ConfigPassphraseDialog = defineAsyncComponent(() => import("@/components/config/ConfigPassphraseDialog.vue")); const DatabaseSearchDialog = defineAsyncComponent(() => import("@/components/search/DatabaseSearchDialog.vue")); @@ -42,7 +39,6 @@ const emit = defineEmits<{ connectSucceeded: [name: string]; connectFailed: [message: string]; openDriverStore: []; - structureEditorSaved: []; openLineageTarget: [ target: { connectionId: string; @@ -165,15 +161,6 @@ watch( :prefill-schema="dialogs.tableImportPrefillSchema.value" :prefill-table="dialogs.tableImportPrefillTable.value" /> - + {{ tabDisplayTitle(tab) }} diff --git a/apps/desktop/src/components/layout/ContentArea.vue b/apps/desktop/src/components/layout/ContentArea.vue index c2a9c74ec..069f34d31 100644 --- a/apps/desktop/src/components/layout/ContentArea.vue +++ b/apps/desktop/src/components/layout/ContentArea.vue @@ -26,6 +26,7 @@ const DataGrid = defineAsyncComponent(() => import("@/components/grid/DataGrid.v const RedisKeyBrowser = defineAsyncComponent(() => import("@/components/redis/RedisKeyBrowser.vue")); const MongoDocBrowser = defineAsyncComponent(() => import("@/components/mongo/MongoDocBrowser.vue")); const ObjectBrowser = defineAsyncComponent(() => import("@/components/objects/ObjectBrowser.vue")); +const TableStructureEditor = defineAsyncComponent(() => import("@/components/structure/TableStructureEditor.vue")); const ExplainPlanViewer = defineAsyncComponent(() => import("@/components/explain/ExplainPlanViewer.vue")); const QueryChart = defineAsyncComponent(() => import("@/components/chart/QueryChart.vue")); import { useQueryStore } from "@/stores/queryStore"; @@ -82,6 +83,8 @@ const emit = defineEmits<{ clickTable: [tableName: string]; openObjectTable: [target: { tableName: string; schema?: string }]; objectSchemaChange: [schema: string | undefined]; + structureEditorSaved: []; + structureEditorClose: []; }>(); const { t } = useI18n(); @@ -678,5 +681,18 @@ defineExpose({ focusSearch, refreshData }); @schema-change="emit('objectSchemaChange', $event)" /> + + + diff --git a/apps/desktop/src/components/objects/ObjectBrowser.vue b/apps/desktop/src/components/objects/ObjectBrowser.vue index fd2cd5130..e275a28c8 100644 --- a/apps/desktop/src/components/objects/ObjectBrowser.vue +++ b/apps/desktop/src/components/objects/ObjectBrowser.vue @@ -511,12 +511,7 @@ function openViewData(row: ObjectBrowserRow) { function openStructureEditor(row: ObjectBrowserRow) { if (row.type !== "TABLE") return; - connectionStore.structureEditorSource = { - connectionId: props.connection.id, - database: props.database, - schema: row.schema || selectedSchema.value, - tableName: row.name, - }; + queryStore.openTableStructure(props.connection.id, props.database, row.schema || selectedSchema.value, row.name); } function openDiagram(row: ObjectBrowserRow) { diff --git a/apps/desktop/src/components/sidebar/TreeItem.vue b/apps/desktop/src/components/sidebar/TreeItem.vue index 0c9eda1fc..6b6715df0 100644 --- a/apps/desktop/src/components/sidebar/TreeItem.vue +++ b/apps/desktop/src/components/sidebar/TreeItem.vue @@ -1240,12 +1240,7 @@ async function confirmDuplicateStructure() { function createTable() { const node = props.node; if (!node.connectionId || !node.database) return; - connectionStore.structureEditorSource = { - connectionId: node.connectionId, - database: node.database, - schema: node.schema, - tableName: "", - }; + queryStore.openTableStructure(node.connectionId, node.database, node.schema, ""); } async function saveFileContent(content: string, defaultFileName: string, filterName: string, filterExt: string) { @@ -1491,12 +1486,7 @@ function openTableImport() { function openStructureEditor() { const node = props.node; if (node.type !== "table" || !node.connectionId || !node.database) return; - connectionStore.structureEditorSource = { - connectionId: node.connectionId, - database: node.database, - schema: node.schema, - tableName: node.label, - }; + queryStore.openTableStructure(node.connectionId, node.database, node.schema, node.label); } function openFieldLineage() { diff --git a/apps/desktop/src/components/structure/TableStructureEditor.vue b/apps/desktop/src/components/structure/TableStructureEditor.vue new file mode 100644 index 000000000..9bd99f65f --- /dev/null +++ b/apps/desktop/src/components/structure/TableStructureEditor.vue @@ -0,0 +1,918 @@ + + +