Skip to content

Commit fd48645

Browse files
shantanu patilclaude
authored andcommitted
fix: Explorer depth toggle, hover edge labels, and view tab filtering
- Remap depth buttons (Overview=1, Detailed=3, Full=Infinity) so Overview shows core architecture instead of isolated actor nodes - Move edge labels to hover-only with tooltip styling and wider hit area to eliminate label overlap/clutter - Filter edges by selectedView: Architecture=all, Data Flow=data_flow, Dependencies=dependency+api_call, with orphan node pruning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e4caae3 commit fd48645

3 files changed

Lines changed: 62 additions & 17 deletions

File tree

src/app/[owner]/[repo]/explore/page.tsx

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,8 @@ export default function ExplorePage() {
122122
const mergedDiagram = useMemo<DiagramData | null>(() => {
123123
if (allDiagrams.length === 0) return null;
124124

125-
// For now merge all diagrams. In future, filter by view type.
126125
const mergedNodes = new Map<string, DiagramData['nodes'][0]>();
127-
const mergedEdges: DiagramData['edges'] = [];
126+
const allEdges: DiagramData['edges'] = [];
128127
const edgeKeys = new Set<string>();
129128

130129
for (const diagram of allDiagrams) {
@@ -137,18 +136,47 @@ export default function ExplorePage() {
137136
const key = `${edge.source}->${edge.target}:${edge.type}`;
138137
if (!edgeKeys.has(key)) {
139138
edgeKeys.add(key);
140-
mergedEdges.push(edge);
139+
allEdges.push(edge);
141140
}
142141
}
143142
}
144143

144+
// Filter edges based on selected view
145+
let filteredEdges: DiagramData['edges'];
146+
switch (selectedView) {
147+
case 'dataflow':
148+
filteredEdges = allEdges.filter((e) => e.type === 'data_flow');
149+
break;
150+
case 'dependencies':
151+
filteredEdges = allEdges.filter((e) => e.type === 'dependency' || e.type === 'api_call');
152+
break;
153+
default: // architecture — show everything
154+
filteredEdges = allEdges;
155+
break;
156+
}
157+
158+
// For filtered views, prune orphan nodes (keep connected + depth-0 for context)
159+
let finalNodes: DiagramData['nodes'][0][];
160+
if (selectedView !== 'architecture') {
161+
const connectedIds = new Set<string>();
162+
for (const edge of filteredEdges) {
163+
connectedIds.add(edge.source);
164+
connectedIds.add(edge.target);
165+
}
166+
finalNodes = Array.from(mergedNodes.values()).filter(
167+
(n) => connectedIds.has(n.id) || n.depth === 0,
168+
);
169+
} else {
170+
finalNodes = Array.from(mergedNodes.values());
171+
}
172+
145173
return {
146-
nodes: Array.from(mergedNodes.values()),
147-
edges: mergedEdges,
174+
nodes: finalNodes,
175+
edges: filteredEdges,
148176
mermaidSource: allDiagrams[0]?.mermaidSource ?? '',
149177
diagramType: allDiagrams[0]?.diagramType ?? 'flowchart',
150178
};
151-
}, [allDiagrams]);
179+
}, [allDiagrams, selectedView]);
152180

153181
// Look up the selected node info for the detail panel
154182
const selectedNodeInfo = useMemo(() => {
@@ -290,9 +318,9 @@ export default function ExplorePage() {
290318
<div className="shrink-0 flex items-center justify-center px-4 py-2 border-t border-gray-200 dark:border-zinc-800 bg-white dark:bg-zinc-900">
291319
<div className="flex items-center gap-1 bg-gray-100 dark:bg-zinc-800 rounded-lg p-0.5">
292320
{[
293-
{ depth: 0, label: 'Overview' },
294-
{ depth: 1, label: 'Detailed' },
295-
{ depth: 2, label: 'Full' },
321+
{ depth: 1, label: 'Overview' },
322+
{ depth: 3, label: 'Detailed' },
323+
{ depth: Infinity, label: 'Full' },
296324
].map(({ depth, label }) => (
297325
<button
298326
key={depth}

src/components/explorer/ExplorerEdge.tsx

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React, { memo } from 'react';
3+
import React, { memo, useState } from 'react';
44
import {
55
BaseEdge,
66
EdgeLabelRenderer,
@@ -16,10 +16,13 @@ function ExplorerEdgeComponent({
1616
targetY,
1717
sourcePosition,
1818
targetPosition,
19-
label,
2019
style,
2120
animated,
21+
data,
2222
}: EdgeProps) {
23+
const [hovered, setHovered] = useState(false);
24+
const label = (data as Record<string, unknown> | undefined)?.label as string | undefined;
25+
2326
const [edgePath, labelX, labelY] = getBezierPath({
2427
sourceX,
2528
sourceY,
@@ -29,20 +32,35 @@ function ExplorerEdgeComponent({
2932
targetPosition,
3033
});
3134

35+
const edgeStyle = hovered
36+
? { ...style, strokeWidth: 2.5 }
37+
: style;
38+
3239
return (
3340
<>
41+
{/* Invisible wider path for easier hover targeting */}
42+
<path
43+
d={edgePath}
44+
fill="none"
45+
stroke="transparent"
46+
strokeWidth={20}
47+
onMouseEnter={() => setHovered(true)}
48+
onMouseLeave={() => setHovered(false)}
49+
/>
3450
<BaseEdge
3551
id={id}
3652
path={edgePath}
37-
style={style}
53+
style={edgeStyle}
3854
className={animated ? 'react-flow__edge-path animated' : ''}
3955
/>
40-
{label && (
56+
{label && hovered && (
4157
<EdgeLabelRenderer>
4258
<div
43-
className="absolute text-[10px] font-medium text-gray-500 dark:text-gray-400 bg-white dark:bg-zinc-900 px-1.5 py-0.5 rounded border border-gray-200 dark:border-zinc-700 pointer-events-none"
59+
className="absolute text-[10px] font-medium text-gray-700 dark:text-gray-200 bg-white dark:bg-zinc-800 px-2 py-1 rounded-md border border-gray-200 dark:border-zinc-600 shadow-lg"
4460
style={{
4561
transform: `translate(-50%, -50%) translate(${labelX}px,${labelY}px)`,
62+
zIndex: 1000,
63+
pointerEvents: 'none',
4664
}}
4765
>
4866
{label}

src/lib/diagramToReactFlow.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function diagramDataToReactFlow(
7272
data: DiagramData,
7373
options?: ConvertOptions,
7474
): { nodes: Node[]; edges: Edge[] } {
75-
const maxDepth = options?.maxDepth ?? 2;
75+
const maxDepth = options?.maxDepth ?? Infinity;
7676

7777
// 1. Filter nodes by depth
7878
const filteredNodes = data.nodes.filter((n) => n.depth <= maxDepth);
@@ -103,10 +103,9 @@ export function diagramDataToReactFlow(
103103
source: e.source,
104104
target: e.target,
105105
type: 'explorer',
106-
label: e.label ?? undefined,
107106
animated: style.animated,
108107
style: { stroke: style.stroke, strokeWidth: 1.5 },
109-
data: { edgeType: e.type },
108+
data: { edgeType: e.type, label: e.label ?? undefined },
110109
};
111110
});
112111

0 commit comments

Comments
 (0)