feat(sidebar): expose visible object filter
This commit is contained in:
1 parent
2ede64f1cb
commit
580b70e1d4
26 files changed
+532
-7
No files matched your search
@@ -12,6 +12,7 @@ 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(),
|
||||
@@ -46,6 +47,17 @@ 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();
|
||||
|
||||
@@ -3,9 +3,9 @@ import { filterDatabaseNamesForVisiblePicker, normalizeVisibleDatabaseSelection
|
||||
|
||||
const DRAFT_VISIBLE_DATABASES_PREFIX = "__visible_draft_";
|
||||
|
||||
// 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<DatabaseType>(["turso", "cloudflare-d1", "elasticsearch", "easysearch", "qdrant", "milvus", "weaviate", "chromadb", "etcd", "zookeeper"]);
|
||||
// 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<DatabaseType>(["turso", "cloudflare-d1", "elasticsearch", "easysearch", "qdrant", "milvus", "weaviate", "chromadb", "etcd", "zookeeper", "mq", "nacos"]);
|
||||
|
||||
type VisibleDatabaseConnectionFields = Pick<
|
||||
ConnectionConfig,
|
||||
|
||||
@@ -18,6 +18,7 @@ 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;
|
||||
@@ -38,6 +39,7 @@ 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;
|
||||
@@ -97,6 +99,9 @@ export function createSidebarTreeRuntime(): SidebarTreeRuntime {
|
||||
handleRowKeydown(node, event) {
|
||||
currentHost()?.handleRowKeydown(node, event);
|
||||
},
|
||||
openPrimaryVisibleFilter(node) {
|
||||
currentHost()?.openPrimaryVisibleFilter(node);
|
||||
},
|
||||
openDataInNewTab(node) {
|
||||
currentHost()?.openDataInNewTab(node);
|
||||
},
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
import { connectionCanChooseVisibleDatabases } from "@/lib/connection/connectionVisibleDatabases";
|
||||
|
||||
const CATALOG_SCOPED_VISIBLE_DATABASE_TYPES = new Set<DatabaseType>(["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" }] : [];
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { ConnectionConfig } from "@/types/database";
|
||||
import { connectionUsesVisibleSchemaFilter, filterDatabaseNamesForVisiblePicker, filterSchemaNamesForVisiblePicker, normalizeVisibleDatabaseSelection } from "@/lib/database/visibleDatabases";
|
||||
|
||||
type SidebarVisibleFilterConnection = Pick<ConnectionConfig, "database" | "db_type" | "driver_profile" | "show_system_schemas" | "username" | "visible_databases" | "visible_schemas">;
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user