🐛 fix(sidebar): 修复视图定位误报未找到

- 视图定位失败时增加表分支可视节点兜底

- 命令搜索对象定位传入精确树节点 key

- 补充国产库视图与元数据缺失场景回归测试
This commit is contained in:
Syngnat
2026-06-09 23:26:15 +08:00
parent ce06bea744
commit c742b4d61e
4 changed files with 102 additions and 0 deletions

View File

@@ -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(

View File

@@ -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,

View File

@@ -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',

View File

@@ -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,