From 67e6b3f32d40fd07ad4f7d3826f4ce22b24a427e Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Thu, 6 Aug 2026 01:27:16 +0800 Subject: [PATCH] Revert "feat(sidebar): expose visible object filter" This reverts commit 580b70e1d4bbb0b652bef452585af5bcaeb4d08e. --- .../sidebar/SidebarTreeRuntimeHost.vue | 6 - .../sidebar/SidebarVisibleFilterControl.vue | 57 --------- .../src/components/sidebar/TreeItem.vue | 2 - .../sidebar/VisibleDatabasesDialog.vue | 1 - .../SidebarVisibleFilterControl.spec.ts | 95 -------------- .../TreeItem.loadMoreActivation.spec.ts | 1 - .../useSidebarConnectionMutationRuntime.ts | 3 +- apps/desktop/src/i18n/locales/en.ts | 2 - apps/desktop/src/i18n/locales/es.ts | 2 - apps/desktop/src/i18n/locales/it.ts | 2 - apps/desktop/src/i18n/locales/ja.ts | 2 - apps/desktop/src/i18n/locales/ko.ts | 2 - apps/desktop/src/i18n/locales/pt-BR.ts | 2 - apps/desktop/src/i18n/locales/zh-CN.ts | 2 - apps/desktop/src/i18n/locales/zh-TW.ts | 2 - .../sidebar/sidebarTreeRuntime.spec.ts | 12 -- .../connection/connectionVisibleDatabases.ts | 6 +- .../src/lib/sidebar/sidebarTreeRuntime.ts | 5 - .../lib/sidebar/sidebarVisibleFilterMenu.ts | 13 -- .../sidebar/sidebarVisibleFilterSummary.ts | 33 ----- ...ectionStore.duckdbVisibleDatabases.spec.ts | 121 ------------------ apps/desktop/src/stores/connectionStore.ts | 45 +------ .../connectionVisibleDatabases.test.ts | 5 - .../sidebarRuntimeDecomposition.test.ts | 10 -- .../sidebarVisibleFilterMenu.test.ts | 16 +-- .../sidebarVisibleFilterSummary.test.ts | 92 ------------- 26 files changed, 7 insertions(+), 532 deletions(-) delete mode 100644 apps/desktop/src/components/sidebar/SidebarVisibleFilterControl.vue delete mode 100644 apps/desktop/src/components/sidebar/__tests__/SidebarVisibleFilterControl.spec.ts delete mode 100644 apps/desktop/src/lib/sidebar/sidebarVisibleFilterSummary.ts delete mode 100644 apps/desktop/src/stores/__tests__/connectionStore.duckdbVisibleDatabases.spec.ts delete mode 100644 packages/app-tests/sidebarVisibleFilterSummary.test.ts diff --git a/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue b/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue index 8007e7f4e..39ccf1d6e 100644 --- a/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue +++ b/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue @@ -4802,11 +4802,6 @@ function handleRowKeydown(node: TreeNode, event: KeyboardEvent) { onKeydown(event); } -function openPrimaryVisibleFilter(node: TreeNode) { - activateRuntimeNode(node); - openVisibleDatabasesDialog(); -} - function openDataInNewTab(node: TreeNode) { activateRuntimeNode(node); openDataInNewTabImmediately(node); @@ -4827,7 +4822,6 @@ defineExpose({ handleRowClick, handleRowDoubleClick, handleRowKeydown, - openPrimaryVisibleFilter, openDataInNewTab, requestPaste, toggleNode, diff --git a/apps/desktop/src/components/sidebar/SidebarVisibleFilterControl.vue b/apps/desktop/src/components/sidebar/SidebarVisibleFilterControl.vue deleted file mode 100644 index 1b5de5423..000000000 --- a/apps/desktop/src/components/sidebar/SidebarVisibleFilterControl.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - diff --git a/apps/desktop/src/components/sidebar/TreeItem.vue b/apps/desktop/src/components/sidebar/TreeItem.vue index a87c427dd..f06481af0 100644 --- a/apps/desktop/src/components/sidebar/TreeItem.vue +++ b/apps/desktop/src/components/sidebar/TreeItem.vue @@ -70,7 +70,6 @@ import { useDragSort } from "@/composables/useDragSort"; import { sidebarTreeRuntimeKey } from "@/lib/sidebar/sidebarTreeRuntime"; import { treeNodePinKey } from "@/lib/app/pinnedItems"; import { isTreeGroupNodeType } from "@/lib/sidebar/treeNodeGroup"; -import SidebarVisibleFilterControl from "./SidebarVisibleFilterControl.vue"; const { t } = useI18n(); @@ -1197,7 +1196,6 @@ function onKeydown(event: KeyboardEvent) { >{{ trailingComment }} - {{ t("connection.readOnlyBadge") }} diff --git a/apps/desktop/src/components/sidebar/VisibleDatabasesDialog.vue b/apps/desktop/src/components/sidebar/VisibleDatabasesDialog.vue index 79f82aeb6..4f1cf403a 100644 --- a/apps/desktop/src/components/sidebar/VisibleDatabasesDialog.vue +++ b/apps/desktop/src/components/sidebar/VisibleDatabasesDialog.vue @@ -84,7 +84,6 @@ async function loadDatabases() { searchText.value = ""; try { const names = await loadObjectNames(); - connectionStore.recordPrimaryVisibleObjectNames(props.connectionId, names); objectNames.value = names; showSystemDatabases.value = false; const configured = isSchemaFilterMode.value ? connection.value?.visible_schemas?.[databaseKey.value] : connection.value?.visible_databases; diff --git a/apps/desktop/src/components/sidebar/__tests__/SidebarVisibleFilterControl.spec.ts b/apps/desktop/src/components/sidebar/__tests__/SidebarVisibleFilterControl.spec.ts deleted file mode 100644 index 8a7a31adb..000000000 --- a/apps/desktop/src/components/sidebar/__tests__/SidebarVisibleFilterControl.spec.ts +++ /dev/null @@ -1,95 +0,0 @@ -// @vitest-environment happy-dom - -import { createApp, defineComponent, h, nextTick, type App } from "vue"; -import { afterEach, describe, expect, it, vi } from "vitest"; -import i18n from "@/i18n"; -import SidebarVisibleFilterControl from "@/components/sidebar/SidebarVisibleFilterControl.vue"; -import { createSidebarTreeRuntime, sidebarTreeRuntimeKey, type SidebarTreeRuntimeHost } from "@/lib/sidebar/sidebarTreeRuntime"; -import type { SidebarVisibleFilterSummary } from "@/lib/sidebar/sidebarVisibleFilterSummary"; -import type { ConnectionConfig, TreeNode } from "@/types/database"; - -const state: { - config: Pick; - summary: SidebarVisibleFilterSummary; -} = { - config: { db_type: "mysql", name: "MySQL" }, - summary: { mode: "database", isExplicit: true, selected: 1, total: 6 }, -}; - -vi.mock("@/stores/connectionStore", () => ({ - useConnectionStore: () => ({ - getConfig: () => state.config, - getSidebarVisibleFilterSummary: () => state.summary, - }), -})); - -const mountedApps: App[] = []; - -function runtimeHost(): SidebarTreeRuntimeHost { - return { - buildContextMenu: vi.fn(() => []), - handleRowClick: vi.fn(), - handleRowDoubleClick: vi.fn(), - handleRowKeydown: vi.fn(), - openPrimaryVisibleFilter: vi.fn(), - openDataInNewTab: vi.fn(), - requestPaste: vi.fn(() => false), - toggleNode: vi.fn(), - }; -} - -async function mountControl() { - const node: TreeNode = { id: "connection-1", label: "MySQL", type: "connection", connectionId: "connection-1" }; - const container = document.createElement("div"); - document.body.append(container); - const runtime = createSidebarTreeRuntime(); - const host = runtimeHost(); - runtime.bindHost(host); - const app = createApp( - defineComponent({ - setup: () => () => h(SidebarVisibleFilterControl, { node }), - }), - ); - mountedApps.push(app); - app.use(i18n); - app.provide(sidebarTreeRuntimeKey, runtime); - app.mount(container); - await nextTick(); - return { container, host, node }; -} - -afterEach(() => { - for (const app of mountedApps.splice(0)) app.unmount(); - document.body.innerHTML = ""; - state.config = { db_type: "mysql", name: "MySQL" }; - state.summary = { mode: "database", isExplicit: true, selected: 1, total: 6 }; -}); - -describe("SidebarVisibleFilterControl", () => { - it("shows the selected/total count and opens the existing primary filter route", async () => { - const { container, host, node } = await mountControl(); - const button = container.querySelector("[data-sidebar-visible-filter]"); - - expect(button?.textContent).toBe("1/6"); - expect(button?.getAttribute("aria-label")).toContain("MySQL"); - button?.click(); - expect(host.openPrimaryVisibleFilter).toHaveBeenCalledWith(node); - }); - - it("keeps an accessible filter control before counts are available", async () => { - state.summary = { mode: "database", isExplicit: false, selected: null, total: null }; - const { container } = await mountControl(); - const button = container.querySelector("[data-sidebar-visible-filter]"); - - expect(button).not.toBeNull(); - expect(button?.textContent).toBe(""); - expect(button?.getAttribute("aria-label")).toContain("MySQL"); - }); - - it("does not render for unsupported connection types", async () => { - state.config = { db_type: "elasticsearch", name: "Search" }; - const { container } = await mountControl(); - - expect(container.querySelector("[data-sidebar-visible-filter]")).toBeNull(); - }); -}); diff --git a/apps/desktop/src/components/sidebar/__tests__/TreeItem.loadMoreActivation.spec.ts b/apps/desktop/src/components/sidebar/__tests__/TreeItem.loadMoreActivation.spec.ts index 9910e0137..a524f9f5d 100644 --- a/apps/desktop/src/components/sidebar/__tests__/TreeItem.loadMoreActivation.spec.ts +++ b/apps/desktop/src/components/sidebar/__tests__/TreeItem.loadMoreActivation.spec.ts @@ -61,7 +61,6 @@ function runtimeHost(): SidebarTreeRuntimeHost { handleRowClick: vi.fn(), handleRowDoubleClick: vi.fn(), handleRowKeydown: vi.fn(), - openPrimaryVisibleFilter: vi.fn(), openDataInNewTab: vi.fn(), requestPaste: vi.fn(() => false), toggleNode: vi.fn(), diff --git a/apps/desktop/src/composables/useSidebarConnectionMutationRuntime.ts b/apps/desktop/src/composables/useSidebarConnectionMutationRuntime.ts index bac37b95b..f233c70a4 100644 --- a/apps/desktop/src/composables/useSidebarConnectionMutationRuntime.ts +++ b/apps/desktop/src/composables/useSidebarConnectionMutationRuntime.ts @@ -16,7 +16,6 @@ import { canConfigureVisibleSchemasForTreeNode } from "@/lib/database/databaseFe import { canCloseSidebarDatabaseConnection } from "@/lib/sidebar/sidebarDatabaseOpenState"; import { selectedConnectionDeleteTargets, selectedConnectionDuplicateTargets } from "@/lib/sidebar/sidebarConnectionSelection"; import { connectionDeleteTargetSnapshot, showDeleteConfirm, showDeleteGroupConfirm, sidebarFormTarget } from "@/components/sidebar/sidebarTreeDialogState"; -import { connectionCanConfigureSidebarVisibleDatabases } from "@/lib/sidebar/sidebarVisibleFilterMenu"; interface SidebarConnectionMutationRuntimeOptions { activeNode: ShallowRef; @@ -235,7 +234,7 @@ export function useSidebarConnectionMutationRuntime(options: SidebarConnectionMu const canConfigureVisibleDatabases = computed(() => { if (activeNode.value.type !== "connection" || !activeNode.value.connectionId) return false; const databaseType = connectionStore.getConfig(activeNode.value.connectionId)?.db_type; - return connectionCanConfigureSidebarVisibleDatabases(databaseType); + return databaseType !== "elasticsearch" && databaseType !== "easysearch" && databaseType !== "qdrant" && databaseType !== "milvus" && databaseType !== "weaviate" && databaseType !== "chromadb" && databaseType !== "etcd" && databaseType !== "mq" && databaseType !== "nacos"; }); const canConfigureVisibleSchemas = computed(() => { if (!activeNode.value.connectionId) return false; diff --git a/apps/desktop/src/i18n/locales/en.ts b/apps/desktop/src/i18n/locales/en.ts index 3115eaf15..c5ebc6f7e 100644 --- a/apps/desktop/src/i18n/locales/en.ts +++ b/apps/desktop/src/i18n/locales/en.ts @@ -2435,7 +2435,6 @@ export default { }, visibleDatabases: { title: "Visible Databases", - sidebarControlLabel: 'Configure visible databases for "{connection}"{count}', description: 'Choose which databases are shown under "{connection}".', searchPlaceholder: "Search databases...", selectedCount: "{selected}/{total} selected", @@ -2450,7 +2449,6 @@ export default { }, visibleSchemas: { title: "Schema Filter", - sidebarControlLabel: 'Configure visible schemas for "{connection}"{count}', description: 'Choose which schemas are shown under "{connection}".', searchPlaceholder: "Search schemas...", selectedCount: "{selected}/{total} selected", diff --git a/apps/desktop/src/i18n/locales/es.ts b/apps/desktop/src/i18n/locales/es.ts index 6cb38c8cb..6564cd1ae 100644 --- a/apps/desktop/src/i18n/locales/es.ts +++ b/apps/desktop/src/i18n/locales/es.ts @@ -2377,7 +2377,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "Bases de datos visibles", - sidebarControlLabel: 'Configurar bases de datos visibles para "{connection}"{count}', description: 'Elige qué bases de datos se muestran bajo "{connection}".', searchPlaceholder: "Buscar bases de datos...", selectedCount: "{selected}/{total} seleccionadas", @@ -2392,7 +2391,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "Filtro de Schema", - sidebarControlLabel: 'Configurar schemas visibles para "{connection}"{count}', description: 'Elige qué schemas se muestran bajo "{connection}".', searchPlaceholder: "Buscar schemas...", selectedCount: "{selected}/{total} seleccionados", diff --git a/apps/desktop/src/i18n/locales/it.ts b/apps/desktop/src/i18n/locales/it.ts index 010429615..24b1c11dd 100644 --- a/apps/desktop/src/i18n/locales/it.ts +++ b/apps/desktop/src/i18n/locales/it.ts @@ -2375,7 +2375,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "Database Visibili", - sidebarControlLabel: 'Configura i database visibili per "{connection}"{count}', description: 'Scegli quali database mostrare sotto "{connection}".', searchPlaceholder: "Cerca database...", selectedCount: "{selected}/{total} selezionati", @@ -2390,7 +2389,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "Filtro Schema", - sidebarControlLabel: 'Configura gli schema visibili per "{connection}"{count}', description: 'Scegli quali schema mostrare sotto "{connection}".', searchPlaceholder: "Cerca schema...", selectedCount: "{selected}/{total} selezionati", diff --git a/apps/desktop/src/i18n/locales/ja.ts b/apps/desktop/src/i18n/locales/ja.ts index 0577dcad5..215036192 100644 --- a/apps/desktop/src/i18n/locales/ja.ts +++ b/apps/desktop/src/i18n/locales/ja.ts @@ -2402,7 +2402,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "表示するデータベース", - sidebarControlLabel: "「{connection}」の表示データベースを設定{count}", description: "「{connection}」の下に表示するデータベースを選択してください。", searchPlaceholder: "データベースを検索...", selectedCount: "{selected}/{total}件選択中", @@ -2417,7 +2416,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "スキーマフィルター", - sidebarControlLabel: "「{connection}」の表示スキーマを設定{count}", description: "「{connection}」の下に表示するスキーマを選択してください。", searchPlaceholder: "スキーマを検索...", selectedCount: "{selected}/{total}件選択中", diff --git a/apps/desktop/src/i18n/locales/ko.ts b/apps/desktop/src/i18n/locales/ko.ts index bd8485b96..95f88f6e9 100644 --- a/apps/desktop/src/i18n/locales/ko.ts +++ b/apps/desktop/src/i18n/locales/ko.ts @@ -2317,7 +2317,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "표시할 데이터베이스", - sidebarControlLabel: '"{connection}"의 표시할 데이터베이스 구성{count}', description: '"{connection}" 아래에 표시할 데이터베이스를 선택하세요.', searchPlaceholder: "데이터베이스 검색...", selectedCount: "{selected}/{total} 선택됨", @@ -2332,7 +2331,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "스키마 필터", - sidebarControlLabel: '"{connection}"의 표시할 스키마 구성{count}', description: '"{connection}" 아래에 표시할 스키마를 선택하세요.', searchPlaceholder: "스키마 검색...", selectedCount: "{selected}/{total} 선택됨", diff --git a/apps/desktop/src/i18n/locales/pt-BR.ts b/apps/desktop/src/i18n/locales/pt-BR.ts index f382e769a..7e27efbc3 100644 --- a/apps/desktop/src/i18n/locales/pt-BR.ts +++ b/apps/desktop/src/i18n/locales/pt-BR.ts @@ -2377,7 +2377,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "Bancos de dados visíveis", - sidebarControlLabel: 'Configurar bancos de dados visíveis para "{connection}"{count}', description: 'Escolha quais bancos de dados são exibidos em "{connection}".', searchPlaceholder: "Pesquisar bancos de dados...", selectedCount: "{selected}/{total} selecionados", @@ -2392,7 +2391,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "Filtro de Schema", - sidebarControlLabel: 'Configurar schemas visíveis para "{connection}"{count}', description: 'Escolha quais schemas são exibidos em "{connection}".', searchPlaceholder: "Pesquisar schemas...", selectedCount: "{selected}/{total} selecionados", diff --git a/apps/desktop/src/i18n/locales/zh-CN.ts b/apps/desktop/src/i18n/locales/zh-CN.ts index 6b7ceddad..4d5435668 100644 --- a/apps/desktop/src/i18n/locales/zh-CN.ts +++ b/apps/desktop/src/i18n/locales/zh-CN.ts @@ -2436,7 +2436,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "显示数据库", - sidebarControlLabel: "配置「{connection}」的可见数据库{count}", description: "选择「{connection}」下要在侧边栏显示的数据库。", searchPlaceholder: "搜索数据库...", selectedCount: "已选择 {selected}/{total}", @@ -2451,7 +2450,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "Schema 过滤器", - sidebarControlLabel: "配置「{connection}」的可见 Schema{count}", description: "选择「{connection}」下要在侧边栏显示的 Schema。", searchPlaceholder: "搜索 Schema...", selectedCount: "已选择 {selected}/{total}", diff --git a/apps/desktop/src/i18n/locales/zh-TW.ts b/apps/desktop/src/i18n/locales/zh-TW.ts index 5af3103ec..2dfce18ae 100644 --- a/apps/desktop/src/i18n/locales/zh-TW.ts +++ b/apps/desktop/src/i18n/locales/zh-TW.ts @@ -2376,7 +2376,6 @@ export default withEnglishFallback({ }, visibleDatabases: { title: "顯示資料庫", - sidebarControlLabel: "設定「{connection}」的可見資料庫{count}", description: "選擇「{connection}」下要在側邊欄顯示的資料庫。", searchPlaceholder: "搜尋資料庫……", selectedCount: "已選擇 {selected}/{total}", @@ -2391,7 +2390,6 @@ export default withEnglishFallback({ }, visibleSchemas: { title: "Schema 過濾器", - sidebarControlLabel: "設定「{connection}」的可見 Schema{count}", description: "選擇「{connection}」下要在側邊欄顯示的 Schema。", searchPlaceholder: "搜尋 Schema……", selectedCount: "已選擇 {selected}/{total}", diff --git a/apps/desktop/src/lib/__tests__/sidebar/sidebarTreeRuntime.spec.ts b/apps/desktop/src/lib/__tests__/sidebar/sidebarTreeRuntime.spec.ts index 5c175abf1..573e4305b 100644 --- a/apps/desktop/src/lib/__tests__/sidebar/sidebarTreeRuntime.spec.ts +++ b/apps/desktop/src/lib/__tests__/sidebar/sidebarTreeRuntime.spec.ts @@ -12,7 +12,6 @@ function host(): SidebarTreeRuntimeHost { handleRowClick: vi.fn(), handleRowDoubleClick: vi.fn(), handleRowKeydown: vi.fn(), - openPrimaryVisibleFilter: vi.fn(), openDataInNewTab: vi.fn(), requestPaste: vi.fn(() => false), toggleNode: vi.fn(), @@ -47,17 +46,6 @@ describe("sidebar tree runtime", () => { expect(runtimeHost.handleRowClick).toHaveBeenCalledTimes(100); }); - it("forwards the direct primary visible-filter action to the bound host", () => { - const runtime = createSidebarTreeRuntime(); - const runtimeHost = host(); - const connection = { id: "connection-1", label: "Connection", type: "connection", connectionId: "connection-1" } satisfies TreeNode; - runtime.bindHost(runtimeHost); - - runtime.openPrimaryVisibleFilter(connection); - - expect(runtimeHost.openPrimaryVisibleFilter).toHaveBeenCalledWith(connection); - }); - it("rejects superseded and disposed generations without affecting another runtime", () => { const runtime = createSidebarTreeRuntime(); const otherRuntime = createSidebarTreeRuntime(); diff --git a/apps/desktop/src/lib/connection/connectionVisibleDatabases.ts b/apps/desktop/src/lib/connection/connectionVisibleDatabases.ts index a1dcabc89..f35185953 100644 --- a/apps/desktop/src/lib/connection/connectionVisibleDatabases.ts +++ b/apps/desktop/src/lib/connection/connectionVisibleDatabases.ts @@ -3,9 +3,9 @@ import { filterDatabaseNamesForVisiblePicker, normalizeVisibleDatabaseSelection const DRAFT_VISIBLE_DATABASES_PREFIX = "__visible_draft_"; -// Turso and Cloudflare D1 target one fixed SQLite-compatible `main` namespace; -// non-database services expose their own root objects rather than database namespaces. -const UNSUPPORTED_VISIBLE_DATABASE_TYPES = new Set(["turso", "cloudflare-d1", "elasticsearch", "easysearch", "qdrant", "milvus", "weaviate", "chromadb", "etcd", "zookeeper", "mq", "nacos"]); +// Turso and Cloudflare D1 connections target one fixed SQLite-compatible `main` namespace; +// listing account-level databases requires separate platform credentials, not the database connection. +const UNSUPPORTED_VISIBLE_DATABASE_TYPES = new Set(["turso", "cloudflare-d1", "elasticsearch", "easysearch", "qdrant", "milvus", "weaviate", "chromadb", "etcd", "zookeeper"]); type VisibleDatabaseConnectionFields = Pick< ConnectionConfig, diff --git a/apps/desktop/src/lib/sidebar/sidebarTreeRuntime.ts b/apps/desktop/src/lib/sidebar/sidebarTreeRuntime.ts index 70c0ae57a..833abe5c2 100644 --- a/apps/desktop/src/lib/sidebar/sidebarTreeRuntime.ts +++ b/apps/desktop/src/lib/sidebar/sidebarTreeRuntime.ts @@ -18,7 +18,6 @@ export interface SidebarTreeRuntimeHost { handleRowClick(node: TreeNode, clickDetail: number): void; handleRowDoubleClick(node: TreeNode, event: MouseEvent): void; handleRowKeydown(node: TreeNode, event: KeyboardEvent): void; - openPrimaryVisibleFilter(node: TreeNode): void; openDataInNewTab(node: TreeNode): void; requestPaste(node: TreeNode): boolean; toggleNode(node: TreeNode): void; @@ -39,7 +38,6 @@ export interface SidebarTreeRuntime { handleRowClick(node: TreeNode, clickDetail: number): void; handleRowDoubleClick(node: TreeNode, event: MouseEvent): void; handleRowKeydown(node: TreeNode, event: KeyboardEvent): void; - openPrimaryVisibleFilter(node: TreeNode): void; openDataInNewTab(node: TreeNode): void; requestPaste(node: TreeNode): boolean; toggleNode(node: TreeNode): void; @@ -99,9 +97,6 @@ export function createSidebarTreeRuntime(): SidebarTreeRuntime { handleRowKeydown(node, event) { currentHost()?.handleRowKeydown(node, event); }, - openPrimaryVisibleFilter(node) { - currentHost()?.openPrimaryVisibleFilter(node); - }, openDataInNewTab(node) { currentHost()?.openDataInNewTab(node); }, diff --git a/apps/desktop/src/lib/sidebar/sidebarVisibleFilterMenu.ts b/apps/desktop/src/lib/sidebar/sidebarVisibleFilterMenu.ts index 262481706..49eb26b11 100644 --- a/apps/desktop/src/lib/sidebar/sidebarVisibleFilterMenu.ts +++ b/apps/desktop/src/lib/sidebar/sidebarVisibleFilterMenu.ts @@ -1,21 +1,8 @@ -import type { DatabaseType } from "@/types/database"; -import { connectionCanChooseVisibleDatabases } from "@/lib/connection/connectionVisibleDatabases"; - -const CATALOG_SCOPED_VISIBLE_DATABASE_TYPES = new Set(["doris", "starrocks"]); - export type SidebarVisibleFilterMenuEntry = { label: "objects" | "schemas"; target: "visible-databases" | "visible-schemas"; }; -export function connectionCanConfigureSidebarVisibleDatabases(databaseType: DatabaseType | undefined): boolean { - // Doris and StarRocks can expose the same database name in multiple catalogs, - // while `visible_databases` is still a flat name list. Keep the sidebar entry - // unavailable until the persisted selection can preserve catalog identity. - if (databaseType && CATALOG_SCOPED_VISIBLE_DATABASE_TYPES.has(databaseType)) return false; - return connectionCanChooseVisibleDatabases(databaseType ? { db_type: databaseType } : undefined); -} - export function sidebarConnectionVisibleFilterMenu(options: { canConfigureVisibleDatabases: boolean; canConfigureVisibleSchemas: boolean; databaseFilterUsesSchemas: boolean }): SidebarVisibleFilterMenuEntry[] { if (!options.canConfigureVisibleDatabases) { return options.canConfigureVisibleSchemas ? [{ label: "schemas", target: "visible-schemas" }] : []; diff --git a/apps/desktop/src/lib/sidebar/sidebarVisibleFilterSummary.ts b/apps/desktop/src/lib/sidebar/sidebarVisibleFilterSummary.ts deleted file mode 100644 index 6da557a0f..000000000 --- a/apps/desktop/src/lib/sidebar/sidebarVisibleFilterSummary.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { ConnectionConfig } from "@/types/database"; -import { connectionUsesVisibleSchemaFilter, filterDatabaseNamesForVisiblePicker, filterSchemaNamesForVisiblePicker, normalizeVisibleDatabaseSelection } from "@/lib/database/visibleDatabases"; - -type SidebarVisibleFilterConnection = Pick; - -export type SidebarVisibleFilterSummary = { - mode: "database" | "schema"; - isExplicit: boolean; - selected: number | null; - total: number | null; -}; - -export function sidebarVisibleFilterSummary(connection: SidebarVisibleFilterConnection, objectNames?: readonly string[]): SidebarVisibleFilterSummary { - const mode = connectionUsesVisibleSchemaFilter(connection) ? "schema" : "database"; - const configured = mode === "schema" ? connection.visible_schemas?.[connection.database || ""] : connection.visible_databases; - if (!objectNames) return { mode, isExplicit: Array.isArray(configured), selected: null, total: null }; - - const names = [...objectNames]; - const defaultNames = mode === "schema" ? filterSchemaNamesForVisiblePicker(names, connection) : filterDatabaseNamesForVisiblePicker(names, connection); - if (!Array.isArray(configured)) { - return { mode, isExplicit: false, selected: defaultNames.length, total: defaultNames.length }; - } - - const selectedNames = normalizeVisibleDatabaseSelection(configured, names); - const defaultNameSet = new Set(defaultNames); - const includesSystemObject = selectedNames.some((name) => !defaultNameSet.has(name)); - return { - mode, - isExplicit: true, - selected: selectedNames.length, - total: includesSystemObject ? names.length : defaultNames.length, - }; -} diff --git a/apps/desktop/src/stores/__tests__/connectionStore.duckdbVisibleDatabases.spec.ts b/apps/desktop/src/stores/__tests__/connectionStore.duckdbVisibleDatabases.spec.ts deleted file mode 100644 index c84de298c..000000000 --- a/apps/desktop/src/stores/__tests__/connectionStore.duckdbVisibleDatabases.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { createPinia, setActivePinia } from "pinia"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import type { ConnectionConfig, TreeNode } from "@/types/database"; - -function installLocalStorage() { - const data = new Map(); - vi.stubGlobal("localStorage", { - getItem: vi.fn((key: string) => data.get(key) ?? null), - setItem: vi.fn((key: string, value: string) => data.set(key, value)), - removeItem: vi.fn((key: string) => data.delete(key)), - }); -} - -function duckDbConnection(visibleDatabases?: string[]): ConnectionConfig { - return { - id: "duckdb-1", - name: "DuckDB", - db_type: "duckdb", - host: "", - port: 0, - username: "", - password: "", - database: "main", - visible_databases: visibleDatabases, - } as ConnectionConfig; -} - -function connectionNode(connection: ConnectionConfig): TreeNode { - return { - id: connection.id, - label: connection.name, - type: "connection", - connectionId: connection.id, - isExpanded: false, - children: [], - }; -} - -function rootEntries(node: TreeNode | undefined) { - return (node?.children ?? []).map((child) => ({ - type: child.type, - database: child.database, - schema: child.schema, - label: child.label, - })); -} - -async function setupStore(visibleDatabases?: string[]) { - const listDatabases = vi.fn().mockResolvedValue([{ name: "main" }, { name: "analytics" }, { name: "warehouse" }]); - const listSchemas = vi.fn().mockResolvedValue(["main", "reporting"]); - const saveConnections = vi.fn().mockResolvedValue(undefined); - vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false })); - vi.doMock("@/lib/backend/api", () => ({ - checkConnectionHealth: vi.fn().mockResolvedValue(undefined), - deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined), - listDatabases, - listSchemas, - loadSchemaCache: vi.fn().mockResolvedValue(null), - saveConnections, - saveSchemaCache: vi.fn().mockResolvedValue(undefined), - saveSidebarLayout: vi.fn().mockResolvedValue(undefined), - })); - - const { useConnectionStore } = await import("@/stores/connectionStore"); - const store = useConnectionStore(); - const connection = duckDbConnection(visibleDatabases); - store.connections = [connection]; - store.connectedIds.add(connection.id); - store.sidebarLayout = { groups: [], order: [{ type: "connection", id: connection.id }] }; - store.treeNodes = [connectionNode(connection)]; - return { store, connection, saveConnections }; -} - -describe("connectionStore DuckDB visible databases", () => { - beforeEach(() => { - vi.resetModules(); - vi.unstubAllGlobals(); - installLocalStorage(); - setActivePinia(createPinia()); - }); - - it("keeps main schemas and hides attached databases when only main is visible", async () => { - const { store, connection } = await setupStore(); - - await store.loadDatabases(connection.id, { force: true }); - await store.setVisibleDatabases(connection.id, ["main"]); - - expect(rootEntries(store.treeNodes[0])).toEqual([ - { type: "schema", database: "main", schema: "main", label: "main" }, - { type: "schema", database: "main", schema: "reporting", label: "reporting" }, - ]); - expect(store.getSidebarVisibleFilterSummary(connection.id)).toEqual({ mode: "database", isExplicit: true, selected: 1, total: 3 }); - }); - - it("hides main schemas and unselected attached databases", async () => { - const { store, connection } = await setupStore(); - - await store.loadDatabases(connection.id, { force: true }); - await store.setVisibleDatabases(connection.id, ["warehouse"]); - - expect(rootEntries(store.treeNodes[0])).toEqual([{ type: "database", database: "warehouse", schema: undefined, label: "warehouse" }]); - expect(store.getSidebarVisibleFilterSummary(connection.id)).toEqual({ mode: "database", isExplicit: true, selected: 1, total: 3 }); - }); - - it("restores main schemas and every attached database after clearing the filter", async () => { - const { store, connection, saveConnections } = await setupStore(); - await store.loadDatabases(connection.id, { force: true }); - await store.setVisibleDatabases(connection.id, ["warehouse"]); - - await store.clearVisibleDatabases(connection.id); - - expect(rootEntries(store.treeNodes[0])).toEqual([ - { type: "schema", database: "main", schema: "main", label: "main" }, - { type: "schema", database: "main", schema: "reporting", label: "reporting" }, - { type: "database", database: "analytics", schema: undefined, label: "analytics" }, - { type: "database", database: "warehouse", schema: undefined, label: "warehouse" }, - ]); - expect(store.getSidebarVisibleFilterSummary(connection.id)).toEqual({ mode: "database", isExplicit: false, selected: 3, total: 3 }); - expect(saveConnections).toHaveBeenLastCalledWith([expect.objectContaining({ id: connection.id, visible_databases: undefined })]); - }); -}); diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts index ef29ef736..0fc5e6ba4 100644 --- a/apps/desktop/src/stores/connectionStore.ts +++ b/apps/desktop/src/stores/connectionStore.ts @@ -122,7 +122,6 @@ import i18n from "@/i18n"; import type { MqAdminConfig } from "@/types/mq"; import { RABBITMQ_MQ_TENANT, resolveMqSystemKindFromConnection } from "@/lib/mq/mqConsoleDefaults"; import { applySidebarDatabaseStorage, applySidebarTableStorage, sidebarDatabaseNames, supportsSidebarDatabaseStorage, supportsSidebarTableStorage, type SidebarTableStorageScope } from "@/lib/sidebar/sidebarDatabaseStorage"; -import { sidebarVisibleFilterSummary } from "@/lib/sidebar/sidebarVisibleFilterSummary"; const PINNED_TREE_NODES_STORAGE_KEY = "dbx-pinned-tree-nodes"; const ACTIVE_CONNECTION_STORAGE_KEY = "dbx-active-connection"; @@ -344,7 +343,6 @@ export const useConnectionStore = defineStore("connection", () => { const completionColumnsCache = ref>({}); const completionForeignKeysCache = ref>({}); const completionDatabasesCache = ref>({}); - const primaryVisibleObjectNames = ref>({}); const sqlServerCompletionContextCache = ref>({}); const elasticsearchCompletionIndicesCache = ref>({}); const redisCompletionKeysCache = ref>({}); @@ -2377,7 +2375,6 @@ export const useConnectionStore = defineStore("connection", () => { clearConnectionError(id); connectionErrorRevisions.delete(id); connectedIds.value.delete(id); - clearPrimaryVisibleObjectNames(id); clearConnectionIdentifierQuote(id); clearConnectionHealthCheck(id); sidebarLayout.value = removeConnectionFromSidebarLayout(sidebarLayout.value, id); @@ -2413,7 +2410,6 @@ export const useConnectionStore = defineStore("connection", () => { connections.value = nextConnections; rebuildTreeNodes(); if (!runtimeConfigChanged) return; - clearPrimaryVisibleObjectNames(config.id); connectedIds.value.delete(config.id); clearConnectionIdentifierQuote(config.id); clearConnectionHealthCheck(config.id); @@ -2559,25 +2555,6 @@ export const useConnectionStore = defineStore("connection", () => { await reloadConnectionDatabaseChildren(connectionId); } - function recordPrimaryVisibleObjectNames(connectionId: string, objectNames: readonly string[]) { - const names = [...objectNames]; - const existing = primaryVisibleObjectNames.value[connectionId]; - if (existing?.length === names.length && existing.every((name, index) => name === names[index])) return; - primaryVisibleObjectNames.value = { ...primaryVisibleObjectNames.value, [connectionId]: names }; - } - - function clearPrimaryVisibleObjectNames(connectionId: string) { - if (!(connectionId in primaryVisibleObjectNames.value)) return; - const next = { ...primaryVisibleObjectNames.value }; - delete next[connectionId]; - primaryVisibleObjectNames.value = next; - } - - function getSidebarVisibleFilterSummary(connectionId: string) { - const config = getConfig(connectionId); - return config ? sidebarVisibleFilterSummary(config, primaryVisibleObjectNames.value[connectionId]) : null; - } - async function clearVisibleDatabases(connectionId: string) { const config = getConfig(connectionId); if (!config || !Array.isArray(config.visible_databases)) return; @@ -3060,16 +3037,10 @@ export const useConnectionStore = defineStore("connection", () => { } } const [databases, schemas] = await Promise.all([withMetadataLoadTimeout(connectionId, api.listDatabases(connectionId), "databases"), withMetadataLoadTimeout(connectionId, api.listSchemas(connectionId, "main"), "schemas")]); - const databaseNames = databases.map((database) => database.name); - const visibleNames = filterDatabaseNamesForConnection(databaseNames, config); - const visibleNameSet = new Set(visibleNames); - const visibleDatabases = databases.filter((database) => visibleNameSet.has(database.name)); - const visibleSchemas = visibleNameSet.has("main") ? schemas : []; - const children = withSavedSqlRoot(connectionId, buildDuckDbConnectionTreeNodes(connectionId, visibleDatabases, visibleSchemas), node); + const children = withSavedSqlRoot(connectionId, buildDuckDbConnectionTreeNodes(connectionId, databases, schemas), node); if (isSidebarSearchQueryChanged(options)) return; const targetNode = treeNodeLoadTarget(load); if (!targetNode) return; - recordPrimaryVisibleObjectNames(connectionId, databaseNames); setChildren(targetNode, children); await savePersistedConnectionTreeChildren(cacheKey, targetNode.children || children); } else if (config && connectionUsesVisibleSchemaFilter(config)) { @@ -3084,7 +3055,7 @@ export const useConnectionStore = defineStore("connection", () => { return; } } - const schemas = await withMetadataLoadTimeout(connectionId, api.listSchemas(connectionId, effectiveDb), "schemas"); + const schemas = await withMetadataLoadTimeout(connectionId, api.listSchemas(connectionId, effectiveDb, true), "schemas"); const visibleSchemas = filterSchemaNamesForConnection(schemas, schemaFilterConfig, effectiveDb || "", { showSystemSchemas }); const schemaNodes: TreeNode[] = sortSidebarNames(visibleSchemas).map((s) => ({ id: `${connectionId}:${s}:${s}`, @@ -3099,7 +3070,6 @@ export const useConnectionStore = defineStore("connection", () => { if (isSidebarSearchQueryChanged(options)) return; const targetNode = treeNodeLoadTarget(load); if (!targetNode) return; - recordPrimaryVisibleObjectNames(connectionId, schemas); setChildren(targetNode, withSavedSqlRoot(connectionId, schemaNodes, targetNode)); await savePersistedConnectionTreeChildren(cacheKey, targetNode.children || schemaNodes); } else { @@ -3183,10 +3153,6 @@ export const useConnectionStore = defineStore("connection", () => { if (isSidebarSearchQueryChanged(options)) return; const targetNode = treeNodeLoadTarget(load); if (!targetNode) return; - recordPrimaryVisibleObjectNames( - connectionId, - databases.map((database) => database.name), - ); setChildren(targetNode, children); await savePersistedConnectionTreeChildren(cacheKey, targetNode.children || children); } @@ -3242,10 +3208,6 @@ export const useConnectionStore = defineStore("connection", () => { const visibleNameSet = new Set(visibleNames); const targetNode = treeNodeLoadTarget(load); if (!targetNode) return; - recordPrimaryVisibleObjectNames( - connectionId, - dbs.map((db) => String(db.db)), - ); setChildren( targetNode, withSavedSqlRoot( @@ -3549,7 +3511,6 @@ export const useConnectionStore = defineStore("connection", () => { const visibleDbs = filterDatabaseNamesForConnection(dbs, config); const targetNode = treeNodeLoadTarget(load); if (!targetNode) return; - recordPrimaryVisibleObjectNames(connectionId, dbs); setChildren( targetNode, withSavedSqlRoot( @@ -6937,8 +6898,6 @@ export const useConnectionStore = defineStore("connection", () => { ensureVisibleDatabase, setVisibleSchemas, clearVisibleSchemas, - recordPrimaryVisibleObjectNames, - getSidebarVisibleFilterSummary, removeConnection, removeConnections, editingConnectionId, diff --git a/packages/app-tests/connectionVisibleDatabases.test.ts b/packages/app-tests/connectionVisibleDatabases.test.ts index 198b562f8..f9b92387d 100644 --- a/packages/app-tests/connectionVisibleDatabases.test.ts +++ b/packages/app-tests/connectionVisibleDatabases.test.ts @@ -90,11 +90,6 @@ test("Turso does not offer a visible database filter for its fixed main namespac assert.equal(connectionCanChooseVisibleDatabases(config({ db_type: "turso" })), false); }); -test("non-database connection types do not offer visible database selection", () => { - assert.equal(connectionCanChooseVisibleDatabases(config({ db_type: "mq" })), false); - assert.equal(connectionCanChooseVisibleDatabases(config({ db_type: "nacos" })), false); -}); - test("OceanBase Oracle uses schema filtering for visible object selection", () => { assert.equal(connectionUsesVisibleSchemaFilter(config({ db_type: "oceanbase-oracle" })), true); assert.equal(connectionUsesVisibleSchemaFilter(config({ db_type: "mysql", driver_profile: "oceanbase" })), false); diff --git a/packages/app-tests/sidebarRuntimeDecomposition.test.ts b/packages/app-tests/sidebarRuntimeDecomposition.test.ts index 0b7aabaa4..2f52693dd 100644 --- a/packages/app-tests/sidebarRuntimeDecomposition.test.ts +++ b/packages/app-tests/sidebarRuntimeDecomposition.test.ts @@ -3,7 +3,6 @@ import { readFileSync } from "node:fs"; import { test } from "vitest"; const treeItem = readFileSync("apps/desktop/src/components/sidebar/TreeItem.vue", "utf8"); -const visibleFilterControl = readFileSync("apps/desktop/src/components/sidebar/SidebarVisibleFilterControl.vue", "utf8"); const connectionTree = readFileSync("apps/desktop/src/components/sidebar/ConnectionTree.vue", "utf8"); const runtimeHost = readFileSync("apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue", "utf8"); const dataOpenRuntime = readFileSync("apps/desktop/src/composables/useSidebarDataOpenRuntime.ts", "utf8"); @@ -34,15 +33,6 @@ test("one tree-level runtime serves every row renderer", () => { assert.match(dataOpenRuntime, /canApplyDataTabMetadata/); }); -test("connection rows expose the primary visible-filter control through the shared runtime", () => { - assert.match(treeItem, //); - assert.match(visibleFilterControl, /data-sidebar-visible-filter/); - assert.match(visibleFilterControl, /control\.selected/); - assert.match(visibleFilterControl, /treeRuntime\.openPrimaryVisibleFilter\(props\.node\)/); - assert.match(runtimeHost, /function openPrimaryVisibleFilter\(node: TreeNode\)/); - assert.match(runtimeHost, /openVisibleDatabasesDialog\(\)/); -}); - test("the persistent runtime releases detached tree nodes", () => { const actionTarget = readFileSync("apps/desktop/src/lib/sidebar/sidebarActionTarget.ts", "utf8"); const connectionMutationRuntime = readFileSync("apps/desktop/src/composables/useSidebarConnectionMutationRuntime.ts", "utf8"); diff --git a/packages/app-tests/sidebarVisibleFilterMenu.test.ts b/packages/app-tests/sidebarVisibleFilterMenu.test.ts index 626959759..8427a74e4 100644 --- a/packages/app-tests/sidebarVisibleFilterMenu.test.ts +++ b/packages/app-tests/sidebarVisibleFilterMenu.test.ts @@ -1,20 +1,6 @@ import assert from "node:assert/strict"; import { test } from "vitest"; -import { connectionCanConfigureSidebarVisibleDatabases, sidebarConnectionVisibleFilterMenu } from "../../apps/desktop/src/lib/sidebar/sidebarVisibleFilterMenu.ts"; - -test("connection-level visible filter support preserves the existing sidebar capability boundary", () => { - assert.equal(connectionCanConfigureSidebarVisibleDatabases("mysql"), true); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("oracle"), true); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("redis"), true); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("sqlite"), true); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("doris"), false); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("starrocks"), false); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("turso"), false); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("zookeeper"), false); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("elasticsearch"), false); - assert.equal(connectionCanConfigureSidebarVisibleDatabases("mq"), false); - assert.equal(connectionCanConfigureSidebarVisibleDatabases(undefined), false); -}); +import { sidebarConnectionVisibleFilterMenu } from "../../apps/desktop/src/lib/sidebar/sidebarVisibleFilterMenu.ts"; test("Dameng and Oracle schema-mode filters keep the connection-level dialog with one schema label", () => { assert.deepEqual( diff --git a/packages/app-tests/sidebarVisibleFilterSummary.test.ts b/packages/app-tests/sidebarVisibleFilterSummary.test.ts deleted file mode 100644 index 852952be4..000000000 --- a/packages/app-tests/sidebarVisibleFilterSummary.test.ts +++ /dev/null @@ -1,92 +0,0 @@ -import assert from "node:assert/strict"; -import { test } from "vitest"; -import type { ConnectionConfig } from "../../apps/desktop/src/types/database.ts"; -import { sidebarVisibleFilterSummary } from "../../apps/desktop/src/lib/sidebar/sidebarVisibleFilterSummary.ts"; - -function connection(overrides: Partial = {}): ConnectionConfig { - return { - id: "connection-1", - name: "Connection", - db_type: "mysql", - host: "localhost", - port: 3306, - username: "root", - ...overrides, - }; -} - -test("summary remains actionable before primary namespace metadata is loaded", () => { - assert.deepEqual(sidebarVisibleFilterSummary(connection({ visible_databases: ["app"] })), { - mode: "database", - isExplicit: true, - selected: null, - total: null, - }); -}); - -test("unfiltered database summary uses the picker's default non-system scope", () => { - assert.deepEqual(sidebarVisibleFilterSummary(connection(), ["app", "analytics", "mysql", "sys"]), { - mode: "database", - isExplicit: false, - selected: 2, - total: 2, - }); -}); - -test("explicit database summary ignores stale names and retains the default denominator", () => { - assert.deepEqual(sidebarVisibleFilterSummary(connection({ visible_databases: ["app", "removed"] }), ["app", "analytics", "mysql"]), { - mode: "database", - isExplicit: true, - selected: 1, - total: 2, - }); -}); - -test("selecting a system database expands the denominator like the picker", () => { - assert.deepEqual(sidebarVisibleFilterSummary(connection({ visible_databases: ["app", "mysql"] }), ["app", "analytics", "mysql", "sys"]), { - mode: "database", - isExplicit: true, - selected: 2, - total: 4, - }); -}); - -test("schema-mode summary reads the primary schema filter for the configured database", () => { - assert.deepEqual( - sidebarVisibleFilterSummary( - connection({ - db_type: "oracle", - database: "ORCL", - username: "APP", - visible_schemas: { ORCL: ["APP"] }, - }), - ["APP", "REPORTING", "SYS"], - ), - { - mode: "schema", - isExplicit: true, - selected: 1, - total: 2, - }, - ); -}); - -test("schema-mode summary includes system schemas when they are explicitly selected", () => { - assert.deepEqual( - sidebarVisibleFilterSummary( - connection({ - db_type: "oracle", - database: "ORCL", - username: "APP", - visible_schemas: { ORCL: ["APP", "SYS"] }, - }), - ["APP", "REPORTING", "SYS"], - ), - { - mode: "schema", - isExplicit: true, - selected: 2, - total: 3, - }, - ); -});