perf(sidebar): reduce tree selection overhead
This commit is contained in:
1 parent
b4a207fc6b
commit
a2c9503a3d
5 files changed
+56
-10
No files matched your search
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, nextTick, watch, type Component } from "vue";
|
||||
import { ref, computed, nextTick, watch, provide, type Component } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Search, X, ListFilter, Crosshair, Server, Database, FolderTree, Table2, Eye, RotateCcw } from "@lucide/vue";
|
||||
import { useConnectionStore } from "@/stores/connectionStore";
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
shouldVirtualizeFlatTree,
|
||||
type FlatTreeNode,
|
||||
} from "@/composables/useFlatTree";
|
||||
import { sidebarTreeContextKey } from "@/lib/sidebarTreeContext";
|
||||
import TreeItem from "./TreeItem.vue";
|
||||
import { RecycleScroller } from "vue-virtual-scroller";
|
||||
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";
|
||||
@@ -148,6 +149,11 @@ const filteredNodes = computed(() => {
|
||||
|
||||
const flatNodes = computed<FlatTreeNode[]>(() => flattenTree(filteredNodes.value));
|
||||
const visibleNodes = computed<TreeNode[]>(() => flatNodes.value.map((item) => item.node));
|
||||
const visibleNodeIndexById = computed(() => {
|
||||
const next = new Map<string, number>();
|
||||
visibleNodes.value.forEach((node, index) => next.set(node.id, index));
|
||||
return next;
|
||||
});
|
||||
const useVirtualTree = computed(() => shouldVirtualizeFlatTree(flatNodes.value.length));
|
||||
const activeTab = computed(() => queryStore.tabs.find((tab) => tab.id === queryStore.activeTabId));
|
||||
const sidebarTreeOverflowClass = computed(() =>
|
||||
@@ -156,6 +162,11 @@ const sidebarTreeOverflowClass = computed(() =>
|
||||
: "overflow-x-hidden",
|
||||
);
|
||||
|
||||
provide(sidebarTreeContextKey, {
|
||||
getVisibleNodes: () => visibleNodes.value,
|
||||
getVisibleNodeIndex: (id: string) => visibleNodeIndexById.value.get(id) ?? -1,
|
||||
});
|
||||
|
||||
const pendingRenameGroupId = ref<string | null>(null);
|
||||
const highlightedNodeId = ref<string | null>(null);
|
||||
let highlightTimer: number | undefined;
|
||||
@@ -495,7 +506,6 @@ defineExpose({ focusSearch, createNewGroup });
|
||||
:drag-disabled="isFiltering"
|
||||
:pending-rename="pendingRenameGroupId === item.node.id"
|
||||
:highlighted="highlightedNodeId === item.node.id"
|
||||
:visible-nodes="visibleNodes"
|
||||
@node-toggled="onNodeToggled"
|
||||
@search-toggle="onSearchToggle"
|
||||
@rename-started="pendingRenameGroupId = null"
|
||||
@@ -516,7 +526,6 @@ defineExpose({ focusSearch, createNewGroup });
|
||||
:drag-disabled="isFiltering"
|
||||
:pending-rename="pendingRenameGroupId === item.node.id"
|
||||
:highlighted="highlightedNodeId === item.id"
|
||||
:visible-nodes="visibleNodes"
|
||||
@node-toggled="onNodeToggled"
|
||||
@search-toggle="onSearchToggle"
|
||||
@rename-started="pendingRenameGroupId = null"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, nextTick, watch, onBeforeUnmount } from "vue";
|
||||
import { ref, computed, nextTick, watch, onBeforeUnmount, inject } from "vue";
|
||||
import { useSqlHighlighter } from "@/composables/useSqlHighlighter";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
@@ -127,8 +127,10 @@ import { hasTreeNodeDatabaseContext } from "@/lib/treeNodeContext";
|
||||
import { sidebarDisplayTableName } from "@/lib/sidebarTableNameDisplay";
|
||||
import {
|
||||
selectedTreeNodesInVisibleOrder as orderSelectedTreeNodes,
|
||||
treeSelectionRangeIdsByIndex,
|
||||
treeSelectionRangeIds,
|
||||
} from "@/lib/sidebarTreeSelection";
|
||||
import { sidebarTreeContextKey } from "@/lib/sidebarTreeContext";
|
||||
import DangerConfirmDialog from "@/components/editor/DangerConfirmDialog.vue";
|
||||
import ProcedureExecutionDialog from "@/components/objects/ProcedureExecutionDialog.vue";
|
||||
import { useExportTracker, type ExportTask } from "@/composables/useExportTracker";
|
||||
@@ -174,7 +176,6 @@ const props = defineProps<{
|
||||
dragDisabled?: boolean;
|
||||
pendingRename?: boolean;
|
||||
highlighted?: boolean;
|
||||
visibleNodes?: TreeNode[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -186,6 +187,7 @@ const emit = defineEmits<{
|
||||
const usesFullWidthLabel = computed(() =>
|
||||
usesFullWidthTreeLabel(props.node.type, settingsStore.editorSettings.sidebarAllowHorizontalScroll),
|
||||
);
|
||||
const sidebarTreeContext = inject(sidebarTreeContextKey, null);
|
||||
const rowWidthClass = computed(() => (usesFullWidthLabel.value ? "w-max min-w-full" : "w-full min-w-0"));
|
||||
const labelWidthClass = computed(() =>
|
||||
usesFullWidthLabel.value ? "shrink-0 whitespace-nowrap" : "min-w-0 flex-1 truncate",
|
||||
@@ -459,7 +461,7 @@ function runRowClickAction() {
|
||||
}
|
||||
|
||||
function visibleTreeNodes(): TreeNode[] {
|
||||
if (props.visibleNodes) return props.visibleNodes;
|
||||
if (sidebarTreeContext) return sidebarTreeContext.getVisibleNodes();
|
||||
return flattenTree(connectionStore.treeNodes).map((item) => item.node);
|
||||
}
|
||||
|
||||
@@ -485,10 +487,20 @@ function toggleTreeNodeSelection(node: TreeNode) {
|
||||
function selectTreeNodeRange(node: TreeNode) {
|
||||
const visible = visibleTreeNodes();
|
||||
const anchorId = connectionStore.treeSelectionAnchorId || connectionStore.selectedTreeNodeId || node.id;
|
||||
const currentIndex = sidebarTreeContext ? sidebarTreeContext.getVisibleNodeIndex(node.id) : -1;
|
||||
const anchorIndex = sidebarTreeContext ? sidebarTreeContext.getVisibleNodeIndex(anchorId) : -1;
|
||||
|
||||
if (sidebarTreeContext && currentIndex >= 0 && anchorIndex >= 0) {
|
||||
connectionStore.selectedTreeNodeIds = treeSelectionRangeIdsByIndex(visible, currentIndex, anchorIndex, node.id);
|
||||
connectionStore.selectedTreeNodeId = node.id;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!visible.some((item) => item.id === anchorId) || !visible.some((item) => item.id === node.id)) {
|
||||
selectSingleTreeNode(node);
|
||||
return;
|
||||
}
|
||||
|
||||
const rangeIds = treeSelectionRangeIds(visible, node.id, anchorId, connectionStore.selectedTreeNodeId);
|
||||
connectionStore.selectedTreeNodeIds = rangeIds;
|
||||
connectionStore.selectedTreeNodeId = node.id;
|
||||
|
||||
Reference in new issue
Block a user