fix(sidebar): restore table list after remote search

This commit is contained in:
Guoyu Su authored and GitHub committed 2026-09-04 12:41:05 +08:00
1 parent b6beefc89e
commit 299c342d6d
6 files changed
+137 -2

No files matched your search

@@ -429,9 +429,10 @@ function collectExpandedObjectSearchTargets(node: TreeNode, tasks: SidebarSearch
if (searchableObjectGroupTypes.has(node.type)) {
if (searchAutoExpandedNodeIds.has(node.id)) {
// Search opened this group on the user's behalf to check for matches;
// once the query is gone there is nothing to show, so collapse it back
// instead of reloading and leaving it open.
// once the query is gone, drop the filtered projection and collapse it
// back. Its next explicit expansion will load the ordinary first page.
node.isExpanded = false;
store.discardFilteredTreeNodeChildren(node.id);
} else {
tasks.push(() => store.loadObjectGroupChildren(node, { force: true }));
}
@@ -715,6 +715,12 @@ async function openDirectNavigationNode(node: TreeNode, requestId: number) {
async function toggle(requestId = beginNavigationRequest()) {
const node = activeNode.value;
// Remote sidebar search intentionally descends into one active connection.
// Keep that scope aligned even when this toggle is satisfied entirely from
// already-loaded children and therefore performs no connection request.
if (node.connectionId && connectionStore.connectedIds.has(node.connectionId)) {
connectionStore.activeConnectionId = node.connectionId;
}
const treeLoadSearchOptions = sidebarTreeContext?.getTreeLoadSearchOptions?.(node);
if (isDirectNavigationTreeNode(node.type)) {
try {
@@ -18,6 +18,7 @@ describe("ConnectionTree global search loading", () => {
expect(source).toContain("while (deferredSearchQuery.value === query && store.sidebarSearchQuery === query)");
expect(source).toContain("const restoreTasks = !newQuery && oldQuery ? restoreTrackedSearchTargets() : [];");
expect(source).toContain("if (shouldCollapse) node.isExpanded = false;");
expect(source).toContain("store.discardFilteredTreeNodeChildren(node.id);");
});
it("limits concurrent metadata loads without dropping a task", async () => {
@@ -11,6 +11,8 @@ import SidebarTreeRuntimeHost from "@/components/sidebar/SidebarTreeRuntimeHost.
const connectionStore = {
treeNodes: [] as TreeNode[],
sidebarSearchQuery: "",
activeConnectionId: null as string | null,
connectedIds: new Set<string>(),
canUseLoadedTreeNodeToggle: vi.fn(() => true),
releaseCollapsedTreeNodeChildren: vi.fn(),
getConfig: vi.fn(() => ({ db_type: "mysql", name: "connection" })),
@@ -56,12 +58,47 @@ afterEach(() => {
document.body.innerHTML = "";
connectionStore.treeNodes = [];
connectionStore.sidebarSearchQuery = "";
connectionStore.activeConnectionId = null;
connectionStore.connectedIds.clear();
vi.clearAllMocks();
connectionStore.canUseLoadedTreeNodeToggle.mockReturnValue(true);
connectionStore.getConfig.mockReturnValue({ db_type: "mysql", name: "connection" });
});
describe("SidebarTreeRuntimeHost expansion", () => {
it("activates the owning connection when a cached node toggles locally", async () => {
const group: TreeNode = {
id: "mysql:basic:__tables",
label: "tree.tables",
type: "group-tables",
connectionId: "mysql",
database: "basic",
isExpanded: false,
children: [{ id: "mysql:basic:orders", label: "orders", type: "table", connectionId: "mysql", database: "basic" }],
};
connectionStore.connectedIds.add("mysql");
connectionStore.activeConnectionId = "another-connection";
const host = ref<InstanceType<typeof SidebarTreeRuntimeHost> | null>(null);
const app = createApp(
defineComponent({
setup: () => () => h(SidebarTreeRuntimeHost, { ref: host, node: group, depth: 0 }),
}),
);
mountedApps.push(app);
const container = document.createElement("div");
document.body.append(container);
app.use(i18n);
app.mount(container);
host.value?.toggleNode(group);
await nextTick();
expect(connectionStore.activeConnectionId).toBe("mysql");
expect(group.isExpanded).toBe(true);
expect(connectionStore.loadObjectGroupChildren).not.toHaveBeenCalled();
});
it("publishes a rendered group collapse and synchronizes the live tree", async () => {
const liveGroup: TreeNode = {
id: "connection:database:__tables",