From 6f6cf2f57cb7e0d55caf87b2ddc6ae44e4efb83f Mon Sep 17 00:00:00 2001 From: lxk955 <164191365+lxk955@users.noreply.github.com> Date: Mon, 12 Oct 2026 14:39:15 +0800 Subject: [PATCH] fix(sql): route shortcut new query to selected sidebar connection --- apps/desktop/src/App.vue | 24 ++++++++++++++--- .../sql/newQueryEntryContext.spec.ts | 27 +++++++++++++------ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/App.vue b/apps/desktop/src/App.vue index 1302fa5b88..da4eaca9f3 100644 --- a/apps/desktop/src/App.vue +++ b/apps/desktop/src/App.vue @@ -88,7 +88,7 @@ import { OBJECT_BROWSER_SEARCH_FOCUS_EVENT, objectBrowserSearchFocusTabId } from import { parseRecentConnectionIds, rankRecentConnections, RECENT_CONNECTION_IDS_STORAGE_KEY, recordRecentConnection } from "@/lib/connection/recentConnections"; import { resolveDefaultDatabase } from "@/lib/database/defaultDatabase"; import { normalizeSqliteNamespace } from "@/lib/database/sqliteNamespace"; -import { findTreeNodeById, resolveNewQueryTarget, resolveNewQueryInitialSql } from "@/lib/sql/newQueryContext"; +import { findTreeNodeById, resolveNewQueryTarget, resolveNewQueryInitialSql, type NewQueryContextSource } from "@/lib/sql/newQueryContext"; import { isSqlObjectNavigationRoutineType, normalizeOracleNavigationTarget, sqlObjectNavigationSourceKind, sqlObjectNavigationSourceName, sqlObjectNavigationSourceSchema, sqlObjectNavigationTableType, type SqlObjectNavigationTarget } from "@/lib/sql/sqlNavigation"; import { buildEditableObjectSource, buildExecutableObjectSourceStatements, executeObjectSourceSave } from "@/lib/table/objectSourceEditor"; import { loadEditableObjectSourceForEditor } from "@/lib/table/objectSourceLoad"; @@ -1112,8 +1112,9 @@ provide(GROUP_TAB_BAR_PORTAL, createGroupTabBarPortal(isSpecialPageActive)); provide(EDITOR_TOOLBAR_ACTIONS, { canNewQuery: canCreateNewQuery, newQuery: (groupId: string) => { + lastFocusedSidebarSurface.value = false; queryStore.focusGroup(groupId); - void newQuery(); + void newQuery({ preferredSource: "tab" }); }, explainMode, blockDangerousRedisCommands, @@ -1305,6 +1306,7 @@ function activateMainContentSurface(surface: MainContentSurface) { settingsStore.settingsPageActive = surface === "settings"; driverStoreActive.value = surface === "driverStore"; pluginCenterActive.value = surface === "pluginCenter"; + lastFocusedSidebarSurface.value = false; } watch( @@ -3092,7 +3094,11 @@ function openConnectionSettings(connectionId: string, initialTab: ConfigTab = "c showConnectionDialog.value = true; } -async function newQuery() { +interface NewQueryOptions { + preferredSource?: NewQueryContextSource; +} + +async function newQuery(options: NewQueryOptions = {}) { const sqlConnections = connectionStore.connections.filter((connection) => quickConnectionOpenTarget(connection).kind === "query" && supportsGenericNewQuery(connection)); const connectedSqlConnectionIds = new Set(sqlConnections.filter((connection) => connectionStore.connectedIds.has(connection.id)).map((connection) => connection.id)); let target = resolveNewQueryTarget({ @@ -3101,6 +3107,7 @@ async function newQuery() { activeConnectionId: connectionStore.activeConnectionId, connections: connectionStore.connections, connectedSqlConnectionIds, + preferredSource: options.preferredSource, }); if (!target) { // No active editor/sidebar choice and no unique online SQL connection: @@ -3157,6 +3164,7 @@ async function newQuery() { const initialSql = resolveNewQueryInitialSql({ activeTab: activeTab.value, selectedTreeNode: findTreeNodeById(connectionStore.treeNodes, connectionStore.selectedTreeNodeId), + preferredSource: options.preferredSource, prefillEnabled: settingsStore.editorSettings.prefillNewQueryWithSelect, targetConnectionId: target.connectionId, targetDatabase: target.database, @@ -4178,6 +4186,10 @@ function rememberSidebarSearchSurface() { lastFocusedSidebarSurface.value = true; } +function rememberEditorContentSurface() { + lastFocusedSidebarSurface.value = false; +} + function setPluginWorkbenchTabRef(tabId: string, element: unknown) { if (element && typeof element === "object" && "refresh" in element && typeof element.refresh === "function") { pluginWorkbenchTabRefs.set(tabId, element as PluginWorkbenchTabHandle); @@ -4316,7 +4328,10 @@ async function handleKeydown(e: KeyboardEvent) { if (isNewQueryShortcut(e, shortcuts)) { e.preventDefault(); e.stopPropagation(); - void newQuery(); + const target = e.target instanceof Element ? e.target : null; + const targetIsDocument = !target || target === document.body || target === document.documentElement; + const sidebarFocused = target?.closest("[data-app-sidebar]") || (targetIsDocument && lastFocusedSidebarSurface.value); + void newQuery({ preferredSource: sidebarFocused ? "sidebar" : undefined }); return; } if (isToggleSidebarShortcut(e, shortcuts)) { @@ -4886,6 +4901,7 @@ onUnmounted(() => { data-editor-content v-show="isSpecialPageActive || (!isAiPanelMaximized && !isHistoryPanelMaximized) || isZenMode" :class="isDetachedWindowContext ? 'flex-1 min-w-0 overflow-hidden bg-background' : isClassicLayout ? 'flex-1 min-w-0 overflow-hidden' : 'flex-1 min-w-0 overflow-hidden rounded-md border border-border/80 bg-background'" + @mousedown="rememberEditorContentSurface" >
= 0 ? closingParen : start; + const braceStart = appSource.indexOf("{", searchStart); let depth = 0; for (let i = braceStart; i < appSource.length; i++) { if (appSource[i] === "{") depth++; @@ -35,21 +37,30 @@ describe("new query entry context wiring", () => { }); it("resolves the shared new-query entry from the active tab and unique online SQL connection", () => { - const body = bodyOf("async function newQuery()"); - // Without an explicit source the resolver defaults to the active tab first - // and the selected sidebar node second, so all ad-hoc entries agree. - expect(body).not.toContain("preferredSource"); + const body = bodyOf("async function newQuery"); expect(body).toContain('quickConnectionOpenTarget(connection).kind === "query"'); expect(body).toContain("connectedSqlConnectionIds,"); + expect(body).toContain("preferredSource: options.preferredSource"); }); it("creates an unbound editor for manual SQL connection selection when the target is ambiguous", () => { - const body = bodyOf("async function newQuery()"); + const body = bodyOf("async function newQuery"); expect(body).toContain("if (sqlConnections.length > 0)"); expect(body).toContain('queryStore.createTab("", "", undefined, "query")'); }); - it("keeps the editor-group entry focused on its own group", () => { - expect(bodyOf("newQuery: (groupId: string) =>")).toContain("queryStore.focusGroup(groupId)"); + it("keeps the editor-group entry focused on its own group and tab context", () => { + const body = bodyOf("newQuery: (groupId: string) =>"); + expect(body).toContain("queryStore.focusGroup(groupId)"); + expect(body).toContain('preferredSource: "tab"'); + }); + + it("routes keyboard shortcut with sidebar context when the sidebar is focused (#11801)", () => { + const body = bodyOf("async function handleKeydown"); + expect(body).toContain('sidebarFocused ? "sidebar" : undefined'); + }); + + it("clears lastFocusedSidebarSurface when editor content is clicked", () => { + expect(appSource).toContain("rememberEditorContentSurface"); }); });