@@ -44,6 +44,11 @@ const LAYOUT_CONFIG = {
4444const DEFAULT_VISIBLE_COUNT = 15
4545
4646function getLayoutedElements ( nodes : Node [ ] , edges : Edge [ ] ) {
47+ // Guard: if no nodes, return empty
48+ if ( nodes . length === 0 ) {
49+ return { nodes : [ ] , edges : [ ] }
50+ }
51+
4752 const dagreGraph = new dagre . graphlib . Graph ( )
4853 dagreGraph . setDefaultEdgeLabel ( ( ) => ( { } ) )
4954 dagreGraph . setGraph ( {
@@ -59,19 +64,26 @@ function getLayoutedElements(nodes: Node[], edges: Edge[]) {
5964 } )
6065 } )
6166
67+ // Only add edges where both source and target exist in nodes
68+ const nodeIds = new Set ( nodes . map ( n => n . id ) )
6269 edges . forEach ( ( edge ) => {
63- dagreGraph . setEdge ( edge . source , edge . target )
70+ if ( nodeIds . has ( edge . source ) && nodeIds . has ( edge . target ) ) {
71+ dagreGraph . setEdge ( edge . source , edge . target )
72+ }
6473 } )
6574
6675 dagre . layout ( dagreGraph )
6776
6877 const layoutedNodes = nodes . map ( ( node ) => {
6978 const nodeWithPosition = dagreGraph . node ( node . id )
79+ // Guard: if dagre failed to position node, use fallback
80+ const x = nodeWithPosition ?. x ?? 0
81+ const y = nodeWithPosition ?. y ?? 0
7082 return {
7183 ...node ,
7284 position : {
73- x : nodeWithPosition . x - LAYOUT_CONFIG . nodeWidth / 2 ,
74- y : nodeWithPosition . y - LAYOUT_CONFIG . nodeHeight / 2 ,
85+ x : x - LAYOUT_CONFIG . nodeWidth / 2 ,
86+ y : y - LAYOUT_CONFIG . nodeHeight / 2 ,
7587 } ,
7688 }
7789 } )
@@ -252,14 +264,12 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
252264 const fileName = node . label || node . id . split ( '/' ) . pop ( )
253265 const metrics = impact . getFileMetrics ( node . id )
254266
267+ // Simplified state - only highlight, don't dim
255268 let state : GraphNodeData [ 'state' ] = 'default'
256269 if ( effectiveSelectedIdCluster === node . id ) state = 'selected'
257270 else if ( selectedImpact ?. directDependents . includes ( node . id ) ) state = 'direct'
258271 else if ( selectedImpact ?. transitiveDependents . includes ( node . id ) ) state = 'transitive'
259- else if ( effectiveSelectedIdCluster && ! effectiveSelectedIdCluster . startsWith ( 'dir:' ) ) state = 'dimmed'
260-
261- // Hover highlighting in clustered mode
262- if ( hoveredFileId === node . id && state === 'dimmed' ) state = 'direct'
272+ // Don't dim - keep as default
263273
264274 flowNodes . push ( {
265275 id : node . id ,
@@ -298,16 +308,15 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
298308 const fileName = node . label || node . id . split ( '/' ) . pop ( )
299309 const metrics = impact . getFileMetrics ( node . id )
300310
311+ // Simplified state - only highlight selected and dependents, don't dim others
301312 let state : GraphNodeData [ 'state' ] = 'default'
302313 if ( effectiveSelectedId ) {
303314 if ( node . id === effectiveSelectedId ) state = 'selected'
304315 else if ( selectedImpact ?. directDependents . includes ( node . id ) ) state = 'direct'
305316 else if ( selectedImpact ?. transitiveDependents . includes ( node . id ) ) state = 'transitive'
306- else state = 'dimmed'
317+ // Don't dim - keep as default for visibility
307318 }
308319
309- if ( hoveredFileId === node . id && state === 'dimmed' ) state = 'direct'
310-
311320 return {
312321 id : node . id ,
313322 type : 'custom' ,
@@ -328,11 +337,12 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
328337 flowEdges = rawGraphData . edges
329338 . filter ( ( edge : any ) => visibleNodeIds . has ( edge . source ) && visibleNodeIds . has ( edge . target ) )
330339 . map ( ( edge : any ) => {
340+ // Simplified - only highlight connected edges, don't dim others
331341 let edgeState : 'default' | 'highlighted' | 'dimmed' | 'incoming' | 'outgoing' = 'default'
332342 if ( effectiveSelectedId ) {
333343 if ( edge . source === effectiveSelectedId ) edgeState = 'outgoing'
334344 else if ( edge . target === effectiveSelectedId ) edgeState = 'incoming'
335- else edgeState = 'dimmed'
345+ // Don't dim - keep as default
336346 }
337347
338348 return {
0 commit comments