From c742b4d61ee0b68c0a0c7acfad1ef3e4c26d9662 Mon Sep 17 00:00:00 2001 From: Syngnat Date: Tue, 9 Jun 2026 23:26:15 +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 - 视图定位失败时增加表分支可视节点兜底 - 命令搜索对象定位传入精确树节点 key - 补充国产库视图与元数据缺失场景回归测试 --- .../Sidebar.locate-toolbar.test.tsx | 10 +++ frontend/src/components/Sidebar.tsx | 1 + frontend/src/utils/sidebarLocate.test.ts | 88 +++++++++++++++++++ frontend/src/utils/sidebarLocate.ts | 3 + 4 files changed, 102 insertions(+) diff --git a/frontend/src/components/Sidebar.locate-toolbar.test.tsx b/frontend/src/components/Sidebar.locate-toolbar.test.tsx index 7449cb6..134216e 100644 --- a/frontend/src/components/Sidebar.locate-toolbar.test.tsx +++ b/frontend/src/components/Sidebar.locate-toolbar.test.tsx @@ -503,6 +503,16 @@ describe('Sidebar locate toolbar', () => { expect(locateActionIndex).toBeGreaterThan(externalSqlActionIndex); }); + it('passes the exact tree key when locating a command-search object node', () => { + const source = readFileSync(new URL('./Sidebar.tsx', import.meta.url), 'utf8'); + const commandSearchRunSource = source.slice( + source.indexOf("if (node.type === 'table' || node.type === 'view' || node.type === 'materialized-view')"), + source.indexOf("if (node.type === 'db-trigger' || node.type === 'db-event' || node.type === 'routine')"), + ); + + expect(commandSearchRunSource).toContain("tabId: String(node.key || '')"); + }); + it('wires external SQL directory file actions to dedicated Wails APIs', () => { const source = readFileSync(new URL('./Sidebar.tsx', import.meta.url), 'utf8'); const loadTablesSource = source.slice( diff --git a/frontend/src/components/Sidebar.tsx b/frontend/src/components/Sidebar.tsx index ae2a0b4..670e035 100644 --- a/frontend/src/components/Sidebar.tsx +++ b/frontend/src/components/Sidebar.tsx @@ -6321,6 +6321,7 @@ const Sidebar: React.FC<{ } if (node.type === 'table' || node.type === 'view' || node.type === 'materialized-view') { void locateObjectInSidebar({ + tabId: String(node.key || ''), connectionId: dataRef.id, dbName: dataRef.dbName, tableName: dataRef.tableName || dataRef.viewName, diff --git a/frontend/src/utils/sidebarLocate.test.ts b/frontend/src/utils/sidebarLocate.test.ts index 06130bb..7516cd6 100644 --- a/frontend/src/utils/sidebarLocate.test.ts +++ b/frontend/src/utils/sidebarLocate.test.ts @@ -512,6 +512,52 @@ describe('sidebarLocate', () => { ]); }); + it('finds a bare mysql-compatible view node when the locate request keeps a different schema name', () => { + const target = resolveSidebarLocateTarget({ + tabId: 'stale-view-tab-id', + connectionId: 'conn-1', + dbName: 'GDB_APP', + tableName: '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-V_ACCOUNT', + type: 'view', + dataRef: { + id: 'conn-1', + dbName: 'GDB_APP', + viewName: 'V_ACCOUNT', + }, + }, + ], + }, + ], + }, + ], + }, + ]; + + expect(findSidebarNodePathForLocate(tree, target)).toEqual([ + 'conn-1', + 'conn-1-GDB_APP', + 'conn-1-GDB_APP-views', + 'conn-1-GDB_APP-view-V_ACCOUNT', + ]); + }); + it('falls back to a table-like node when a view is only present in the tables branch', () => { const target = resolveSidebarLocateTarget({ tabId: 'stale-view-tab-id', @@ -557,6 +603,48 @@ describe('sidebarLocate', () => { ]); }); + it('falls back to a visual table-like node when view metadata is not present on the node', () => { + const target = resolveSidebarLocateTarget({ + tabId: 'stale-view-tab-id', + connectionId: 'conn-1', + dbName: 'SYSDBA', + tableName: 'V_ACCOUNT', + 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', + title: 'V_ACCOUNT', + type: 'table', + dataRef: {}, + }, + ], + }, + ], + }, + ], + }, + ]; + + expect(findSidebarNodePathForLocate(tree, target)).toEqual([ + 'conn-1', + 'conn-1-SYSDBA', + 'conn-1-SYSDBA-tables', + 'conn-1-SYSDBA-V_ACCOUNT', + ]); + }); + it('finds a view node by title when the tree node is missing object metadata', () => { const target = resolveSidebarLocateTarget({ tabId: 'stale-view-tab-id', diff --git a/frontend/src/utils/sidebarLocate.ts b/frontend/src/utils/sidebarLocate.ts index d34d239..49ae6b1 100644 --- a/frontend/src/utils/sidebarLocate.ts +++ b/frontend/src/utils/sidebarLocate.ts @@ -494,6 +494,9 @@ export const findSidebarNodePathForLocate = ( const tableLikePaths = collectSidebarNodePathsForLocateByObject(nodes, tableLikeTarget); const tableLikePath = selectPreferredSidebarLocatePath(tableLikePaths, target); if (tableLikePath) return tableLikePath; + const visualTableLikePaths = collectSidebarNodePathsForLocateByVisualIdentity(nodes, tableLikeTarget); + const visualTableLikePath = selectPreferredSidebarLocatePath(visualTableLikePaths, target); + if (visualTableLikePath) return visualTableLikePath; if (!hasLocateTargetSchema(target)) { const relaxedTableLikePaths = collectSidebarNodePathsForLocateByObject( nodes,