From 73e93e955c91fb4b130851647a71512e486d677f Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 9 Jun 2026 23:51:36 +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=E7=BC=BA=E5=A4=B1=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=97=B6=E5=AE=9A=E4=BD=8D=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/Sidebar.tsx | 8 +++- frontend/src/utils/sidebarLocate.test.ts | 61 ++++++++++++++++++++++++ frontend/src/utils/sidebarLocate.ts | 15 +++++- 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index 670e035..861afbb 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -2790,7 +2790,7 @@ const Sidebar: React.FC<{ }); return; } else if (node.type === 'view' || node.type === 'materialized-view') { - const { viewName, dbName, id } = node.dataRef; + const { viewName, dbName, id, schemaName } = node.dataRef; addTab({ id: node.key, title: viewName, @@ -2799,6 +2799,8 @@ const Sidebar: React.FC<{ dbName, tableName: viewName, objectType: node.type === 'materialized-view' ? 'materialized-view' : 'view', + schemaName, + sidebarLocateKey: String(node.key || ''), }); return; } else if (node.type === 'saved-query') { @@ -4346,7 +4348,7 @@ const Sidebar: React.FC<{ // --- 视图操作 --- const openViewDefinition = (node: any) => { - const { viewName, dbName, id } = node.dataRef; + const { viewName, dbName, id, schemaName } = node.dataRef; const isMaterialized = node.type === 'materialized-view' || node.dataRef?.objectKind === 'materialized-view'; addTab({ id: `view-def-${id}-${dbName}-${viewName}`, @@ -4356,6 +4358,8 @@ const Sidebar: React.FC<{ dbName, viewName, viewKind: isMaterialized ? 'materialized' : 'view', + schemaName, + sidebarLocateKey: String(node.key || ''), }); }; diff --git a/frontend/src/utils/sidebarLocate.test.ts b/frontend/src/utils/sidebarLocate.test.ts index 7516cd6..8f29a55 100644 --- a/frontend/src/utils/sidebarLocate.test.ts +++ b/frontend/src/utils/sidebarLocate.test.ts @@ -96,6 +96,21 @@ describe('sidebarLocate', () => { })).toBeNull(); }); + it('keeps table-style view tabs on the views branch', () => { + expect(normalizeSidebarLocateObjectRequestFromTab({ + id: 'legacy-view-tab-id', + type: 'table', + connectionId: 'conn-1', + dbName: 'GDB_APP', + tableName: 'V_ACCOUNT', + objectType: 'view', + })).toMatchObject({ + tabId: 'legacy-view-tab-id', + tableName: 'V_ACCOUNT', + objectGroup: 'views', + }); + }); + it('builds locate requests from trigger and routine tabs', () => { expect(normalizeSidebarLocateObjectRequestFromTab({ id: 'trigger-conn-1-main-audit.users_bi', @@ -690,6 +705,52 @@ describe('sidebarLocate', () => { ]); }); + it('finds a schema-qualified view request by visual title when the node has no schema metadata', () => { + const target = resolveSidebarLocateTarget({ + tabId: 'stale-view-tab-id', + connectionId: 'conn-1', + dbName: 'GDB_APP', + tableName: 'SYSDBA.V_ACCOUNT', + schemaName: 'SYSDBA', + objectGroup: 'views', + }, { groupBySchema: false }); + + const tree = [ + { + key: 'conn-1', + children: [ + { + key: 'conn-1-GDB_APP', + dataRef: { id: 'conn-1', dbName: 'GDB_APP' }, + children: [ + { + key: 'conn-1-GDB_APP-views', + children: [ + { + key: 'conn-1-GDB_APP-view-generated-key', + title: 'V_ACCOUNT', + type: 'view', + dataRef: { + id: 'conn-1', + dbName: 'GDB_APP', + }, + }, + ], + }, + ], + }, + ], + }, + ]; + + expect(findSidebarNodePathForLocate(tree, target)).toEqual([ + 'conn-1', + 'conn-1-GDB_APP', + 'conn-1-GDB_APP-views', + 'conn-1-GDB_APP-view-generated-key', + ]); + }); + 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', diff --git a/frontend/src/utils/sidebarLocate.ts b/frontend/src/utils/sidebarLocate.ts index 49ae6b1..c5d497f 100644 --- a/frontend/src/utils/sidebarLocate.ts +++ b/frontend/src/utils/sidebarLocate.ts @@ -60,6 +60,7 @@ export interface SidebarLocateTabLike { schemaName?: string; sidebarLocateKey?: string; filePath?: string; + objectType?: string; } const toTrimmedString = (value: unknown): string => String(value ?? '').trim(); @@ -167,7 +168,11 @@ export const normalizeSidebarLocateObjectRequestFromTab = (tab: SidebarLocateTab schemaName: tab.schemaName, objectGroup: tab.type === 'view-def' ? (tab.viewKind === 'materialized' ? 'materializedViews' : 'views') - : (tab.type === 'trigger' ? 'triggers' : (tab.type === 'routine-def' ? 'routines' : undefined)), + : (tab.type === 'trigger' + ? 'triggers' + : (tab.type === 'routine-def' + ? 'routines' + : (tab.objectType === 'materialized-view' ? 'materializedViews' : (tab.objectType === 'view' ? 'views' : undefined)))), }); }; @@ -278,6 +283,14 @@ const matchesLocateObjectName = ( return true; } + if ( + options.allowUnqualifiedSchemaMatch + && !resolvedNodeSchema + && normalizeLocateName(nodeObject) === normalizeLocateName(targetObject) + ) { + return true; + } + if (!resolvedTargetSchema) { if (options.allowUnqualifiedSchemaMatch) { return normalizeLocateName(nodeObject) === normalizeLocateName(targetObject);