feat(elasticsearch): show index aliases on sidebar rows
This commit is contained in:
1 parent
6299d62125
commit
61bd3cdf62
22 files changed
+432
-51
No files matched your search
@@ -90,6 +90,7 @@ import { focusSidebarRenameInput } from "@/lib/sidebar/sidebarRenameFocus";
|
||||
import { ensureSqlExtension, stripSqlExtension } from "@/lib/savedSql/savedSqlFileName";
|
||||
import { savedSqlErrorMessage } from "@/lib/savedSql/savedSqlErrors";
|
||||
import { useSavedSqlStore } from "@/stores/savedSqlStore";
|
||||
import { elasticsearchIndexAliasLabel } from "@/lib/sidebar/elasticsearchIndexActions";
|
||||
import { isXuguPublicSynonymTreeNode, isXuguSchedulerJobTreeNode, xuguSchemaDisplayName } from "@/lib/sidebar/xuguPublicSynonyms";
|
||||
import { xuguDatafileDetailRows, xuguTablespaceDetailRows } from "@/lib/sidebar/xuguTablespaces";
|
||||
// --- Drag and Drop ---
|
||||
@@ -442,6 +443,7 @@ function treeNodeSecondaryValue(node: TreeNode): string | undefined {
|
||||
if (node.type === "type" && node.customTypeKind) return t(`customType.kinds.${node.customTypeKind}`);
|
||||
if (node.type === "type-member") return (node.meta as CustomTypeTreeMemberMeta | undefined)?.displayValue;
|
||||
if (node.type === "datafile") return node.xuguDatafilePath;
|
||||
if (node.type === "elasticsearch-index") return elasticsearchIndexAliasLabel(node);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -604,6 +606,16 @@ const detailTooltip = computed(() => {
|
||||
}));
|
||||
return rows.length ? { rows } : null;
|
||||
}
|
||||
if (node.type === "elasticsearch-index") {
|
||||
const aliases = elasticsearchIndexAliasLabel(node);
|
||||
if (!aliases) return null;
|
||||
return {
|
||||
rows: [
|
||||
{ label: t("objects.name"), value: visibleLabel(node) },
|
||||
{ label: t("tree.elasticsearchAlias"), value: aliases },
|
||||
],
|
||||
};
|
||||
}
|
||||
const comment = node.type === "column" && node.meta && "comment" in node.meta ? (node.meta as ColumnInfo).comment : node.comment;
|
||||
if (!comment || (node.type !== "schema" && node.type !== "table" && node.type !== "view" && node.type !== "column")) return null;
|
||||
const rows: DetailTooltipRow[] = [
|
||||
@@ -1567,7 +1579,10 @@ function onKeydown(event: KeyboardEvent) {
|
||||
]"
|
||||
>{{ visibleLabel(node) }}</span
|
||||
>
|
||||
<span v-if="treeNodeSecondaryValue(node)" class="min-w-0 max-w-[55%] shrink truncate text-xs text-muted-foreground" :title="treeNodeSecondaryValue(node)">{{ treeNodeSecondaryValue(node) }}</span>
|
||||
<span v-if="treeNodeSecondaryValue(node)" class="flex min-w-0 max-w-[55%] shrink items-center gap-1 text-xs text-muted-foreground" :title="node.type === 'elasticsearch-index' ? undefined : treeNodeSecondaryValue(node)">
|
||||
<Link2 v-if="node.type === 'elasticsearch-index'" class="h-3 w-3 shrink-0 text-sky-400" />
|
||||
<span class="min-w-0 truncate">{{ treeNodeSecondaryValue(node) }}</span>
|
||||
</span>
|
||||
<button
|
||||
v-if="canDragPinnedOrder()"
|
||||
type="button"
|
||||
|
||||
@@ -3637,6 +3637,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
linkedServers: "Əlaqələndirilmiş serverlər",
|
||||
defaultDatabase: "Standart verilənlər bazası",
|
||||
elasticsearchAlias: "Təxəllüs",
|
||||
columns: "Sütunlar",
|
||||
attributes: "Atributlar",
|
||||
methods: "Metodlar",
|
||||
|
||||
@@ -3636,6 +3636,7 @@ export default {
|
||||
},
|
||||
linkedServers: "Linked Servers",
|
||||
defaultDatabase: "Default DB",
|
||||
elasticsearchAlias: "Alias",
|
||||
columns: "Columns",
|
||||
attributes: "Attributes",
|
||||
methods: "Methods",
|
||||
|
||||
@@ -3518,6 +3518,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
linkedServers: "Servidores vinculados",
|
||||
defaultDatabase: "Base predeterminada",
|
||||
elasticsearchAlias: "Alias",
|
||||
columns: "Columnas",
|
||||
attributes: "Atributos",
|
||||
methods: "Métodos",
|
||||
|
||||
@@ -3516,6 +3516,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
linkedServers: "Server Collegati",
|
||||
defaultDatabase: "DB Predefinito",
|
||||
elasticsearchAlias: "Alias",
|
||||
columns: "Colonne",
|
||||
attributes: "Attributi",
|
||||
methods: "Metodi",
|
||||
|
||||
@@ -3541,6 +3541,7 @@ export default withEnglishFallback({
|
||||
no: "いいえ",
|
||||
},
|
||||
defaultDatabase: "デフォルトDB",
|
||||
elasticsearchAlias: "エイリアス",
|
||||
columns: "列",
|
||||
attributes: "属性",
|
||||
methods: "メソッド",
|
||||
|
||||
@@ -3395,6 +3395,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
linkedServers: "연결된 서버",
|
||||
defaultDatabase: "기본 DB",
|
||||
elasticsearchAlias: "별칭",
|
||||
columns: "컬럼",
|
||||
attributes: "속성",
|
||||
methods: "메서드",
|
||||
|
||||
@@ -3519,6 +3519,7 @@ export default withEnglishFallback({
|
||||
linkedServers: "Servidores Vinculados",
|
||||
materializedViews: "Visualizações Materializadas",
|
||||
defaultDatabase: "Banco padrão",
|
||||
elasticsearchAlias: "Alias",
|
||||
columns: "Colunas",
|
||||
attributes: "Atributos",
|
||||
methods: "Métodos",
|
||||
|
||||
@@ -3609,6 +3609,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
linkedServers: "Bağlı Sunucular",
|
||||
defaultDatabase: "Varsayılan VT",
|
||||
elasticsearchAlias: "Takma ad",
|
||||
columns: "Sütunlar",
|
||||
attributes: "Öznitelikler",
|
||||
methods: "Yöntemler",
|
||||
|
||||
@@ -3557,6 +3557,7 @@ export default withEnglishFallback({
|
||||
},
|
||||
linkedServers: "链接服务器",
|
||||
defaultDatabase: "默认库",
|
||||
elasticsearchAlias: "别名",
|
||||
columns: "字段",
|
||||
attributes: "属性",
|
||||
methods: "方法",
|
||||
|
||||
@@ -3516,6 +3516,7 @@ export default withEnglishFallback({
|
||||
linkedServers: "連結伺服器",
|
||||
materializedViews: "具體化檢視",
|
||||
defaultDatabase: "預設庫",
|
||||
elasticsearchAlias: "別名",
|
||||
columns: "欄位",
|
||||
attributes: "屬性",
|
||||
methods: "方法",
|
||||
|
||||
@@ -3863,7 +3863,7 @@ export async function mongoCloneCollection(connectionId: string, database: strin
|
||||
|
||||
export async function elasticsearchListIndices(connectionId: string): Promise<string[]> {
|
||||
const collections = await documentListCollections(connectionId, "default");
|
||||
return collections.map((c) => c.name);
|
||||
return [...new Set(collections.flatMap((collection) => [collection.name, ...(collection.aliases ?? [])].filter((name) => name.trim())))];
|
||||
}
|
||||
|
||||
/** Lists every Meilisearch index visible to the current connection credentials. */
|
||||
|
||||
@@ -3951,7 +3951,7 @@ export async function vectorRenameCollection(connectionId: string, database: str
|
||||
|
||||
export async function elasticsearchListIndices(connectionId: string): Promise<string[]> {
|
||||
const collections = await documentListCollections(connectionId, "default");
|
||||
return collections.map((c) => c.name);
|
||||
return [...new Set(collections.flatMap((collection) => [collection.name, ...(collection.aliases ?? [])].filter((name) => name.trim())))];
|
||||
}
|
||||
|
||||
/** Lists every Meilisearch index visible to the current connection credentials. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { elasticsearchClearIndexPreview, isElasticsearchClearConfirmed, isElasticsearchIndexPattern, isElasticsearchProtocolIndex, isPartialElasticsearchClear, matchesElasticsearchIndexPattern } from "@/lib/sidebar/elasticsearchIndexActions";
|
||||
import { elasticsearchClearIndexPreview, elasticsearchIndexAliasLabel, isElasticsearchClearConfirmed, isElasticsearchIndexPattern, isElasticsearchProtocolIndex, isPartialElasticsearchClear, matchesElasticsearchIndexPattern } from "@/lib/sidebar/elasticsearchIndexActions";
|
||||
import type { ElasticsearchDeleteByQueryResult } from "@/lib/backend/tauri";
|
||||
|
||||
function clearResult(overrides: Partial<ElasticsearchDeleteByQueryResult> = {}): ElasticsearchDeleteByQueryResult {
|
||||
@@ -16,6 +16,12 @@ describe("Elasticsearch index actions", () => {
|
||||
expect(isElasticsearchProtocolIndex("elasticsearch-index", undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it("renders aliases on the same row as the index name", () => {
|
||||
expect(elasticsearchIndexAliasLabel({ searchAliases: ["orders-write", "orders-read"] })).toBe("orders-write, orders-read");
|
||||
expect(elasticsearchIndexAliasLabel({ searchAliases: ["", " "] })).toBeUndefined();
|
||||
expect(elasticsearchIndexAliasLabel({})).toBeUndefined();
|
||||
});
|
||||
|
||||
it("previews the exact request the clear action sends", () => {
|
||||
const preview = elasticsearchClearIndexPreview("logs-2026.08");
|
||||
expect(preview).toContain("POST /logs-2026.08/_delete_by_query?conflicts=proceed&refresh=true");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { DatabaseType } from "@/types/database";
|
||||
import type { DatabaseType, TreeNode } from "@/types/database";
|
||||
import type { ElasticsearchDeleteByQueryResult } from "@/lib/backend/tauri";
|
||||
|
||||
/**
|
||||
@@ -10,6 +10,11 @@ export function isElasticsearchProtocolIndex(nodeType: string, dbType: DatabaseT
|
||||
return nodeType === "elasticsearch-index" && (dbType === "elasticsearch" || dbType === "easysearch");
|
||||
}
|
||||
|
||||
export function elasticsearchIndexAliasLabel(node: Pick<TreeNode, "searchAliases">): string | undefined {
|
||||
const aliases = node.searchAliases?.filter((alias) => alias.trim()) ?? [];
|
||||
return aliases.length ? aliases.join(", ") : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* With an `index_grouping` regex configured, a sidebar index node is a collapsed
|
||||
* pattern (`logs-2026.08.*`) rather than one index, and clearing it hits every
|
||||
|
||||
+71
-13
@@ -45,13 +45,17 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
});
|
||||
|
||||
it("openElasticsearchConnectionTree only ensures connectivity, does not expand or list indices", async () => {
|
||||
const elasticsearchListIndices = vi.fn().mockResolvedValue(["orders", "users"]);
|
||||
const documentListCollections = vi.fn().mockResolvedValue([
|
||||
{ name: "orders", id: "orders", kind: "index" },
|
||||
{ name: "users", id: "users", kind: "index" },
|
||||
]);
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth,
|
||||
elasticsearchListIndices,
|
||||
documentListCollections,
|
||||
elasticsearchListIndices: vi.fn(),
|
||||
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
|
||||
loadSchemaCache: vi.fn().mockResolvedValue(null),
|
||||
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -66,7 +70,7 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
|
||||
await store.openElasticsearchConnectionTree("es-1");
|
||||
|
||||
expect(elasticsearchListIndices).not.toHaveBeenCalled();
|
||||
expect(documentListCollections).not.toHaveBeenCalled();
|
||||
const node = store.treeNodes.find((n) => n.id === "es-1");
|
||||
// openElasticsearchConnectionTree does NOT expand the node
|
||||
expect(node?.isExpanded).toBe(false);
|
||||
@@ -74,13 +78,17 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
});
|
||||
|
||||
it("refreshTreeNode lists indices", async () => {
|
||||
const elasticsearchListIndices = vi.fn().mockResolvedValue(["orders", "users"]);
|
||||
const documentListCollections = vi.fn().mockResolvedValue([
|
||||
{ name: "orders", id: "orders", kind: "index" },
|
||||
{ name: "users", id: "users", kind: "index" },
|
||||
]);
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth,
|
||||
elasticsearchListIndices,
|
||||
documentListCollections,
|
||||
elasticsearchListIndices: vi.fn(),
|
||||
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
|
||||
loadSchemaCache: vi.fn().mockResolvedValue(null),
|
||||
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -96,7 +104,7 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
|
||||
await store.refreshTreeNode(node);
|
||||
|
||||
expect(elasticsearchListIndices).toHaveBeenCalledWith("es-1");
|
||||
expect(documentListCollections).toHaveBeenCalledWith("es-1", "default");
|
||||
expect(
|
||||
node.children
|
||||
?.filter((c) => c.type === "elasticsearch-index")
|
||||
@@ -106,13 +114,17 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
});
|
||||
|
||||
it("loadElasticsearchIndices lists indices and expands", async () => {
|
||||
const elasticsearchListIndices = vi.fn().mockResolvedValue(["orders", "users"]);
|
||||
const documentListCollections = vi.fn().mockResolvedValue([
|
||||
{ name: "orders", id: "orders", kind: "index" },
|
||||
{ name: "users", id: "users", kind: "index" },
|
||||
]);
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth,
|
||||
elasticsearchListIndices,
|
||||
documentListCollections,
|
||||
elasticsearchListIndices: vi.fn(),
|
||||
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
|
||||
loadSchemaCache: vi.fn().mockResolvedValue(null),
|
||||
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -127,7 +139,7 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
|
||||
await store.loadElasticsearchIndices("es-1");
|
||||
|
||||
expect(elasticsearchListIndices).toHaveBeenCalledWith("es-1");
|
||||
expect(documentListCollections).toHaveBeenCalledWith("es-1", "default");
|
||||
const node = store.treeNodes.find((n) => n.id === "es-1");
|
||||
expect(
|
||||
node?.children
|
||||
@@ -138,13 +150,17 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
});
|
||||
|
||||
it("loads Easysearch indices through the Elasticsearch-compatible tree", async () => {
|
||||
const elasticsearchListIndices = vi.fn().mockResolvedValue(["orders", "users"]);
|
||||
const documentListCollections = vi.fn().mockResolvedValue([
|
||||
{ name: "orders", id: "orders", kind: "index" },
|
||||
{ name: "users", id: "users", kind: "index" },
|
||||
]);
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth,
|
||||
elasticsearchListIndices,
|
||||
documentListCollections,
|
||||
elasticsearchListIndices: vi.fn(),
|
||||
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
|
||||
loadSchemaCache: vi.fn().mockResolvedValue(null),
|
||||
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -159,16 +175,56 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
|
||||
await store.loadElasticsearchIndices("easysearch-1");
|
||||
|
||||
expect(elasticsearchListIndices).toHaveBeenCalledWith("easysearch-1");
|
||||
expect(documentListCollections).toHaveBeenCalledWith("easysearch-1", "default");
|
||||
expect(
|
||||
store.treeNodes
|
||||
.find((node) => node.id === "easysearch-1")
|
||||
?.children?.map((node) => node.label)
|
||||
?.children?.filter((node) => node.type === "elasticsearch-index")
|
||||
.map((node) => node.label)
|
||||
.sort(),
|
||||
).toEqual(["orders", "users"]);
|
||||
});
|
||||
|
||||
it("keeps aliases on the same index row instead of adding a second node", async () => {
|
||||
const documentListCollections = vi.fn().mockResolvedValue([
|
||||
{ name: "orders", id: "orders", aliases: ["orders-write"] },
|
||||
{ name: "users", id: "users", aliases: [] },
|
||||
]);
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth,
|
||||
documentListCollections,
|
||||
elasticsearchListIndices: vi.fn(),
|
||||
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
|
||||
loadSchemaCache: vi.fn().mockResolvedValue(null),
|
||||
saveSchemaCache: vi.fn().mockResolvedValue(undefined),
|
||||
saveConnections: vi.fn().mockResolvedValue(undefined),
|
||||
saveSidebarLayout: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
const { useConnectionStore } = await import("@/stores/connectionStore");
|
||||
const store = useConnectionStore();
|
||||
store.addEphemeralConnection(esConnection());
|
||||
seedConnectionNode(store);
|
||||
|
||||
await store.loadElasticsearchIndices("es-1");
|
||||
|
||||
const nodes = store.treeNodes.find((node) => node.id === "es-1")?.children?.filter((node) => node.type === "elasticsearch-index");
|
||||
expect(
|
||||
nodes?.map((node) => ({
|
||||
label: node.label,
|
||||
searchAliases: node.searchAliases,
|
||||
})),
|
||||
).toEqual([
|
||||
{ label: "orders", searchAliases: ["orders-write"] },
|
||||
{ label: "users", searchAliases: undefined },
|
||||
]);
|
||||
});
|
||||
|
||||
it("uses the shared Meilisearch index-list method for the Meilisearch tree", async () => {
|
||||
const documentListCollections = vi.fn().mockResolvedValue([{ name: "wrong-index", id: "wrong-index", kind: "index" }]);
|
||||
const elasticsearchListIndices = vi.fn().mockResolvedValue(["wrong-index"]);
|
||||
const meilisearchListIndexes = vi.fn().mockResolvedValue(["movies", "books"]);
|
||||
const checkConnectionHealth = vi.fn().mockResolvedValue(undefined);
|
||||
@@ -176,6 +232,7 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
vi.doMock("@/lib/backend/tauriRuntime", () => ({ isTauriRuntime: () => false }));
|
||||
vi.doMock("@/lib/backend/api", () => ({
|
||||
checkConnectionHealth,
|
||||
documentListCollections,
|
||||
elasticsearchListIndices,
|
||||
meilisearchListIndexes,
|
||||
deleteSchemaCachePrefix: vi.fn().mockResolvedValue(undefined),
|
||||
@@ -193,6 +250,7 @@ describe("connectionStore Elasticsearch open/expand", () => {
|
||||
await store.loadElasticsearchIndices("meili-1");
|
||||
|
||||
expect(meilisearchListIndexes).toHaveBeenCalledWith("meili-1");
|
||||
expect(documentListCollections).not.toHaveBeenCalled();
|
||||
expect(elasticsearchListIndices).not.toHaveBeenCalled();
|
||||
expect(
|
||||
store.treeNodes
|
||||
|
||||
@@ -4989,7 +4989,21 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
await ensureConnected(connectionId);
|
||||
load = reclaimTreeNodeLoad(load, node);
|
||||
const isMeilisearch = getConfig(connectionId)?.db_type === "meilisearch";
|
||||
const indices = await withMetadataLoadTimeout(connectionId, isMeilisearch ? api.meilisearchListIndexes(connectionId) : api.elasticsearchListIndices(connectionId), isMeilisearch ? "Meilisearch indexes" : "Elasticsearch indices");
|
||||
const collections = isMeilisearch
|
||||
? sortSidebarNames(await withMetadataLoadTimeout(connectionId, api.meilisearchListIndexes(connectionId), "Meilisearch indexes")).map((name) => ({ name, aliases: [] as string[] }))
|
||||
: [...(await withMetadataLoadTimeout(connectionId, api.documentListCollections(connectionId, "default"), "Elasticsearch indices"))].sort((left, right) => compareSidebarNames(left.name, right.name));
|
||||
const indexNodes = collections.map((collection) => {
|
||||
const aliases = collection.aliases?.filter((alias) => alias.trim());
|
||||
return {
|
||||
id: `${connectionId}:__collection:${collection.name}`,
|
||||
label: collection.name,
|
||||
type: "elasticsearch-index" as const,
|
||||
connectionId,
|
||||
database: "default",
|
||||
isExpanded: false,
|
||||
...(aliases?.length ? { searchAliases: aliases } : {}),
|
||||
};
|
||||
});
|
||||
const targetNode = treeNodeLoadTarget(load);
|
||||
if (!targetNode) return;
|
||||
setChildren(
|
||||
@@ -4997,14 +5011,7 @@ export const useConnectionStore = defineStore("connection", () => {
|
||||
withSavedSqlRoot(
|
||||
connectionId,
|
||||
[
|
||||
...sortSidebarNames(indices).map((index) => ({
|
||||
id: `${connectionId}:__collection:${index}`,
|
||||
label: index,
|
||||
type: "elasticsearch-index" as const,
|
||||
connectionId,
|
||||
database: "default",
|
||||
isExpanded: false,
|
||||
})),
|
||||
...indexNodes,
|
||||
...(isMeilisearch
|
||||
? [
|
||||
{
|
||||
|
||||
@@ -1562,4 +1562,5 @@ export interface CollectionInfo {
|
||||
milvusSchema?: MilvusCollectionSchema;
|
||||
kind?: MongoCollectionKind | "bucket";
|
||||
bucketName?: string;
|
||||
aliases?: string[];
|
||||
}
|
||||
Reference in new issue
Block a user