From 75b60f94d201b81648565b2d47a6471c7769f4f1 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 9 Jun 2026 19:38:41 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(sidebar):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=A7=86=E5=9B=BE=E5=AE=9A=E4=BD=8D=E8=AF=AF=E6=8A=A5?= =?UTF-8?q?=E6=9C=AA=E6=89=BE=E5=88=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sidebar.locate-toolbar.test.tsx | 9 ++++ frontend/src/components/Sidebar.tsx | 6 ++- frontend/src/utils/sidebarLocate.test.ts | 46 +++++++++++++++++++ frontend/src/utils/sidebarLocate.ts | 9 ++++ 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Sidebar.locate-toolbar.test.tsx b/frontend/src/components/Sidebar.locate-toolbar.test.tsx index 3d85ea0..7449cb6 100644 --- a/frontend/src/components/Sidebar.locate-toolbar.test.tsx +++ b/frontend/src/components/Sidebar.locate-toolbar.test.tsx @@ -1434,4 +1434,13 @@ describe('Sidebar locate toolbar', () => { expect(source).toContain('void loadTables(dbNode);'); expect(source).toContain("window.removeEventListener('gonavi:sidebar-table-pin-changed'"); }); + + it('waits long enough for slow object-tree loads before reporting locate misses', () => { + const source = readFileSync(new URL('./Sidebar.tsx', import.meta.url), 'utf8'); + + expect(source).toContain('const SIDEBAR_LOCATE_LOAD_WAIT_INTERVAL_MS = 50;'); + expect(source).toContain('const SIDEBAR_LOCATE_LOAD_WAIT_ATTEMPTS = 160;'); + expect(source).toContain('attempt < SIDEBAR_LOCATE_LOAD_WAIT_ATTEMPTS'); + expect(source).toContain('window.setTimeout(resolve, SIDEBAR_LOCATE_LOAD_WAIT_INTERVAL_MS)'); + }); }); diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 148c7d5..d9cf7b7 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -186,6 +186,8 @@ type SidebarContextMenuState = { const SIDEBAR_CONTEXT_MENU_SAFE_GAP = 8; const SIDEBAR_CONTEXT_MENU_FALLBACK_WIDTH = 264; const SIDEBAR_CONTEXT_MENU_FALLBACK_HEIGHT = 420; +const SIDEBAR_LOCATE_LOAD_WAIT_INTERVAL_MS = 50; +const SIDEBAR_LOCATE_LOAD_WAIT_ATTEMPTS = 160; type ExternalSQLFileModalMode = 'create' | 'rename' | 'create-directory' | 'rename-directory'; const isExternalSQLDirectoryModalMode = (mode: ExternalSQLFileModalMode): boolean => @@ -2439,8 +2441,8 @@ const Sidebar: React.FC<{ const locateObjectInSidebarRef = useRef<(detail: unknown) => Promise>(async () => {}); const waitForSidebarLoadKey = async (loadKey: string) => { - for (let attempt = 0; attempt < 30 && loadingNodesRef.current.has(loadKey); attempt += 1) { - await new Promise(resolve => window.setTimeout(resolve, 50)); + for (let attempt = 0; attempt < SIDEBAR_LOCATE_LOAD_WAIT_ATTEMPTS && loadingNodesRef.current.has(loadKey); attempt += 1) { + await new Promise(resolve => window.setTimeout(resolve, SIDEBAR_LOCATE_LOAD_WAIT_INTERVAL_MS)); } }; diff --git a/frontend/src/utils/sidebarLocate.test.ts b/frontend/src/utils/sidebarLocate.test.ts index 357fd50..987ce94 100644 --- a/frontend/src/utils/sidebarLocate.test.ts +++ b/frontend/src/utils/sidebarLocate.test.ts @@ -557,6 +557,52 @@ describe('sidebarLocate', () => { ]); }); + it('falls back from a schema-qualified view request to a bare table-like node in the same database', () => { + const target = resolveSidebarLocateTarget({ + tabId: 'stale-view-tab-id', + connectionId: 'conn-1', + dbName: 'SYSDBA', + tableName: 'SYSDBA.V_ACCOUNT', + schemaName: 'SYSDBA', + objectGroup: 'views', + }, { groupBySchema: false }); + + const tree = [ + { + key: 'conn-1', + children: [ + { + key: 'conn-1-SYSDBA', + dataRef: { id: 'conn-1', dbName: 'SYSDBA' }, + children: [ + { + key: 'conn-1-SYSDBA-tables', + children: [ + { + key: 'conn-1-SYSDBA-V_ACCOUNT', + type: 'table', + dataRef: { + id: 'conn-1', + dbName: 'SYSDBA', + tableName: 'V_ACCOUNT', + }, + }, + ], + }, + ], + }, + ], + }, + ]; + + expect(findSidebarNodePathForLocate(tree, target)).toEqual([ + 'conn-1', + 'conn-1-SYSDBA', + 'conn-1-SYSDBA-tables', + 'conn-1-SYSDBA-V_ACCOUNT', + ]); + }); + it('falls back to a unique schema-qualified table-like node for an unqualified view request', () => { const target = resolveSidebarLocateTarget({ tabId: 'stale-view-tab-id', diff --git a/frontend/src/utils/sidebarLocate.ts b/frontend/src/utils/sidebarLocate.ts index bb310d0..62debbd 100644 --- a/frontend/src/utils/sidebarLocate.ts +++ b/frontend/src/utils/sidebarLocate.ts @@ -268,6 +268,15 @@ const matchesLocateObjectName = ( if (normalize(normalizedNodeName) === normalize(target.tableName)) return true; + if ( + resolvedTargetSchema + && !resolvedNodeSchema + && normalize(resolvedTargetSchema) === normalize(target.dbName) + && normalize(nodeObject) === normalize(targetObject) + ) { + return true; + } + if (!resolvedTargetSchema) { if (options.allowUnqualifiedSchemaMatch) { return normalize(nodeObject) === normalize(targetObject);