mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-03 12:18:48 +08:00
🐛 fix(sidebar): 单击打开数据库对象节点
- 支持视图、函数、触发器等对象单击直接打开定义 tab - 覆盖查询日志打开后 CK/SQLite 查询结果仍切回数据结果 Fixes #595
This commit is contained in:
@@ -1121,6 +1121,78 @@ describe('QueryEditor external SQL save', () => {
|
||||
renderer.unmount();
|
||||
});
|
||||
|
||||
it.each(['sqlite', 'clickhouse'])(
|
||||
'activates the data result tab for %s after the sql log tab was open',
|
||||
async (dbType) => {
|
||||
storeState.appearance.uiVersion = 'v2';
|
||||
storeState.connections[0].config.type = dbType;
|
||||
storeState.sqlLogs = [{
|
||||
id: 'log-1',
|
||||
timestamp: Date.now(),
|
||||
sql: 'select old',
|
||||
status: 'success',
|
||||
duration: 12,
|
||||
}];
|
||||
backendApp.DBGetColumns.mockResolvedValue({
|
||||
success: true,
|
||||
data: [{ name: 'id', key: 'PRI' }],
|
||||
});
|
||||
backendApp.DBGetIndexes.mockResolvedValue({ success: true, data: [] });
|
||||
backendApp.DBQueryMulti.mockResolvedValueOnce({
|
||||
success: true,
|
||||
data: [{
|
||||
columns: ['id', 'name'],
|
||||
rows: [{ id: 1, name: 'alpha' }],
|
||||
statementIndex: 1,
|
||||
}],
|
||||
});
|
||||
|
||||
const windowListeners: Record<string, ((event?: any) => void)[]> = {};
|
||||
vi.stubGlobal('window', {
|
||||
addEventListener: vi.fn((type: string, listener: (event?: any) => void) => {
|
||||
windowListeners[type] ||= [];
|
||||
windowListeners[type].push(listener);
|
||||
}),
|
||||
removeEventListener: vi.fn(),
|
||||
dispatchEvent: vi.fn(),
|
||||
requestAnimationFrame: vi.fn((callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 1;
|
||||
}),
|
||||
cancelAnimationFrame: vi.fn(),
|
||||
innerHeight: 900,
|
||||
});
|
||||
|
||||
let renderer!: ReactTestRenderer;
|
||||
await act(async () => {
|
||||
renderer = create(<QueryEditor tab={createTab({
|
||||
query: 'SELECT * FROM users',
|
||||
})} />);
|
||||
});
|
||||
|
||||
const openEvent = new CustomEvent('gonavi:show-sql-execution-log', { detail: { mode: 'open' } });
|
||||
await act(async () => {
|
||||
windowListeners['gonavi:show-sql-execution-log']?.forEach((listener) => listener(openEvent));
|
||||
});
|
||||
expect(textContent(renderer.toJSON())).toContain('SQL 执行日志');
|
||||
dataGridState.latestProps = null;
|
||||
|
||||
await act(async () => {
|
||||
await findButton(renderer, '运行').props.onClick();
|
||||
});
|
||||
await act(async () => {
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(textContent(renderer.toJSON())).toContain('结果 1');
|
||||
expect(dataGridState.latestProps?.columnNames).toEqual(['id', 'name']);
|
||||
expect(dataGridState.latestProps?.data?.[0]).toMatchObject({ id: 1, name: 'alpha' });
|
||||
|
||||
renderer.unmount();
|
||||
},
|
||||
);
|
||||
|
||||
it('keeps query result panel visibility isolated per tab', async () => {
|
||||
storeState.appearance.uiVersion = 'v2';
|
||||
storeState.queryOptions.showQueryResultsPanel = false;
|
||||
|
||||
@@ -665,6 +665,26 @@ describe('Sidebar locate toolbar', () => {
|
||||
expect(commandSearchRunSource).toContain("tabId: String(node.key || '')");
|
||||
});
|
||||
|
||||
it('opens view routine and trigger nodes from single-click selection', () => {
|
||||
const source = readSidebarSource();
|
||||
const openObjectSource = source.slice(
|
||||
source.indexOf('const openSidebarObjectNode ='),
|
||||
source.indexOf('const onSelect ='),
|
||||
);
|
||||
const onSelectSource = source.slice(
|
||||
source.indexOf('const onSelect ='),
|
||||
source.indexOf('const onExpand ='),
|
||||
);
|
||||
|
||||
expect(openObjectSource).toContain("node.type === 'view' || node.type === 'materialized-view'");
|
||||
expect(openObjectSource).toContain("node.type === 'db-trigger'");
|
||||
expect(openObjectSource).toContain("node.type === 'routine'");
|
||||
expect(openObjectSource).toContain("type: 'table'");
|
||||
expect(openObjectSource).toContain("type: 'trigger'");
|
||||
expect(openObjectSource).toContain("type: 'routine-def'");
|
||||
expect(onSelectSource).toContain('openSidebarObjectNode(info.node)');
|
||||
});
|
||||
|
||||
it('wires external SQL directory file actions to dedicated Wails APIs', () => {
|
||||
const source = readSidebarSource();
|
||||
const loadTablesSource = source.slice(
|
||||
|
||||
@@ -1451,6 +1451,66 @@ const Sidebar: React.FC<{
|
||||
});
|
||||
};
|
||||
|
||||
const openSidebarObjectNode = (node: any): boolean => {
|
||||
if (node.type === 'view' || node.type === 'materialized-view') {
|
||||
const { viewName, dbName, id, schemaName } = node.dataRef;
|
||||
addTab({
|
||||
id: node.key,
|
||||
title: viewName,
|
||||
type: 'table',
|
||||
connectionId: id,
|
||||
dbName,
|
||||
tableName: viewName,
|
||||
objectType: node.type === 'materialized-view' ? 'materialized-view' : 'view',
|
||||
schemaName,
|
||||
sidebarLocateKey: String(node.key || ''),
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node.type === 'db-trigger') {
|
||||
const { triggerName, triggerTableName, schemaName, dbName, id } = node.dataRef;
|
||||
addTab({
|
||||
id: `trigger-${node.key}`,
|
||||
title: t('sidebar.tab.trigger', { name: triggerName }),
|
||||
type: 'trigger',
|
||||
connectionId: id,
|
||||
dbName,
|
||||
triggerName,
|
||||
triggerTableName,
|
||||
schemaName,
|
||||
sidebarLocateKey: String(node.key || ''),
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node.type === 'db-event') {
|
||||
openEventDefinition(node);
|
||||
return true;
|
||||
}
|
||||
if (node.type === 'routine') {
|
||||
const { routineName, routineType, dbName, id } = node.dataRef;
|
||||
const typeLabel = t(routineType === 'PROCEDURE' ? 'sidebar.object.procedure' : 'sidebar.object.function');
|
||||
addTab({
|
||||
id: `routine-def-${node.key}`,
|
||||
title: t('sidebar.tab.routine_definition', { type: typeLabel, name: routineName }),
|
||||
type: 'routine-def',
|
||||
connectionId: id,
|
||||
dbName,
|
||||
routineName,
|
||||
routineType
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (node.type === 'sequence') {
|
||||
openSequenceDefinition(node);
|
||||
return true;
|
||||
}
|
||||
if (node.type === 'package') {
|
||||
openPackageDefinition(node);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const onSelect = (keys: React.Key[], info: any) => {
|
||||
if (isV2Ui && info?.node?.type === 'v2-table-section') {
|
||||
return;
|
||||
@@ -1514,6 +1574,8 @@ const Sidebar: React.FC<{
|
||||
schemaName,
|
||||
} as any);
|
||||
}, 250);
|
||||
} else if (openSidebarObjectNode(info.node)) {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user