fix(graph): address review — reachFrom direct edges + node a11y

- reachFrom now returns the direct outbound edges PLUS the recursive
  $graphLookup reaches, de-duped by edge id, with maxDepth to bound cycles.
  It was dropping edges straight off the start node. [review P2]
- GraphView SVG nodes are keyboard-accessible: role/tabIndex/aria-label +
  Enter/Space handler alongside onClick. [review P3]

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
sb-iam
2026-06-27 17:56:47 -07:00
parent 546aeeed70
commit 32bff6a3ab
2 changed files with 27 additions and 2 deletions
+18 -2
View File
@@ -70,7 +70,7 @@ export async function reachFrom(podId: string, startNodeId: string): Promise<Rea
const db = await getDb();
const rows = await db
.collection<GraphEdgeDoc>('graph_edges')
.aggregate<{ reaches: GraphEdgeDoc[] }>([
.aggregate<GraphEdgeDoc & { reaches: GraphEdgeDoc[] }>([
{ $match: { podId, source: startNodeId } },
{
$graphLookup: {
@@ -80,9 +80,25 @@ export async function reachFrom(podId: string, startNodeId: string): Promise<Rea
connectToField: 'source',
as: 'reaches',
restrictSearchWithMatch: { podId },
maxDepth: 6,
},
},
])
.toArray();
return { start: startNodeId, reaches: rows.flatMap((r) => r.reaches) };
// Include the direct outbound edges (the $match rows) plus everything reachable
// from them, de-duped by edge id. Without the direct rows, edges straight off
// the start node go missing unless a cycle happens to re-discover them.
const seen = new Set<string>();
const reaches: GraphEdgeDoc[] = [];
for (const row of rows) {
const { reaches: recursive, ...direct } = row;
for (const edge of [direct as GraphEdgeDoc, ...(recursive ?? [])]) {
if (edge?.id && !seen.has(edge.id)) {
seen.add(edge.id);
reaches.push(edge);
}
}
}
return { start: startNodeId, reaches };
}