From 148345494e9459345caf645c03ab2064d8545cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E4=B8=AB=E8=AE=B2=E6=A2=B5?= Date: Sun, 6 Sep 2026 20:39:34 +0800 Subject: [PATCH] fix(desktop): unify grouped tab bar portal across special pages --- apps/desktop/src/App.vue | 106 +++-- .../src/components/layout/AppTabBar.vue | 188 ++------- .../src/components/layout/ContentArea.vue | 36 +- .../src/components/layout/EditorGroup.vue | 57 +-- .../components/layout/EditorGroupTabBar.vue | 145 ++++--- .../components/layout/SqlEditorWorkspace.vue | 164 +++++--- .../layout/__tests__/AppTabBar.portal.spec.ts | 378 ++++++++++++++++++ .../layout/__tests__/AppTabBar.spec.ts | 155 ++----- .../__tests__/ContentArea.preload.spec.ts | 171 ++++++++ .../EditorGroupTabBar.groups.spec.ts | 130 +++++- .../SqlEditorWorkspace.mount.spec.ts | 133 +++++- .../__tests__/SqlEditorWorkspace.spec.ts | 19 +- .../appContentSurfaces.contract.spec.ts | 15 +- ...ceLayout.column-mode-special-pages.spec.ts | 43 +- .../src/components/layout/appTabBar.css | 6 + .../components/layout/groupTabBarPortal.ts | 13 + .../components/layout/sqlEditorWorkspace.css | 50 +-- .../sidebar/SidebarTreeRuntimeHost.vue | 2 +- .../__tests__/app/openTabsPersistence.spec.ts | 11 + .../src/lib/app/openTabsPersistence.ts | 2 + .../lib/query/__tests__/queryOutput.spec.ts | 31 ++ apps/desktop/src/lib/query/queryOutput.ts | 7 + .../__tests__/queryStore.detached.spec.ts | 13 + .../__tests__/queryStore.sourceView.spec.ts | 45 +++ apps/desktop/src/stores/queryStore.ts | 18 +- apps/desktop/src/types/database.ts | 2 + .../app-tests/sidebarContextMenuHost.test.ts | 2 +- 27 files changed, 1352 insertions(+), 590 deletions(-) create mode 100644 apps/desktop/src/components/layout/__tests__/AppTabBar.portal.spec.ts create mode 100644 apps/desktop/src/components/layout/__tests__/ContentArea.preload.spec.ts create mode 100644 apps/desktop/src/components/layout/groupTabBarPortal.ts create mode 100644 apps/desktop/src/lib/query/__tests__/queryOutput.spec.ts create mode 100644 apps/desktop/src/lib/query/queryOutput.ts create mode 100644 apps/desktop/src/stores/__tests__/queryStore.sourceView.spec.ts diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 737fdd1c02..6fbe5a7095 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -5,6 +5,7 @@ import { ChevronsRight, FileText } from "@lucide/vue"; import { TooltipProvider } from "@/components/ui/tooltip"; import AppToolbar from "@/components/layout/AppToolbar.vue"; import AppTabBar from "@/components/layout/AppTabBar.vue"; +import { createGroupTabBarPortal, GROUP_TAB_BAR_PORTAL } from "@/components/layout/groupTabBarPortal"; import AppSidebar from "@/components/layout/AppSidebar.vue"; import SqlEditorWorkspace from "@/components/layout/SqlEditorWorkspace.vue"; import { EDITOR_TOOLBAR_ACTIONS } from "@/components/layout/editorToolbarActions"; @@ -790,6 +791,7 @@ const specialPageTabs = computed(() => ({ driverStoreActive: driverStoreActive.value, driverUpdateCount: toolbarAgentDriverUpdateCount.value, })); +provide(GROUP_TAB_BAR_PORTAL, createGroupTabBarPortal(computed(() => !isDetachedWindowContext && (driverStoreActive.value || settingsStore.settingsPageActive)))); provide(EDITOR_TOOLBAR_ACTIONS, { explainMode, blockDangerousRedisCommands, @@ -910,19 +912,6 @@ useScheduledDatabaseBackups({ scheduler: true }); const appVersion = ref(""); const isClassicLayout = computed(() => settingsStore.editorSettings.appLayout === "classic"); -const isVerticalTabPlacement = computed(() => settingsStore.editorSettings.tabPlacement === "left" || settingsStore.editorSettings.tabPlacement === "right"); -// AppTabBar only renders the settings/driver special-page strip, and that strip -// is still a horizontal-only "w-full" bar (see AppTabBar.vue's app-tab-bar class). -// Placing it inside a flex-row/flex-row-reverse workspace squeezes the sibling -// content pane (EditorSettingsPage/DriverStorePage) to zero width, so fall back -// to stacking it above the content instead of adopting the vertical layout here. -const isSpecialPageStripActive = computed(() => driverStoreActive.value || settingsStore.settingsPageActive); -const tabWorkspaceLayoutClass = computed(() => { - if (settingsStore.editorSettings.tabPlacement === "bottom") return "flex-col-reverse"; - if (isVerticalTabPlacement.value && isSpecialPageStripActive.value) return "flex-col"; - if (settingsStore.editorSettings.tabPlacement === "right") return "flex-row-reverse"; - return isVerticalTabPlacement.value ? "flex-row" : "flex-col"; -}); // Every pane's vertical strip writes back to this shared width/collapse state. function startTabBarResize(event: MouseEvent) { @@ -2474,7 +2463,7 @@ async function onOpenObjectSource(table: SqlObjectNavigationTarget, initialEditi databaseType: resolvedDatabaseType, signature: navigation.signature, }); - const tabId = queryStore.createTab(target.connectionId, target.database, `Source - ${sourceName}`, "query", sourceSchema, editableSource, target.catalog, { forceNew: true }); + const tabId = queryStore.createTab(target.connectionId, target.database, `Source - ${sourceName}`, "query", sourceSchema, editableSource, target.catalog, { forceNew: true, sourceView: true }); const sourceIsEditable = raw.editable !== false && !["SEQUENCE", "TRIGGER", "TYPE", "TYPE_BODY"].includes(resolvedType); if (sourceIsEditable) { queryStore.setObjectSource(tabId, { @@ -2854,7 +2843,7 @@ async function handleQuickOpenSelect(item: any) { databaseType, signature: item.signature, }); - const tabId = queryStore.createTab(item.connectionId, item.database, `Source - ${objectName}`); + const tabId = queryStore.createTab(item.connectionId, item.database, `Source - ${objectName}`, "query", undefined, undefined, undefined, { sourceView: true }); queryStore.updateSql(tabId, editableSource); if (item.type !== "sequence" && item.type !== "trigger" && item.type !== "event" && item.type !== "type" && item.type !== "type-body") { queryStore.setObjectSource(tabId, { @@ -3453,7 +3442,7 @@ onUnmounted(() => {
-
+
{ :agent-driver-update-count="toolbarAgentDriverUpdateCount" :detached-drop-target="detachedDropTargetTabId !== null" :can-detach-tabs="isDesktop" + :tab-bar-width="tabBarWidth" + :tab-bar-collapsed="tabBarCollapsed" @activate-driver-store="openDriverStorePage" @activate-settings-page="activateSettingsPage" @activate-tab="activateQueryTab" @@ -3475,7 +3466,26 @@ onUnmounted(() => { @discard-all-tab-close="handleDiscardAllPendingTabClose" @cancel-tab-close="cancelPendingAppClose" @detach-tab="detachTab" - /> + > + + + { -
- - -
+
+
{ @structure-editor-close="(tabId: string) => queryStore.closeTab(tabId)" @open-settings="openSettings" @open-connection-settings="openConnectionSettings" - /> + > + +
-
diff --git a/apps/desktop/src/components/layout/AppTabBar.vue b/apps/desktop/src/components/layout/AppTabBar.vue index 4eaf7abefb..c8d88f29f3 100644 --- a/apps/desktop/src/components/layout/AppTabBar.vue +++ b/apps/desktop/src/components/layout/AppTabBar.vue @@ -1,15 +1,14 @@