fix(sidebar): locate grouped connections after restart

Closes #6840
This commit is contained in:
t8y2 committed 2026-08-22 05:46:37 +00:00
1 parent a6f4cebd18
commit 11179676ed
3 files changed
+88 -3

No files matched your search

@@ -34,7 +34,17 @@ import { pruneTreeSelectionToVisibleNodeIds } from "@/lib/sidebar/sidebarTreeSel
import { isEditableSidebarTypeSearchTarget, sidebarTypeSearchNextQuery } from "@/lib/sidebar/sidebarTypeSearch"; import { isEditableSidebarTypeSearchTarget, sidebarTypeSearchNextQuery } from "@/lib/sidebar/sidebarTypeSearch";
import { isInternalDorisCatalog, usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport"; import { isInternalDorisCatalog, usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport";
import { connectionObjectTreeNodeSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect"; import { connectionObjectTreeNodeSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
import { activeTabSidebarTarget, findSidebarNodeForActiveTab, findSidebarNodeForTarget, findNodePathForTarget, scrollTopForSidebarNode, shouldScrollActiveSidebarSelection, type ActiveTabSidebarTarget, type SidebarNodeScrollAlign } from "@/lib/sidebar/sidebarActiveTabTarget"; import {
activeTabSidebarTarget,
findSidebarConnectionNode,
findSidebarNodeForActiveTab,
findSidebarNodeForTarget,
findNodePathForTarget,
scrollTopForSidebarNode,
shouldScrollActiveSidebarSelection,
type ActiveTabSidebarTarget,
type SidebarNodeScrollAlign,
} from "@/lib/sidebar/sidebarActiveTabTarget";
import { findLoadedTableTargetForCandidate, queryContextTargetFromCandidate, queryCursorTableCandidate, type QueryCursorTableCandidate } from "@/lib/sql/queryCursorTableTarget"; import { findLoadedTableTargetForCandidate, queryContextTargetFromCandidate, queryCursorTableCandidate, type QueryCursorTableCandidate } from "@/lib/sql/queryCursorTableTarget";
import { createFlatTreeIndex, SIDEBAR_TREE_ROW_HEIGHT, SIDEBAR_TREE_PRERENDER_COUNT, SIDEBAR_TREE_SCROLL_BUFFER, flattenTree, shouldVirtualizeFlatTree, type FlatTreeNode } from "@/composables/useFlatTree"; import { createFlatTreeIndex, SIDEBAR_TREE_ROW_HEIGHT, SIDEBAR_TREE_PRERENDER_COUNT, SIDEBAR_TREE_SCROLL_BUFFER, flattenTree, shouldVirtualizeFlatTree, type FlatTreeNode } from "@/composables/useFlatTree";
import { sidebarTreeContextKey } from "@/lib/sidebar/sidebarTreeContext"; import { sidebarTreeContextKey } from "@/lib/sidebar/sidebarTreeContext";
@@ -1414,7 +1424,7 @@ async function ensureTreeLoadedForTarget(target: ActiveTabSidebarTarget, opts?:
const loadOptions = force ? { force: true } : undefined; const loadOptions = force ? { force: true } : undefined;
// Ensure databases are loaded under the connection // Ensure databases are loaded under the connection
const connNode = store.treeNodes.find((n) => n.id === connId); const connNode = findSidebarConnectionNode(store.treeNodes, connId);
if (connNode && (force || !connNode.children || connNode.children.length === 0)) { if (connNode && (force || !connNode.children || connNode.children.length === 0)) {
try { try {
if (config.db_type === "redis") { if (config.db_type === "redis") {
@@ -86,6 +86,22 @@ export type ActiveTabSidebarTarget =
savedSqlId: string; savedSqlId: string;
}; };
/**
* Resolve a connection root without walking its potentially large object tree.
* Grouped connections live below connection-group nodes, while a connection
* id can also appear on descendants, so only group children are traversed.
*/
export function findSidebarConnectionNode(nodes: readonly TreeNode[], connectionId: string): TreeNode | null {
for (const node of nodes) {
if (node.type === "connection" && node.id === connectionId) return node;
if (node.type === "connection-group" && node.children) {
const found = findSidebarConnectionNode(node.children, connectionId);
if (found) return found;
}
}
return null;
}
export function activeTabSidebarTarget(tab: QueryTab | undefined | null): ActiveTabSidebarTarget | null { export function activeTabSidebarTarget(tab: QueryTab | undefined | null): ActiveTabSidebarTarget | null {
if (!tab) return null; if (!tab) return null;
+60 -1
View File
@@ -1,6 +1,6 @@
import { strict as assert } from "node:assert"; import { strict as assert } from "node:assert";
import { test } from "vitest"; import { test } from "vitest";
import { activeTabSidebarTarget, findNodePathForTarget, findSidebarNodeForActiveTab, scrollTopForSidebarNode, shouldScrollActiveSidebarSelection } from "../../apps/desktop/src/lib/sidebar/sidebarActiveTabTarget.ts"; import { activeTabSidebarTarget, findNodePathForTarget, findSidebarConnectionNode, findSidebarNodeForActiveTab, scrollTopForSidebarNode, shouldScrollActiveSidebarSelection } from "../../apps/desktop/src/lib/sidebar/sidebarActiveTabTarget.ts";
import type { FlatTreeNode } from "../../apps/desktop/src/composables/useFlatTree.ts"; import type { FlatTreeNode } from "../../apps/desktop/src/composables/useFlatTree.ts";
import type { QueryTab, TreeNode } from "../../apps/desktop/src/types/database.ts"; import type { QueryTab, TreeNode } from "../../apps/desktop/src/types/database.ts";
@@ -8,6 +8,65 @@ function flat(node: TreeNode, depth = 0): FlatTreeNode {
return { id: node.id, node, depth, type: node.type }; return { id: node.id, node, depth, type: node.type };
} }
test("findSidebarConnectionNode resolves grouped roots without scanning descendants", () => {
const groupedConnection: TreeNode = {
id: "conn-grouped",
label: "Grouped",
type: "connection",
connectionId: "conn-grouped",
children: [
{
id: "conn-grouped:app",
label: "app",
type: "database",
connectionId: "conn-grouped",
database: "app",
},
],
};
const nestedGroups: TreeNode[] = [
{
id: "group-outer",
label: "Outer",
type: "connection-group",
children: [
{
id: "group-inner",
label: "Inner",
type: "connection-group",
children: [groupedConnection],
},
],
},
];
assert.equal(findSidebarConnectionNode(nestedGroups, "conn-grouped"), groupedConnection);
assert.equal(findSidebarConnectionNode(nestedGroups, "missing"), null);
assert.equal(
findSidebarConnectionNode(
[
{
id: "conn-root",
label: "Root",
type: "connection",
connectionId: "conn-root",
children: [
{
id: "conn-nested-decoy",
label: "Decoy",
type: "connection",
connectionId: "conn-grouped",
},
],
},
...nestedGroups,
],
"conn-grouped",
),
groupedConnection,
);
});
test("findNodePathForTarget handles loaded, unloaded, and MySQL schema fallback trees", () => { test("findNodePathForTarget handles loaded, unloaded, and MySQL schema fallback trees", () => {
const cases = [ const cases = [
{ {