feat(meilisearch): add workspace, key, and task management
This commit is contained in:
48 files changed
+3984
-18
No files matched your search
@@ -11,6 +11,12 @@ describe("sidebar active-tab targets", () => {
|
||||
expect(matchesTarget({ id: "connection:pg-2", label: "Other", type: "connection", connectionId: "pg-2" } as TreeNode, target!)).toBe(false);
|
||||
});
|
||||
|
||||
it("selects the Meilisearch system-management leaf for its dedicated tab", () => {
|
||||
const target = activeTabSidebarTarget({ mode: "meilisearch-system", connectionId: "meili-1" } as QueryTab);
|
||||
expect(target).toEqual({ type: "meilisearch-system", connectionId: "meili-1" });
|
||||
expect(matchesTarget({ id: "meili-system", label: "meilisearch.systemManagement", type: "meilisearch-system", connectionId: "meili-1" }, target!)).toBe(true);
|
||||
});
|
||||
|
||||
it("locates a query context only in its exact catalog", () => {
|
||||
const target = activeTabSidebarTarget({ mode: "query", connectionId: "doris-1", catalog: "hive", database: "analytics" } as QueryTab);
|
||||
const hiveDatabase = { id: "hive:analytics", label: "analytics", type: "database", connectionId: "doris-1", catalog: "hive", database: "analytics" } as TreeNode;
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { sortSidebarTreeChildrenForParent } from "@/lib/sidebar/sidebarNodeOrdering";
|
||||
import type { TreeNode } from "@/types/database";
|
||||
|
||||
describe("Meilisearch sidebar ordering", () => {
|
||||
it("keeps the single system-management node after all indexes", () => {
|
||||
const children: TreeNode[] = [
|
||||
{ id: "system", label: "meilisearch.systemManagement", type: "meilisearch-system", connectionId: "c1" },
|
||||
{ id: "z", label: "zebra", type: "elasticsearch-index", connectionId: "c1" },
|
||||
{ id: "a", label: "alpha", type: "elasticsearch-index", connectionId: "c1" },
|
||||
];
|
||||
const result = sortSidebarTreeChildrenForParent({ type: "connection" }, children, "meilisearch");
|
||||
expect(result.map((node) => node.id)).toEqual(["a", "z", "system"]);
|
||||
expect(result.filter((node) => node.type === "meilisearch-system")).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -59,6 +59,12 @@ describe("treeNodeClick", () => {
|
||||
expect(treeNodeRowAction("consul-overview", false, "double")).toBe("toggle");
|
||||
});
|
||||
|
||||
it("opens Meilisearch system management as a direct leaf navigation entry", () => {
|
||||
expect(isDirectNavigationTreeNode("meilisearch-system")).toBe(true);
|
||||
expect(shouldActivateTreeNodeOnSingleClick("meilisearch-system", "double")).toBe(true);
|
||||
expect(treeNodeRowAction("meilisearch-system", false, "double")).toBe("toggle");
|
||||
});
|
||||
|
||||
it("keeps Nacos namespace and access-control navigation responsive during rapid row switching", () => {
|
||||
for (const type of ["nacos-namespace", "nacos-access-control"] as const) {
|
||||
expect(isDirectNavigationTreeNode(type), type).toBe(true);
|
||||
|
||||
@@ -754,6 +754,17 @@ export const meilisearchGetIndexStats = forward("meilisearchGetIndexStats");
|
||||
export const meilisearchGetIndexOverview = forward("meilisearchGetIndexOverview");
|
||||
export const meilisearchDeleteIndex = forward("meilisearchDeleteIndex");
|
||||
export const meilisearchDeleteAllDocuments = forward("meilisearchDeleteAllDocuments");
|
||||
export const meilisearchGetSystemOverview = forward("meilisearchGetSystemOverview");
|
||||
export const meilisearchListIndexes = forward("meilisearchListIndexes");
|
||||
export const meilisearchListKeys = forward("meilisearchListKeys");
|
||||
export const meilisearchGetKey = forward("meilisearchGetKey");
|
||||
export const meilisearchCreateKey = forward("meilisearchCreateKey");
|
||||
export const meilisearchUpdateKey = forward("meilisearchUpdateKey");
|
||||
export const meilisearchDeleteKey = forward("meilisearchDeleteKey");
|
||||
export const meilisearchGetTasks = forward("meilisearchGetTasks");
|
||||
export const meilisearchGetTask = forward("meilisearchGetTask");
|
||||
export const meilisearchCancelTasks = forward("meilisearchCancelTasks");
|
||||
export const meilisearchDeleteTasks = forward("meilisearchDeleteTasks");
|
||||
export const mongoDeleteDocument = forward("mongoDeleteDocument");
|
||||
export const mongoDeleteDocuments = forward("mongoDeleteDocuments");
|
||||
export const mongoFindOneAndUpdate = forward("mongoFindOneAndUpdate");
|
||||
|
||||
@@ -48,6 +48,7 @@ import type {
|
||||
import { normalizeRustMongoCommand, type MongoCommand } from "@/lib/mongo/mongoShellCommand";
|
||||
import { BackendErrorException, type BackendError } from "@/lib/backend/errorUtils";
|
||||
import { decodeMeilisearchDocumentPage, decodeMeilisearchSearchResult, type MeilisearchDocumentPage, type MeilisearchDocumentPageWire, type MeilisearchSearchResult, type MeilisearchSearchWireResult } from "@/lib/backend/meilisearchTransport";
|
||||
import type { CreatedKey, EnqueuedTaskSummary, KeyCreateInput, KeyListItem, KeyPage, KeyUpdateInput, MeilisearchSystemOverview, MeilisearchTask, TaskListInput, TaskPage, TaskSelector } from "@/types/meilisearchManagement";
|
||||
import type { CollectionInfo } from "@/types/database";
|
||||
import type { SchemaDiffPreparation, SchemaDiffPreparationOptions, TableDiff, FunctionDiff, SequenceDiff, RuleDiff, OwnerDiff } from "@/lib/schema/schemaDiff";
|
||||
import type { SidebarObjectKind } from "@/lib/database/databaseObjectCapabilities";
|
||||
@@ -3659,6 +3660,12 @@ export async function elasticsearchListIndices(connectionId: string): Promise<st
|
||||
return collections.map((c) => c.name);
|
||||
}
|
||||
|
||||
/** Lists every Meilisearch index visible to the current connection credentials. */
|
||||
export async function meilisearchListIndexes(connectionId: string): Promise<string[]> {
|
||||
const collections = await documentListCollections(connectionId, "default");
|
||||
return collections.map((collection) => collection.name);
|
||||
}
|
||||
|
||||
export async function vectorListCollections(connectionId: string, database?: string): Promise<CollectionInfo[]> {
|
||||
return documentListCollections(connectionId, database || "default");
|
||||
}
|
||||
@@ -4073,6 +4080,46 @@ export async function meilisearchDeleteAllDocuments(connectionId: string, index:
|
||||
});
|
||||
}
|
||||
|
||||
export async function meilisearchGetSystemOverview(connectionId: string): Promise<MeilisearchSystemOverview> {
|
||||
return post("/api/document-store/meilisearch/system/overview", { connectionId });
|
||||
}
|
||||
|
||||
export async function meilisearchListKeys(connectionId: string, offset = 0, limit = 20): Promise<KeyPage> {
|
||||
return post("/api/document-store/meilisearch/keys/list", { connectionId, offset, limit });
|
||||
}
|
||||
|
||||
export async function meilisearchGetKey(connectionId: string, uid: string): Promise<KeyListItem> {
|
||||
return post("/api/document-store/meilisearch/keys/get", { connectionId, uid });
|
||||
}
|
||||
|
||||
export async function meilisearchCreateKey(connectionId: string, input: KeyCreateInput): Promise<CreatedKey> {
|
||||
return post("/api/document-store/meilisearch/keys/create", { connectionId, input });
|
||||
}
|
||||
|
||||
export async function meilisearchUpdateKey(connectionId: string, uid: string, input: KeyUpdateInput): Promise<KeyListItem> {
|
||||
return post("/api/document-store/meilisearch/keys/update", { connectionId, uid, input });
|
||||
}
|
||||
|
||||
export async function meilisearchDeleteKey(connectionId: string, uid: string): Promise<void> {
|
||||
return post("/api/document-store/meilisearch/keys/delete", { connectionId, uid });
|
||||
}
|
||||
|
||||
export async function meilisearchGetTasks(connectionId: string, input: TaskListInput): Promise<TaskPage> {
|
||||
return post("/api/document-store/meilisearch/tasks/list", { connectionId, input });
|
||||
}
|
||||
|
||||
export async function meilisearchGetTask(connectionId: string, uid: number, expectedIndexUid?: string): Promise<MeilisearchTask> {
|
||||
return post("/api/document-store/meilisearch/tasks/get", { connectionId, uid, expectedIndexUid: expectedIndexUid ?? null });
|
||||
}
|
||||
|
||||
export async function meilisearchCancelTasks(connectionId: string, selector: TaskSelector): Promise<EnqueuedTaskSummary> {
|
||||
return post("/api/document-store/meilisearch/tasks/cancel", { connectionId, selector });
|
||||
}
|
||||
|
||||
export async function meilisearchDeleteTasks(connectionId: string, selector: TaskSelector): Promise<EnqueuedTaskSummary> {
|
||||
return post("/api/document-store/meilisearch/tasks/delete", { connectionId, selector });
|
||||
}
|
||||
|
||||
export async function mongoDeleteDocuments(connectionId: string, database: string, collection: string, filterJson: string, many: boolean): Promise<{ affected_rows: number }> {
|
||||
return post("/api/mongo/delete-documents", {
|
||||
connectionId,
|
||||
|
||||
@@ -5,6 +5,7 @@ import { normalizeRustMongoCommand, type MongoCommand } from "@/lib/mongo/mongoS
|
||||
import { ExternalSqlFileTooLargeError } from "@/lib/sql/sqlFileOpen";
|
||||
import { appendDebugLog, isDebugLoggingEnabled } from "@/lib/backend/debugLog";
|
||||
import { decodeMeilisearchDocumentPage, decodeMeilisearchSearchResult, type MeilisearchDocumentPage, type MeilisearchDocumentPageWire, type MeilisearchSearchResult, type MeilisearchSearchWireResult } from "@/lib/backend/meilisearchTransport";
|
||||
import type { CreatedKey, EnqueuedTaskSummary, KeyCreateInput, KeyListItem, KeyPage, KeyUpdateInput, MeilisearchSystemOverview, MeilisearchTask, TaskListInput, TaskPage, TaskSelector } from "@/types/meilisearchManagement";
|
||||
|
||||
/** Normalize Tauri rejections once at the public backend boundary. */
|
||||
async function invokeBackend<T>(command: string, args?: Record<string, unknown>): Promise<T> {
|
||||
@@ -3645,6 +3646,12 @@ export async function elasticsearchListIndices(connectionId: string): Promise<st
|
||||
return collections.map((c) => c.name);
|
||||
}
|
||||
|
||||
/** Lists every Meilisearch index visible to the current connection credentials. */
|
||||
export async function meilisearchListIndexes(connectionId: string): Promise<string[]> {
|
||||
const collections = await documentListCollections(connectionId, "default");
|
||||
return collections.map((collection) => collection.name);
|
||||
}
|
||||
|
||||
export async function vectorListCollections(connectionId: string, database?: string): Promise<CollectionInfo[]> {
|
||||
return documentListCollections(connectionId, database || "default");
|
||||
}
|
||||
@@ -4043,6 +4050,46 @@ export async function meilisearchDeleteAllDocuments(connectionId: string, index:
|
||||
});
|
||||
}
|
||||
|
||||
export async function meilisearchGetSystemOverview(connectionId: string): Promise<MeilisearchSystemOverview> {
|
||||
return invokeBackend("meilisearch_get_system_overview", { connectionId });
|
||||
}
|
||||
|
||||
export async function meilisearchListKeys(connectionId: string, offset = 0, limit = 20): Promise<KeyPage> {
|
||||
return invokeBackend("meilisearch_list_keys", { connectionId, offset, limit });
|
||||
}
|
||||
|
||||
export async function meilisearchGetKey(connectionId: string, uid: string): Promise<KeyListItem> {
|
||||
return invokeBackend("meilisearch_get_key", { connectionId, uid });
|
||||
}
|
||||
|
||||
export async function meilisearchCreateKey(connectionId: string, input: KeyCreateInput): Promise<CreatedKey> {
|
||||
return invokeBackend("meilisearch_create_key", { connectionId, input });
|
||||
}
|
||||
|
||||
export async function meilisearchUpdateKey(connectionId: string, uid: string, input: KeyUpdateInput): Promise<KeyListItem> {
|
||||
return invokeBackend("meilisearch_update_key", { connectionId, uid, input });
|
||||
}
|
||||
|
||||
export async function meilisearchDeleteKey(connectionId: string, uid: string): Promise<void> {
|
||||
return invokeBackend("meilisearch_delete_key", { connectionId, uid });
|
||||
}
|
||||
|
||||
export async function meilisearchGetTasks(connectionId: string, input: TaskListInput): Promise<TaskPage> {
|
||||
return invokeBackend("meilisearch_get_tasks", { connectionId, input });
|
||||
}
|
||||
|
||||
export async function meilisearchGetTask(connectionId: string, uid: number, expectedIndexUid?: string): Promise<MeilisearchTask> {
|
||||
return invokeBackend("meilisearch_get_task", { connectionId, uid, expectedIndexUid: expectedIndexUid ?? null });
|
||||
}
|
||||
|
||||
export async function meilisearchCancelTasks(connectionId: string, selector: TaskSelector): Promise<EnqueuedTaskSummary> {
|
||||
return invokeBackend("meilisearch_cancel_tasks", { connectionId, selector });
|
||||
}
|
||||
|
||||
export async function meilisearchDeleteTasks(connectionId: string, selector: TaskSelector): Promise<EnqueuedTaskSummary> {
|
||||
return invokeBackend("meilisearch_delete_tasks", { connectionId, selector });
|
||||
}
|
||||
|
||||
export async function mongoDeleteDocuments(connectionId: string, database: string, collection: string, filterJson: string, many: boolean): Promise<{ affected_rows: number }> {
|
||||
const affectedRows = await invoke<number>("mongo_delete_documents", {
|
||||
connectionId,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { loadMeilisearchKeyColumns, MEILISEARCH_KEY_COLUMN_KEYS, MEILISEARCH_KEY_COLUMN_STORAGE_KEY, saveMeilisearchKeyColumns } from "./meilisearchKeyColumns";
|
||||
|
||||
describe("Meilisearch key column persistence", () => {
|
||||
beforeEach(() => localStorage.removeItem(MEILISEARCH_KEY_COLUMN_STORAGE_KEY));
|
||||
|
||||
it("uses all columns by default", () => {
|
||||
expect(loadMeilisearchKeyColumns()).toEqual(MEILISEARCH_KEY_COLUMN_KEYS);
|
||||
});
|
||||
|
||||
it("stores valid columns in canonical order", () => {
|
||||
saveMeilisearchKeyColumns(["expiresAt", "name", "key"]);
|
||||
expect(loadMeilisearchKeyColumns()).toEqual(["name", "key", "expiresAt"]);
|
||||
});
|
||||
|
||||
it("falls back safely for invalid persisted data", () => {
|
||||
localStorage.setItem(MEILISEARCH_KEY_COLUMN_STORAGE_KEY, "invalid");
|
||||
expect(loadMeilisearchKeyColumns()).toEqual(MEILISEARCH_KEY_COLUMN_KEYS);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/backend/safeStorage";
|
||||
|
||||
export const MEILISEARCH_KEY_COLUMN_STORAGE_KEY = "dbx:meilisearch:key-columns:v1";
|
||||
export const MEILISEARCH_KEY_COLUMN_KEYS = ["name", "key", "uid", "actions", "indexes", "expiresAt"] as const;
|
||||
export type MeilisearchKeyColumnKey = (typeof MEILISEARCH_KEY_COLUMN_KEYS)[number];
|
||||
|
||||
function isKeyColumn(value: unknown): value is MeilisearchKeyColumnKey {
|
||||
return typeof value === "string" && MEILISEARCH_KEY_COLUMN_KEYS.includes(value as MeilisearchKeyColumnKey);
|
||||
}
|
||||
|
||||
export function loadMeilisearchKeyColumns(): MeilisearchKeyColumnKey[] {
|
||||
try {
|
||||
const parsed = JSON.parse(safeLocalStorageGet(MEILISEARCH_KEY_COLUMN_STORAGE_KEY) || "null") as { visible?: unknown } | null;
|
||||
const visible = Array.isArray(parsed?.visible) ? parsed.visible.filter(isKeyColumn) : [];
|
||||
return visible.length ? MEILISEARCH_KEY_COLUMN_KEYS.filter((key) => visible.includes(key)) : [...MEILISEARCH_KEY_COLUMN_KEYS];
|
||||
} catch {
|
||||
return [...MEILISEARCH_KEY_COLUMN_KEYS];
|
||||
}
|
||||
}
|
||||
|
||||
export function saveMeilisearchKeyColumns(visible: readonly MeilisearchKeyColumnKey[]): void {
|
||||
const normalized = MEILISEARCH_KEY_COLUMN_KEYS.filter((key) => visible.includes(key));
|
||||
safeLocalStorageSet(MEILISEARCH_KEY_COLUMN_STORAGE_KEY, JSON.stringify({ version: 1, visible: normalized.length ? normalized : [...MEILISEARCH_KEY_COLUMN_KEYS] }));
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { loadMeilisearchTaskColumns, MEILISEARCH_TASK_COLUMN_KEYS, MEILISEARCH_TASK_COLUMN_STORAGE_KEY, saveMeilisearchTaskColumns } from "./meilisearchTaskColumns";
|
||||
|
||||
describe("Meilisearch task column persistence", () => {
|
||||
beforeEach(() => localStorage.removeItem(MEILISEARCH_TASK_COLUMN_STORAGE_KEY));
|
||||
|
||||
it("shows every supported column by default", () => {
|
||||
expect(loadMeilisearchTaskColumns()).toEqual(MEILISEARCH_TASK_COLUMN_KEYS);
|
||||
});
|
||||
|
||||
it("persists known visible columns in stable table order", () => {
|
||||
saveMeilisearchTaskColumns(["finishedAt", "uid", "details"]);
|
||||
expect(loadMeilisearchTaskColumns()).toEqual(["uid", "details", "finishedAt"]);
|
||||
});
|
||||
|
||||
it("ignores corrupt and unknown stored values", () => {
|
||||
localStorage.setItem(MEILISEARCH_TASK_COLUMN_STORAGE_KEY, JSON.stringify({ visible: ["unknown", "status"] }));
|
||||
expect(loadMeilisearchTaskColumns()).toEqual(["status"]);
|
||||
localStorage.setItem(MEILISEARCH_TASK_COLUMN_STORAGE_KEY, "not-json");
|
||||
expect(loadMeilisearchTaskColumns()).toEqual(MEILISEARCH_TASK_COLUMN_KEYS);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/backend/safeStorage";
|
||||
|
||||
export const MEILISEARCH_TASK_COLUMN_STORAGE_KEY = "dbx:meilisearch:task-columns:v1";
|
||||
|
||||
export const MEILISEARCH_TASK_COLUMN_KEYS = ["uid", "index", "type", "status", "details", "enqueuedAt", "startedAt", "finishedAt", "duration"] as const;
|
||||
|
||||
export type MeilisearchTaskColumnKey = (typeof MEILISEARCH_TASK_COLUMN_KEYS)[number];
|
||||
|
||||
function isTaskColumnKey(value: unknown): value is MeilisearchTaskColumnKey {
|
||||
return typeof value === "string" && MEILISEARCH_TASK_COLUMN_KEYS.includes(value as MeilisearchTaskColumnKey);
|
||||
}
|
||||
|
||||
export function loadMeilisearchTaskColumns(): MeilisearchTaskColumnKey[] {
|
||||
try {
|
||||
const parsed = JSON.parse(safeLocalStorageGet(MEILISEARCH_TASK_COLUMN_STORAGE_KEY) || "null") as { visible?: unknown } | null;
|
||||
const visible = Array.isArray(parsed?.visible) ? parsed.visible.filter(isTaskColumnKey) : [];
|
||||
return visible.length ? MEILISEARCH_TASK_COLUMN_KEYS.filter((key) => visible.includes(key)) : [...MEILISEARCH_TASK_COLUMN_KEYS];
|
||||
} catch {
|
||||
return [...MEILISEARCH_TASK_COLUMN_KEYS];
|
||||
}
|
||||
}
|
||||
|
||||
export function saveMeilisearchTaskColumns(visible: readonly MeilisearchTaskColumnKey[]): void {
|
||||
const normalized = MEILISEARCH_TASK_COLUMN_KEYS.filter((key) => visible.includes(key));
|
||||
safeLocalStorageSet(MEILISEARCH_TASK_COLUMN_STORAGE_KEY, JSON.stringify({ version: 1, visible: normalized.length ? normalized : [...MEILISEARCH_TASK_COLUMN_KEYS] }));
|
||||
}
|
||||
@@ -64,6 +64,10 @@ export type ActiveTabSidebarTarget =
|
||||
type: "consul-overview";
|
||||
connectionId: string;
|
||||
}
|
||||
| {
|
||||
type: "meilisearch-system";
|
||||
connectionId: string;
|
||||
}
|
||||
| {
|
||||
type: "mq-tenant";
|
||||
connectionId: string;
|
||||
@@ -143,6 +147,10 @@ export function activeTabSidebarTarget(tab: QueryTab | undefined | null): Active
|
||||
};
|
||||
}
|
||||
|
||||
if (tab.mode === "meilisearch-system") {
|
||||
return { type: "meilisearch-system", connectionId: tab.connectionId };
|
||||
}
|
||||
|
||||
if (tab.mode === "mongo-bucket") {
|
||||
return {
|
||||
type: "mongo-gridfs",
|
||||
@@ -255,6 +263,10 @@ export function matchesTarget(node: TreeNode, target: ActiveTabSidebarTarget): b
|
||||
return node.type === "mongo-collection" && node.connectionId === target.connectionId && node.database === target.database && node.label === target.collectionName;
|
||||
}
|
||||
|
||||
if (target.type === "meilisearch-system") {
|
||||
return node.type === "meilisearch-system" && node.connectionId === target.connectionId;
|
||||
}
|
||||
|
||||
if (target.type === "mongo-gridfs") {
|
||||
return node.type === "mongo-gridfs" && node.connectionId === target.connectionId && node.database === target.database;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,9 @@ export function sortSidebarTreeChildrenForParent(parent: Pick<TreeNode, "type">,
|
||||
const withConnectionUtilityOrder = (children: TreeNode[]) => [...savedSqlNodes, ...children, ...userAdminNodes];
|
||||
|
||||
if (databaseType === "mongodb" || databaseType === "elasticsearch" || databaseType === "easysearch" || databaseType === "meilisearch" || databaseType === "qdrant" || databaseType === "milvus" || databaseType === "weaviate" || databaseType === "chromadb") {
|
||||
return withConnectionUtilityOrder(sortByLabel(regularChildren));
|
||||
const meilisearchSystem = regularChildren.filter((child) => child.type === "meilisearch-system");
|
||||
const databaseObjects = regularChildren.filter((child) => child.type !== "meilisearch-system");
|
||||
return withConnectionUtilityOrder([...sortByLabel(databaseObjects), ...meilisearchSystem]);
|
||||
}
|
||||
|
||||
if (databaseType === "duckdb") {
|
||||
|
||||
@@ -30,6 +30,7 @@ const leafTypes: Set<TreeNodeType> = new Set([
|
||||
"dynamodb-table",
|
||||
"vector-collection",
|
||||
"elasticsearch-index",
|
||||
"meilisearch-system",
|
||||
"user-admin",
|
||||
"dameng-users",
|
||||
"dameng-roles",
|
||||
|
||||
@@ -27,6 +27,7 @@ const toggleLeafNodeTypes = new Set<TreeNodeType>([
|
||||
"dynamodb-table",
|
||||
"vector-collection",
|
||||
"elasticsearch-index",
|
||||
"meilisearch-system",
|
||||
"user-admin",
|
||||
"dameng-users",
|
||||
"dameng-roles",
|
||||
@@ -34,7 +35,7 @@ const toggleLeafNodeTypes = new Set<TreeNodeType>([
|
||||
// These are application entry points rather than database objects. They should
|
||||
// always navigate on a single click, even when the user prefers double-click
|
||||
// activation for ordinary tree objects.
|
||||
const directNavigationTreeNodeTypes = new Set<TreeNodeType>(["consul-root", "consul-overview", "nacos-namespace", "nacos-access-control"]);
|
||||
const directNavigationTreeNodeTypes = new Set<TreeNodeType>(["consul-root", "consul-overview", "nacos-namespace", "nacos-access-control", "meilisearch-system"]);
|
||||
const repeatableNavigationTreeNodeTypes = new Set<TreeNodeType>(["nacos-namespace", "nacos-access-control"]);
|
||||
|
||||
export function isDirectNavigationTreeNode(type: TreeNodeType): boolean {
|
||||
|
||||
@@ -102,6 +102,8 @@ export function getTreeNodeIconInfo(node: TreeNode): TreeNodeIconInfo | null {
|
||||
return { icon: TableProperties, colorClass: "text-cyan-400" };
|
||||
case "elasticsearch-index":
|
||||
return { icon: Table, colorClass: "text-emerald-400" };
|
||||
case "meilisearch-system":
|
||||
return { icon: Gauge, colorClass: "text-emerald-500" };
|
||||
case "procedure":
|
||||
return { icon: ScrollText, colorClass: "text-blue-500" };
|
||||
case "function":
|
||||
|
||||
Reference in new issue
Block a user