feat(xugu): expose tablespaces and datafiles in tree

This commit is contained in:
Elias authored and GitHub committed 2026-09-01 00:34:12 +08:00
1 parent afe3b3f3c2
commit 351a8b699b
32 files changed
+811 -4

No files matched your search

+70 -2
View File
@@ -164,6 +164,7 @@ import { invalidateObjectBrowserRowsCache } from "@/lib/table/objectBrowserRowsC
import { MetadataTaskLimiter } from "@/lib/metadata/metadataTaskLimiter";
import { buildCustomTypeTreeChildren } from "@/lib/sidebar/customTypeTree";
import { TreeNodeLoadRegistry, type TreeNodeLoadHandle } from "@/lib/metadata/treeNodeLoadHandle";
import { buildXuguTablespaceChildren } from "@/lib/sidebar/xuguTablespaces";
import i18n from "@/i18n";
import type { MqAdminConfig } from "@/types/mq";
import { RABBITMQ_MQ_TENANT, resolveMqSystemKindFromConnection } from "@/lib/mq/mqConsoleDefaults";
@@ -1364,7 +1365,7 @@ export const useConnectionStore = defineStore("connection", () => {
// as metadata children, withConnectionUtilityNodes would keep the old copies
// AND append fresh ones on every useCachedChildren pass, duplicating the
// 用户/角色 menus once per refresh cycle.
return node.type === "user-admin" || node.type === "dameng-users" || node.type === "dameng-roles" || node.type === "dameng-job-admin" || node.type === "saved-sql-root";
return node.type === "user-admin" || node.type === "dameng-users" || node.type === "dameng-roles" || node.type === "dameng-job-admin" || node.type === "group-tablespaces" || node.type === "saved-sql-root";
}
function connectionMetadataChildren(children: TreeNode[] | undefined): TreeNode[] {
@@ -1653,13 +1654,33 @@ export const useConnectionStore = defineStore("connection", () => {
};
}
function buildXuguTablespacesNode(connectionId: string, existingConnectionNode?: TreeNode): TreeNode | undefined {
const config = getConfig(connectionId);
if (effectiveDatabaseTypeForConnection(config) !== "xugu") return undefined;
const existing = existingConnectionNode?.children?.find((child) => child.type === "group-tablespaces");
return {
id: `${connectionId}:__xugu_tablespaces`,
label: "tree.xuguTablespaces",
type: "group-tablespaces",
connectionId,
// SYS_TABLESPACES/SYS_DATAFILES are scoped to the current database. The
// optional value lets the agent switch to the configured database while
// retaining compatibility with connections that have no default DB.
database: config?.database || "",
objectCount: existing?.objectCount,
isExpanded: existing?.isExpanded ?? false,
children: existing?.children ?? [],
};
}
function withConnectionUtilityNodes(connectionId: string, children: TreeNode[], existingConnectionNode?: TreeNode): TreeNode[] {
const nonUtilityChildren = connectionMetadataChildren(children);
const userAdminNode = buildUserAdminNode(connectionId, existingConnectionNode);
const damengUserNode = buildDamengUserNode(connectionId, existingConnectionNode);
const damengRoleNode = buildDamengRoleNode(connectionId, existingConnectionNode);
const damengJobAdminNode = buildDamengJobAdminNode(connectionId, existingConnectionNode);
return [...nonUtilityChildren, userAdminNode, damengUserNode, damengRoleNode, damengJobAdminNode].filter(Boolean) as TreeNode[];
const xuguTablespacesNode = buildXuguTablespacesNode(connectionId, existingConnectionNode);
return [...nonUtilityChildren, userAdminNode, damengUserNode, damengRoleNode, damengJobAdminNode, xuguTablespacesNode].filter(Boolean) as TreeNode[];
}
function withSavedSqlRoot(connectionId: string, children: TreeNode[], existingConnectionNode?: TreeNode): TreeNode[] {
@@ -4137,6 +4158,50 @@ export const useConnectionStore = defineStore("connection", () => {
{ flush: "post" },
);
async function loadXuguTablespaces(node: TreeNode, options?: LoadTreeOptions) {
if (node.type !== "group-tablespaces" || !node.connectionId) return;
const connectionId = node.connectionId;
const config = getConfig(connectionId);
if (effectiveDatabaseTypeForConnection(config) !== "xugu") return;
return runTreeMetadataLoad(
{
kind: "xugu-tablespaces",
connectionId,
database: node.database || undefined,
driverProfile: metadataDriverProfile(config),
},
async () => {
let load = beginTreeNodeLoad(node);
try {
await ensureConnected(connectionId);
load = reclaimTreeNodeLoad(load, node);
if (useCachedChildren(node, options, load)) return;
const tablespaces = await withMetadataLoadTimeout(connectionId, api.listXuguTablespaces(connectionId, node.database || undefined), "Xugu tablespaces");
const targetNode = treeNodeLoadTarget(load);
if (!targetNode) return;
const children = buildXuguTablespaceChildren(targetNode, tablespaces);
setChildren(targetNode, children);
targetNode.objectCount = children.length;
targetNode.isExpanded = true;
} catch (error) {
// Storage metadata is an optional, read-only enhancement. A user
// without SYS_* view access should see an empty group rather than a
// connection-level RPC error that blocks the rest of the tree.
console.debug("[DBX][xugu-tablespaces:unavailable]", { connectionId, error });
const targetNode = treeNodeLoadTarget(load);
if (targetNode) {
setChildren(targetNode, []);
targetNode.objectCount = 0;
targetNode.isExpanded = true;
}
} finally {
finishTreeNodeLoad(load);
}
},
options,
);
}
async function loadDatabases(connectionId: string, options?: LoadTreeOptions) {
const configForScope = getConfig(connectionId);
const searchFilter = activeTreeLoadSearchFilter(options);
@@ -6549,6 +6614,8 @@ export const useConnectionStore = defineStore("connection", () => {
node.isExpanded = true;
} else if (node.type === "doris-catalog" && node.connectionId) {
await loadDorisCatalogDatabases(node, options);
} else if (node.type === "group-tablespaces" && node.connectionId) {
await loadXuguTablespaces(node, options);
} else if (node.type === "database" && node.connectionId && hasTreeNodeDatabaseContext(node)) {
if (node.catalog && node.catalog !== "internal") {
await loadDorisCatalogTables(node, options);
@@ -8863,6 +8930,7 @@ export const useConnectionStore = defineStore("connection", () => {
loadObjectGroupChildren,
loadCustomTypeChildren,
loadPackageMembers,
loadXuguTablespaces,
loadXuguTypeMembers,
loadMoreObjectGroupChildren,
loadAllObjectGroupChildren,