feat(sidebar): 添加一键折叠所有节点功能
- 在侧边栏中添加了“折叠所有”按钮,用户可以一键折叠所有展开的节点。 - 更新了相关的国际化文本,支持多语言。 - 增加了 collapseAllGroups 和 collapseExpandedTreeNodes 函数以支持新功能。
This commit is contained in:
parent
e7dffeca37
commit
af9ad39ffb
|
|
@ -2,7 +2,7 @@
|
|||
import { computed, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { translateBackendError } from "@/i18n/backend-errors";
|
||||
import { Upload, Download, FolderPlus, RefreshCw, ChevronsLeft } from "@lucide/vue";
|
||||
import { Upload, Download, FolderPlus, RefreshCw, ChevronsLeft, ChevronsUp } from "@lucide/vue";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
|
||||
import LightDropdown from "@/components/ui/LightDropdown.vue";
|
||||
|
|
@ -45,6 +45,10 @@ function createNewGroup() {
|
|||
void connectionTreeRef.value?.createNewGroup();
|
||||
}
|
||||
|
||||
function collapseAllTreeNodes() {
|
||||
connectionTreeRef.value?.collapseAllTreeNodes();
|
||||
}
|
||||
|
||||
function focusSearch(): boolean {
|
||||
return connectionTreeRef.value?.focusSearch() ?? false;
|
||||
}
|
||||
|
|
@ -88,6 +92,14 @@ defineExpose({ focusSearch });
|
|||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("sidebar.export") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="collapseAllTreeNodes">
|
||||
<ChevronsUp class="h-3 w-3" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{{ t("sidebar.collapseAll") }}</TooltipContent>
|
||||
</Tooltip>
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" @click="createNewGroup">
|
||||
|
|
|
|||
|
|
@ -702,6 +702,13 @@ function onSearchToggle(node: TreeNode) {
|
|||
searchCollapsedIds.value = next;
|
||||
}
|
||||
|
||||
function collapseAllTreeNodes() {
|
||||
store.collapseAllTreeNodes();
|
||||
if (isSearching.value) {
|
||||
searchCollapsedIds.value = new Set(flatNodes.value.filter((item) => item.node.children?.length).map((item) => item.id));
|
||||
}
|
||||
}
|
||||
|
||||
function currentTreeScroller(): HTMLElement | null {
|
||||
return ((useVirtualTree.value ? treeScrollerRef.value?.$el : plainTreeScrollerRef.value) as HTMLElement | undefined) ?? null;
|
||||
}
|
||||
|
|
@ -859,7 +866,7 @@ onUnmounted(() => {
|
|||
window.clearTimeout(sidebarScrollingTimer);
|
||||
});
|
||||
|
||||
defineExpose({ focusSearch, createNewGroup });
|
||||
defineExpose({ focusSearch, createNewGroup, collapseAllTreeNodes });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -920,7 +927,7 @@ defineExpose({ focusSearch, createNewGroup });
|
|||
:prerender="SIDEBAR_TREE_PRERENDER_COUNT"
|
||||
:skip-hover="true"
|
||||
key-field="id"
|
||||
type-field="type"
|
||||
type-field="poolType"
|
||||
flow-mode
|
||||
>
|
||||
<template #default="{ item }">
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ import { clearActiveTableReferencePayload, createTableReferencePayload, createTa
|
|||
import { editableRowIdentifierColumns, usesSyntheticRowIdKey } from "@/lib/tableEditing";
|
||||
import { tableOpenPageLimit } from "@/lib/tableOpenPageLimit";
|
||||
import { supportsDatabaseCreation, supportsDatabaseSearch, supportsFieldLineage, supportsObjectBrowserTreeNode, supportsSchemaDiagram, supportsSqlFileExecution, supportsTableImport, supportsTableTruncate, supportsTableStructureEditing, usesTreeSchemaMode } from "@/lib/databaseCapabilities";
|
||||
import { copyNameForTreeNode, objectSourceKindForTreeNode, sidebarSelectionCopyAction, treeNodeRowAction, treeNodeRowDoubleClickAction } from "@/lib/treeNodeClick";
|
||||
import { copyNameForTreeNode, objectSourceKindForTreeNode, shouldRunTreeNodeRowAction, sidebarSelectionCopyAction, treeNodeRowAction, treeNodeRowDoubleClickAction } from "@/lib/treeNodeClick";
|
||||
import { formatSqlInsert } from "@/lib/exportFormats";
|
||||
import { joinExportedDdls } from "@/lib/ddlExport";
|
||||
import { fetchTableDataForExport } from "@/lib/tableDataExport";
|
||||
|
|
@ -636,17 +636,20 @@ async function toggle() {
|
|||
}
|
||||
}
|
||||
|
||||
function runRowClickAction() {
|
||||
function runRowClickAction(clickDetail: number) {
|
||||
const node = props.node;
|
||||
if (node.type === "load-more") {
|
||||
if (clickDetail > 1) return;
|
||||
void loadMoreObjectGroupChildren();
|
||||
return;
|
||||
}
|
||||
if (node.type === "object-browser") {
|
||||
if (clickDetail > 1) return;
|
||||
void openObjectBrowser();
|
||||
return;
|
||||
}
|
||||
const action = treeNodeRowAction(node.type, canExpand.value, settingsStore.editorSettings.sidebarActivation);
|
||||
if (!shouldRunTreeNodeRowAction(action, clickDetail)) return;
|
||||
if (action === "open-data") {
|
||||
openData();
|
||||
} else if (node.type === "mongo-collection") {
|
||||
|
|
@ -680,6 +683,18 @@ async function loadAllObjectGroupChildren() {
|
|||
}
|
||||
}
|
||||
|
||||
function onToggleClick() {
|
||||
selectSingleTreeNode(props.node);
|
||||
rowRef.value?.focus({ preventScroll: true });
|
||||
void toggle();
|
||||
}
|
||||
|
||||
function onToggleMouseDown(event: MouseEvent) {
|
||||
if (event.button !== 0) return;
|
||||
selectSingleTreeNode(props.node);
|
||||
rowRef.value?.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
function visibleTreeNodes(): TreeNode[] {
|
||||
if (sidebarTreeContext) return sidebarTreeContext.getVisibleNodes();
|
||||
return flattenTree(connectionStore.treeNodes).map((item) => item.node);
|
||||
|
|
@ -749,8 +764,7 @@ function onClick(event: MouseEvent) {
|
|||
selectSingleTreeNode(props.node);
|
||||
rowRef.value?.focus({ preventScroll: true });
|
||||
if (settingsStore.editorSettings.sidebarActivation === "double") return;
|
||||
if (event.detail > 1) return;
|
||||
runRowClickAction();
|
||||
runRowClickAction(event.detail);
|
||||
}
|
||||
|
||||
function onTreeItemContextMenu(event: MouseEvent, openContextMenu: (event: MouseEvent) => void) {
|
||||
|
|
@ -4487,7 +4501,7 @@ function treeItemMenuItems(): ContextMenuItem[] {
|
|||
<div v-if="showDropBefore" class="absolute right-2 top-0 h-0.5 bg-primary rounded-full pointer-events-none" :style="{ left: paddingLeft }" />
|
||||
<div v-if="showDropAfter" class="absolute right-2 bottom-0 h-0.5 bg-primary rounded-full pointer-events-none" :style="{ left: paddingLeft }" />
|
||||
<template v-if="canExpand">
|
||||
<button type="button" class="-m-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted hover:text-foreground" @click.stop="toggle">
|
||||
<button type="button" class="-m-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-sm text-muted-foreground hover:bg-muted hover:text-foreground" @mousedown.stop="onToggleMouseDown" @click.stop="onToggleClick">
|
||||
<Loader2 v-if="node.isLoading" class="w-3.5 h-3.5 animate-spin" />
|
||||
<ChevronDown v-else-if="node.isExpanded" class="w-3.5 h-3.5" />
|
||||
<ChevronRight v-else class="w-3.5 h-3.5" />
|
||||
|
|
|
|||
|
|
@ -9,11 +9,18 @@ export interface FlatTreeNode {
|
|||
depth: number;
|
||||
id: string;
|
||||
type: TreeNodeType;
|
||||
poolType: string;
|
||||
}
|
||||
|
||||
function walk(children: TreeNode[], depth: number, result: FlatTreeNode[]) {
|
||||
for (const node of children) {
|
||||
result.push({ node, depth, id: node.id, type: node.type });
|
||||
result.push({
|
||||
node,
|
||||
depth,
|
||||
id: node.id,
|
||||
type: node.type,
|
||||
poolType: node.type === "connection-group" ? `${node.type}:${node.id}` : node.type,
|
||||
});
|
||||
if (node.isExpanded && node.children) {
|
||||
walk(node.children, depth + 1, result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export default {
|
|||
importDbeaver: "Import DBeaver",
|
||||
importDatagrip: "Import DataGrip",
|
||||
export: "Export Connections",
|
||||
collapseAll: "Collapse all",
|
||||
collapse: "Collapse sidebar",
|
||||
expand: "Expand sidebar",
|
||||
showMore: "Show {count} more...",
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export default withEnglishFallback({
|
|||
importDbeaver: "Importar DBeaver",
|
||||
importDatagrip: "Importar DataGrip",
|
||||
export: "Exportar conexiones",
|
||||
collapseAll: "Contraer todo",
|
||||
collapse: "Contraer barra lateral",
|
||||
expand: "Expandir barra lateral",
|
||||
showMore: "Mostrar {count} más...",
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ export default withEnglishFallback({
|
|||
importDbeaver: "Importa DBeaver",
|
||||
importDatagrip: "Importa DataGrip",
|
||||
export: "Esporta Connessioni",
|
||||
collapseAll: "Riduci tutto",
|
||||
collapse: "Riduci barra laterale",
|
||||
expand: "Espandi barra laterale",
|
||||
showMore: "Mostra altri {count}...",
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export default withEnglishFallback({
|
|||
importDbeaver: "DBeaverをインポート",
|
||||
importDatagrip: "DataGripをインポート",
|
||||
export: "接続をエクスポート",
|
||||
collapseAll: "すべて折りたたむ",
|
||||
collapse: "サイドバーを折りたたむ",
|
||||
expand: "サイドバーを展開",
|
||||
showMore: "さらに{count}件表示...",
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export default withEnglishFallback({
|
|||
importDbeaver: "Importar DBeaver",
|
||||
importDatagrip: "Importar DataGrip",
|
||||
export: "Exportar Conexões",
|
||||
collapseAll: "Recolher tudo",
|
||||
collapse: "Recolher barra lateral",
|
||||
expand: "Expandir barra lateral",
|
||||
showMore: "Mostrar mais {count}...",
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export default withEnglishFallback({
|
|||
importDbeaver: "导入 DBeaver",
|
||||
importDatagrip: "导入 DataGrip",
|
||||
export: "导出连接",
|
||||
collapseAll: "一键折叠",
|
||||
collapse: "收起侧边栏",
|
||||
expand: "展开侧边栏",
|
||||
showMore: "加载更多 ({count})...",
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ export default withEnglishFallback({
|
|||
importDbeaver: "匯入 DBeaver",
|
||||
importDatagrip: "匯入 DataGrip",
|
||||
export: "匯出連線",
|
||||
collapseAll: "一鍵收合",
|
||||
collapse: "收合側邊欄",
|
||||
expand: "展開側邊欄",
|
||||
showMore: "再顯示 {count} 個……",
|
||||
|
|
|
|||
|
|
@ -309,6 +309,13 @@ export function toggleGroupCollapsed(layout: SidebarLayout, groupId: string): Si
|
|||
};
|
||||
}
|
||||
|
||||
export function collapseAllGroups(layout: SidebarLayout): SidebarLayout {
|
||||
return {
|
||||
...layout,
|
||||
groups: layout.groups.map((group) => (group.collapsed ? group : { ...group, collapsed: true })),
|
||||
};
|
||||
}
|
||||
|
||||
export function removeConnectionFromSidebarLayout(layout: SidebarLayout, connectionId: string): SidebarLayout {
|
||||
return { ...layout, order: removeConnectionFromEntries(layout.order, connectionId) };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
import type { TreeNode } from "@/types/database";
|
||||
|
||||
export function collapseExpandedTreeNodes(nodes: TreeNode[]): number {
|
||||
let collapsedCount = 0;
|
||||
|
||||
for (const node of nodes) {
|
||||
if (node.isExpanded) {
|
||||
node.isExpanded = false;
|
||||
collapsedCount += 1;
|
||||
}
|
||||
if (node.children?.length) {
|
||||
collapsedCount += collapseExpandedTreeNodes(node.children);
|
||||
}
|
||||
}
|
||||
|
||||
return collapsedCount;
|
||||
}
|
||||
|
|
@ -33,6 +33,11 @@ export function treeNodeRowAction(type: TreeNodeType, canExpand: boolean, activa
|
|||
return "none";
|
||||
}
|
||||
|
||||
export function shouldRunTreeNodeRowAction(action: TreeNodeRowAction, clickDetail: number): boolean {
|
||||
if (action === "none") return false;
|
||||
return action === "toggle" || clickDetail <= 1;
|
||||
}
|
||||
|
||||
export function treeNodeRowDoubleClickAction(type: TreeNodeType, canOpenObjectBrowser: boolean, activation: SidebarActivation = "single", canExpand = false): TreeNodeRowDoubleClickAction {
|
||||
if (activation === "double") {
|
||||
if (dataNodeTypes.has(type)) return "open-data";
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
renameGroup as renameGroupOp,
|
||||
deleteGroup as deleteGroupOp,
|
||||
toggleGroupCollapsed as toggleGroupCollapsedOp,
|
||||
collapseAllGroups as collapseAllGroupsOp,
|
||||
moveConnectionToGroup as moveConnectionToGroupOp,
|
||||
remapSidebarLayoutConnectionIds,
|
||||
reorderEntry as reorderEntryOp,
|
||||
|
|
@ -26,6 +27,7 @@ import { isSchemaAware, normalizeSidebarObjectKind, sidebarObjectKindsForDatabas
|
|||
import { connectionObjectTreeNodeSchema, connectionObjectTreeQuerySchema, connectionUsesDatabaseObjectTreeMode, effectiveDatabaseTypeForConnection } from "@/lib/jdbcDialect";
|
||||
import { buildDatabaseTreeNodes, buildDuckDbConnectionTreeNodes, sortSidebarNames, shouldIncludeDefaultDatabaseNode } from "@/lib/databaseTree";
|
||||
import { buildSqlServerDatabaseTreeNodes } from "@/lib/sqlServerTree";
|
||||
import { collapseExpandedTreeNodes } from "@/lib/sidebarTreeCollapse";
|
||||
import { findDatabaseTreeNode } from "@/lib/treeRefreshTarget";
|
||||
import { shouldMarkDisconnected } from "@/lib/connectionHealth";
|
||||
import { connectionAttemptOriginalErrorMessage, connectionAttemptTimeoutMessage, connectionAttemptTimeoutMs } from "@/lib/connectionAttemptTimeout";
|
||||
|
|
@ -3505,6 +3507,11 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
persistSidebarLayoutDebounced();
|
||||
}
|
||||
|
||||
function collapseAllTreeNodes() {
|
||||
updateLayoutAndRebuild(collapseAllGroupsOp(sidebarLayout.value));
|
||||
collapseExpandedTreeNodes(treeNodes.value);
|
||||
}
|
||||
|
||||
async function refreshAllTree() {
|
||||
const expandedIds = collectExpandedNodeIds(treeNodes.value);
|
||||
const refreshExpandedNodes = async (nodes: TreeNode[]) => {
|
||||
|
|
@ -3936,6 +3943,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
|||
treeNodes,
|
||||
removeTreeNode,
|
||||
refreshAllTree,
|
||||
collapseAllTreeNodes,
|
||||
refreshSidebarObjectPagination,
|
||||
refreshTreeNode,
|
||||
refreshDatabaseTreeNode,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
removeConnectionFromSidebarLayout,
|
||||
emptyLayout,
|
||||
remapSidebarLayoutConnectionIds,
|
||||
collapseAllGroups,
|
||||
} from "../../apps/desktop/src/lib/sidebarLayout.ts";
|
||||
import type { ConnectionConfig, SidebarLayout } from "../../apps/desktop/src/types/database.ts";
|
||||
|
||||
|
|
@ -213,6 +214,37 @@ test("toggleGroupCollapsed flips collapsed state", () => {
|
|||
assert.equal(toggled.groups[0].collapsed, true);
|
||||
});
|
||||
|
||||
test("collapseAllGroups keeps other groups collapsed after one group is reopened", async () => {
|
||||
const layout: SidebarLayout = {
|
||||
groups: [
|
||||
{ id: "g1", name: "G1", collapsed: false },
|
||||
{ id: "g2", name: "G2", collapsed: false },
|
||||
],
|
||||
order: [
|
||||
{ type: "group", id: "g1", children: [{ type: "connection", id: "a" }] },
|
||||
{ type: "group", id: "g2", children: [{ type: "connection", id: "b" }] },
|
||||
],
|
||||
};
|
||||
|
||||
const collapsed = collapseAllGroups(layout);
|
||||
assert.deepEqual(
|
||||
collapsed.groups.map((group) => [group.id, group.collapsed]),
|
||||
[
|
||||
["g1", true],
|
||||
["g2", true],
|
||||
],
|
||||
);
|
||||
|
||||
const reopenedFirst = toggleGroupCollapsed(collapsed, "g1");
|
||||
assert.deepEqual(
|
||||
reopenedFirst.groups.map((group) => [group.id, group.collapsed]),
|
||||
[
|
||||
["g1", false],
|
||||
["g2", true],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
// --- moveConnectionToGroup ---
|
||||
|
||||
test("moveConnectionToGroup moves connection into a group", () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
import { strict as assert } from "node:assert";
|
||||
import { test } from "vitest";
|
||||
import { collapseExpandedTreeNodes } from "../../apps/desktop/src/lib/sidebarTreeCollapse.ts";
|
||||
import type { TreeNode } from "../../apps/desktop/src/types/database.ts";
|
||||
|
||||
test("collapseExpandedTreeNodes collapses all expanded descendants", () => {
|
||||
const nodes: TreeNode[] = [
|
||||
{
|
||||
id: "conn",
|
||||
label: "conn",
|
||||
type: "connection",
|
||||
isExpanded: true,
|
||||
children: [
|
||||
{
|
||||
id: "db",
|
||||
label: "db",
|
||||
type: "database",
|
||||
isExpanded: true,
|
||||
children: [
|
||||
{ id: "tables", label: "Tables", type: "group-tables", isExpanded: false },
|
||||
{ id: "views", label: "Views", type: "group-views", isExpanded: true },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ id: "closed", label: "closed", type: "connection", isExpanded: false },
|
||||
];
|
||||
|
||||
assert.equal(collapseExpandedTreeNodes(nodes), 3);
|
||||
assert.equal(nodes[0].isExpanded, false);
|
||||
assert.equal(nodes[0].children?.[0]?.isExpanded, false);
|
||||
assert.equal(nodes[0].children?.[0]?.children?.[0]?.isExpanded, false);
|
||||
assert.equal(nodes[0].children?.[0]?.children?.[1]?.isExpanded, false);
|
||||
assert.equal(nodes[1].isExpanded, false);
|
||||
});
|
||||
|
||||
test("collapseExpandedTreeNodes returns zero when nothing is expanded", () => {
|
||||
const nodes: TreeNode[] = [{ id: "conn", label: "conn", type: "connection", isExpanded: false }];
|
||||
|
||||
assert.equal(collapseExpandedTreeNodes(nodes), 0);
|
||||
assert.equal(nodes[0].isExpanded, false);
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { test } from "vitest";
|
||||
import assert from "node:assert/strict";
|
||||
import { copyNameForTreeNode, objectSourceKindForTreeNode, sidebarSelectionCopyAction, treeNodeRowAction, treeNodeRowDoubleClickAction } from "../../apps/desktop/src/lib/treeNodeClick.ts";
|
||||
import { copyNameForTreeNode, objectSourceKindForTreeNode, shouldRunTreeNodeRowAction, sidebarSelectionCopyAction, treeNodeRowAction, treeNodeRowDoubleClickAction } from "../../apps/desktop/src/lib/treeNodeClick.ts";
|
||||
|
||||
test("table and view rows open data without toggling structure groups", () => {
|
||||
assert.equal(treeNodeRowAction("table", true), "open-data");
|
||||
|
|
@ -43,6 +43,14 @@ test("leaf data browser nodes keep their open behavior through toggle handler",
|
|||
assert.equal(treeNodeRowAction("mongo-collection", false), "toggle");
|
||||
});
|
||||
|
||||
test("repeated clicks continue to toggle expandable rows", () => {
|
||||
assert.equal(shouldRunTreeNodeRowAction("toggle", 1), true);
|
||||
assert.equal(shouldRunTreeNodeRowAction("toggle", 2), true);
|
||||
assert.equal(shouldRunTreeNodeRowAction("toggle", 3), true);
|
||||
assert.equal(shouldRunTreeNodeRowAction("open-data", 2), false);
|
||||
assert.equal(shouldRunTreeNodeRowAction("none", 1), false);
|
||||
});
|
||||
|
||||
test("plain metadata leaf rows do nothing on row clicks", () => {
|
||||
assert.equal(treeNodeRowAction("column", false), "none");
|
||||
assert.equal(treeNodeRowAction("index", false), "none");
|
||||
|
|
|
|||
|
|
@ -36,6 +36,21 @@ test("flattenTree preserves depth and node type for virtualized sidebar rows", (
|
|||
);
|
||||
});
|
||||
|
||||
test("connection groups use per-node pool types to avoid recycled row state", () => {
|
||||
const nodes: TreeNode[] = [
|
||||
{ id: "g1", label: "Group 1", type: "connection-group", isExpanded: false },
|
||||
{ id: "g2", label: "Group 2", type: "connection-group", isExpanded: false },
|
||||
{ id: "c1", label: "Connection", type: "connection", isExpanded: false },
|
||||
];
|
||||
|
||||
const flat = flattenTree(nodes);
|
||||
|
||||
assert.equal(flat[0].type, "connection-group");
|
||||
assert.equal(flat[1].type, "connection-group");
|
||||
assert.notEqual(flat[0].poolType, flat[1].poolType);
|
||||
assert.equal(flat[2].poolType, "connection");
|
||||
});
|
||||
|
||||
test("shouldVirtualizeFlatTree virtualizes every non-empty sidebar tree", () => {
|
||||
assert.equal(shouldVirtualizeFlatTree(0), false);
|
||||
assert.equal(shouldVirtualizeFlatTree(1), true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue