fix(sidebar): hide connection utility nodes in search results

This commit is contained in:
Terry Yao
2026-09-22 16:26:12 +08:00
committed by GitHub
parent 69b43cf401
commit 933ed6a670
2 changed files with 123 additions and 3 deletions
@@ -4,7 +4,14 @@ import { buildTableTreeNodes } from "@/lib/table/tableTree";
import { stripTableVGroupsFromChildren } from "@/lib/table/tableVGroup";
const preserveMatchedSubtreeTypes = new Set(["connection", "database", "schema", "table", "view", "mongo-db", "mongo-collection"]);
const hiddenSearchNodeTypes = new Set<TreeNodeType>(["user-admin", "dameng-job-admin"]);
// Synthetic connection utility entries (the isConnectionUtilityNode types in
// connectionStore) are admin/navigation shortcuts, not schema objects. Their
// labels are i18n keys that can never match a text query, so they never
// self-match — but a few of them (oracle-db-links, group-tablespaces) are
// groups whose children ARE real objects, so their children stay searchable
// and the group only survives through a child hit. saved-sql-root is exempt:
// its saved queries are real searchable files rather than a shortcut.
const hiddenSearchNodeTypes = new Set<TreeNodeType>(["user-admin", "dameng-users", "dameng-roles", "dameng-job-admin", "group-tablespaces", "oracle-db-links"]);
function bestMatch(matchLabel: SidebarLabelMatcher, label: string, comment?: string | null, aliases?: readonly string[]) {
let best = matchLabel(label);
@@ -360,7 +367,11 @@ function filterSidebarTreeWithMatcher(nodes: TreeNode[], matchLabel: SidebarLabe
const filteredNodes: { node: TreeNode; score: number }[] = [];
for (const node of nodes) {
if (matchLabel && hiddenSearchNodeTypes.has(node.type)) continue;
// Utility groups never match by their own label; groups without children
// (or not yet loaded) drop out entirely, while groups that hold real
// objects (db links, tablespaces) survive through a matching child.
const hiddenUtility = !!matchLabel && hiddenSearchNodeTypes.has(node.type);
if (hiddenUtility && !node.children?.length) continue;
if (node.type === "object-browser" && node.hiddenChildren) {
const matches = node.hiddenChildren.flatMap((child) => {
if (searchableNodeTypes && !searchableNodeTypes.has(child.type)) return [];
@@ -373,7 +384,7 @@ function filterSidebarTreeWithMatcher(nodes: TreeNode[], matchLabel: SidebarLabe
}
const label = normalizedLabel(node, resolveLabel);
const canSelfMatch = !searchableNodeTypes || searchableNodeTypes.has(node.type);
const canSelfMatch = (!searchableNodeTypes || searchableNodeTypes.has(node.type)) && !hiddenUtility;
const selfMatch = canSelfMatch ? (matchLabel ? bestMatch(matchLabel, label, node.comment, node.searchAliases) : { score: 0 }) : null;
// Type-only filtering keeps matching rows and their ancestor path, but not
// unrelated descendants that would make the selected type appear ignored.
+109
View File
@@ -318,6 +318,20 @@ test("omits synthetic connection management entries when the connection itself m
connectionId: "conn:1",
database: "",
},
{
id: "conn:1:__dameng_users",
label: "tree.damengUsers",
type: "dameng-users",
connectionId: "conn:1",
database: "",
},
{
id: "conn:1:__dameng_roles",
label: "tree.damengRoles",
type: "dameng-roles",
connectionId: "conn:1",
database: "",
},
{
id: "conn:1:__dameng_jobs",
label: "tree.damengJobAdmin",
@@ -325,6 +339,20 @@ test("omits synthetic connection management entries when the connection itself m
connectionId: "conn:1",
database: "",
},
{
id: "conn:1:__xugu_tablespaces",
label: "tree.xuguTablespaces",
type: "group-tablespaces",
connectionId: "conn:1",
database: "",
},
{
id: "conn:1:__oracle_db_links",
label: "tree.databaseLinks",
type: "oracle-db-links",
connectionId: "conn:1",
database: "",
},
],
},
];
@@ -354,6 +382,14 @@ test("keeps a disconnected connection search result collapsed when it only has s
connectionId: "conn:1",
database: "",
},
{
id: "conn:1:__oracle_db_links",
label: "tree.databaseLinks",
type: "oracle-db-links",
connectionId: "conn:1",
database: "",
children: [],
},
],
},
];
@@ -364,6 +400,79 @@ test("keeps a disconnected connection search result collapsed when it only has s
assert.equal(filtered[0]?.isExpanded, false);
});
test("keeps utility groups searchable through their real object children", () => {
const nodes: TreeNode[] = [
{
id: "conn:1",
label: "prod",
type: "connection",
connectionId: "conn:1",
isExpanded: true,
children: [
{
id: "conn:1:__oracle_db_links",
label: "tree.databaseLinks",
type: "oracle-db-links",
connectionId: "conn:1",
database: "",
children: [
{
id: "conn:1:__oracle_db_links:reporting",
label: "REPORTING.LOCALDOMAIN",
type: "oracle-db-link",
connectionId: "conn:1",
database: "",
},
],
},
],
},
];
const filtered = filterSidebarTree(nodes, "reporting", new Set());
assert.equal(filtered[0]?.type, "connection");
assert.deepEqual(
filtered[0]?.children?.map((child) => child.type),
["oracle-db-links"],
);
assert.equal(filtered[0]?.children?.[0]?.children?.[0]?.label, "REPORTING.LOCALDOMAIN");
});
test("drops utility groups whose children do not match the query", () => {
const nodes: TreeNode[] = [
{
id: "conn:1",
label: "prod",
type: "connection",
connectionId: "conn:1",
isExpanded: true,
children: [
{
id: "conn:1:__xugu_tablespaces",
label: "tree.xuguTablespaces",
type: "group-tablespaces",
connectionId: "conn:1",
database: "",
children: [
{
id: "conn:1:__xugu_tablespaces:system",
label: "SYSTEM",
type: "tablespace",
connectionId: "conn:1",
database: "",
},
],
},
],
},
];
const filtered = filterSidebarTree(nodes, "reporting", new Set());
assert.deepEqual(filtered, []);
});
test("does not return synthetic connection management entries as direct text matches", () => {
const nodes: TreeNode[] = [
{