fix(sql): route shortcut new query to selected sidebar connection

This commit is contained in:
lxk955
2026-10-12 14:39:15 +08:00
committed by GitHub
parent 6b293e9eaa
commit 6f6cf2f57c
2 changed files with 39 additions and 12 deletions
+20 -4
View File
@@ -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"
>
<div class="h-full flex min-h-0 min-w-0 flex-col">
<AppTabBar
@@ -17,7 +17,9 @@ const appSource = readFileSync(new URL("../../../App.vue", import.meta.url), "ut
function bodyOf(fnSignature: string): string {
const start = appSource.indexOf(fnSignature);
expect(start, `expected to find "${fnSignature}" in App.vue`).toBeGreaterThanOrEqual(0);
const braceStart = appSource.indexOf("{", start);
const closingParen = appSource.indexOf(")", start);
const searchStart = closingParen >= 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");
});
});