diff --git a/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue b/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue index a26102a200..8d81d1d2e1 100644 --- a/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue +++ b/apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue @@ -64,6 +64,7 @@ import type { ColumnInfo, DatabaseType, TreeNode, TreeNodeType } from "@/types/d import * as api from "@/lib/backend/api"; import { resolveDefaultDatabase } from "@/lib/database/defaultDatabase"; import { canTreeNodePin, canTreeNodeShowExpander } from "@/lib/sidebar/sidebarTreeItemLayout"; +import { objectTypesForGroupNode } from "@/lib/table/tableTree"; import { buildTableDeleteTemplate, buildTableInsertTemplate, buildTableSelectTemplate, buildTableUpdateTemplate } from "@/lib/table/tableSqlTemplates"; import { driverStoreFocusForInstallError } from "@/lib/connection/agentDriverInstallHint"; import { @@ -493,7 +494,10 @@ async function toggle() { return; } - const databaseObjectGroup = node.type === "group-tables" || node.type === "group-views" || node.type === "group-materialized-views" || node.type === "group-procedures" || node.type === "group-functions" || node.type === "group-sequences" || node.type === "group-packages"; + // Keep the click path aligned with every object-group definition. In + // particular, schema-level trigger/type groups have no tableName, so they + // must use the generic object loader rather than the table-trigger loader. + const databaseObjectGroup = !!objectTypesForGroupNode(node.type); if (databaseObjectGroup && connectionStore.isTreeNodeChildrenLoaded(node.id)) { node.isExpanded = !node.isExpanded; if (wasExpanded && !connectionStore.sidebarSearchQuery) connectionStore.releaseCollapsedTreeNodeChildren(node.id); diff --git a/apps/desktop/src/stores/connectionStore.ts b/apps/desktop/src/stores/connectionStore.ts index 5795f830b8..8fd437a02c 100644 --- a/apps/desktop/src/stores/connectionStore.ts +++ b/apps/desktop/src/stores/connectionStore.ts @@ -3978,7 +3978,7 @@ export const useConnectionStore = defineStore("connection", () => { await loadForeignKeys(node.connectionId, node.database, node.tableName, node.schema, node.id, node.catalog); } else if (node.type === "group-triggers" && node.connectionId && hasTreeNodeDatabaseContext(node) && node.tableName) { await loadTriggers(node.connectionId, node.database, node.tableName, node.schema, node.id, node.catalog); - } else if (node.type === "group-tables" || node.type === "group-views" || node.type === "group-materialized-views" || node.type === "group-procedures" || node.type === "group-functions" || node.type === "group-sequences" || node.type === "group-packages") { + } else if (objectTypesForGroupNode(node.type)) { await loadObjectGroupChildren(node, options); } else if (node.type === "group-partitions") { node.isExpanded = true; diff --git a/packages/app-tests/sidebarTreeAffordances.test.ts b/packages/app-tests/sidebarTreeAffordances.test.ts index 2d729b3187..2c8a5c54f6 100644 --- a/packages/app-tests/sidebarTreeAffordances.test.ts +++ b/packages/app-tests/sidebarTreeAffordances.test.ts @@ -5,6 +5,7 @@ import { test } from "vitest"; const treeItem = readFileSync("apps/desktop/src/components/sidebar/TreeItem.vue", "utf8"); const runtimeHost = readFileSync("apps/desktop/src/components/sidebar/SidebarTreeRuntimeHost.vue", "utf8"); const connectionTree = readFileSync("apps/desktop/src/components/sidebar/ConnectionTree.vue", "utf8"); +const connectionStore = readFileSync("apps/desktop/src/stores/connectionStore.ts", "utf8"); test("sidebar rows retain database-specific node affordances", () => { for (const nodeType of ["connection", "database", "schema", "table", "column", "mongo-db", "mongo-collection", "redis-db", "nacos-namespace", "mq-tenant"]) { @@ -24,3 +25,8 @@ test("complex tree changes retain the full rebuild fallback", () => { assert.match(connectionTree, /flattenTree\(filteredNodes\.value\)/); assert.match(connectionTree, /watch\(flatNodes,/); }); + +test("programmable object groups use the shared metadata loader", () => { + assert.match(runtimeHost, /const databaseObjectGroup = !!objectTypesForGroupNode\(node\.type\)/); + assert.match(connectionStore, /else if \(objectTypesForGroupNode\(node\.type\)\) \{\s*await loadObjectGroupChildren\(node, options\);/); +});