fix(sidebar): avoid synchronous selection pruning

This commit is contained in:
t8y2 committed 2026-08-18 15:47:44 +08:00
1 parent 94949eb1c7
commit 0b49c5a761
4 files changed
+59 -12

No files matched your search

@@ -30,7 +30,7 @@ import { copyNameForTreeNode, objectSourceTargetForTreeNode } from "@/lib/sideba
import { supportsTypeObjectSource } from "@/lib/database/databaseObjectCapabilities";
import { copyToClipboard } from "@/lib/common/clipboard";
import { connectionPasteTargetGroupId, copySelectedConnectionsToClipboards, selectedConnectionEditTarget } from "@/lib/sidebar/sidebarConnectionSelection";
import { pruneTreeSelectionToVisibleNodes } from "@/lib/sidebar/sidebarTreeSelection";
import { pruneTreeSelectionToVisibleNodeIds } from "@/lib/sidebar/sidebarTreeSelection";
import { isEditableSidebarTypeSearchTarget, sidebarTypeSearchNextQuery } from "@/lib/sidebar/sidebarTypeSearch";
import { isInternalDorisCatalog, usesTreeSchemaMode } from "@/lib/database/databaseFeatureSupport";
import { connectionObjectTreeNodeSchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/database/jdbcDialect";
@@ -807,11 +807,13 @@ const selectableVisibleNodes = computed<TreeNode[]>(() => flatTreeIndex.value.se
const selectableVisibleNodeIndexById = computed(() => flatTreeIndex.value.selectableVisibleNodeIndexById);
const useVirtualTree = computed(() => shouldVirtualizeFlatTree(flatNodes.value.length));
const activeTab = computed(() => queryStore.tabs.find((tab) => tab.id === queryStore.activeTabId));
const hasTreeMultiSelection = computed(() => store.connectionMultiSelectActive || store.selectedTreeNodeIds.length > 1);
watch(
visibleNodes,
(nodes) => {
const next = pruneTreeSelectionToVisibleNodes(nodes, {
() => (hasTreeMultiSelection.value ? flatTreeIndex.value.nodeById : null),
(visibleNodeIds) => {
if (!visibleNodeIds) return;
const next = pruneTreeSelectionToVisibleNodeIds(visibleNodeIds, {
nodeIds: store.selectedTreeNodeIds,
activeNodeId: store.selectedTreeNodeId,
anchorNodeId: store.treeSelectionAnchorId,
@@ -823,7 +825,7 @@ watch(
store.treeSelectionAnchorId = next.anchorNodeId;
if (!next.nodeIds.length) store.connectionMultiSelectActive = false;
},
{ flush: "sync" },
{ flush: "post" },
);
// --- Sticky database header ---
@@ -0,0 +1,16 @@
import { readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
const connectionTreeSource = readFileSync(new URL("../ConnectionTree.vue", import.meta.url), "utf8");
describe("ConnectionTree selection pruning", () => {
it("does not track the visible tree outside multi-selection", () => {
expect(connectionTreeSource).toContain("store.connectionMultiSelectActive || store.selectedTreeNodeIds.length > 1");
expect(connectionTreeSource).toContain("hasTreeMultiSelection.value ? flatTreeIndex.value.nodeById : null");
expect(connectionTreeSource).not.toMatch(/watch\(\s*visibleNodes,/);
});
it("defers selection cleanup until after the tree render", () => {
expect(connectionTreeSource).toMatch(/pruneTreeSelectionToVisibleNodeIds[\s\S]*?\{ flush: "post" \}/);
});
});