1- import { useEffect , useState , useCallback , useMemo } from 'react'
1+ import { useEffect , useState , useCallback , useMemo , useRef } from 'react'
22import ReactFlow , {
33 Controls ,
44 Background ,
@@ -125,6 +125,7 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
125125 const [ clusterByDir , setClusterByDir ] = useState ( false )
126126 const [ expandedDirs , setExpandedDirs ] = useState < Set < string > > ( new Set ( ) )
127127 const [ rawGraphData , setRawGraphData ] = useState < any > ( null )
128+ const [ renderKey , setRenderKey ] = useState ( 0 ) // Force re-render key
128129
129130 const { fitView } = useReactFlow ( )
130131 const { resolvedTheme } = useTheme ( )
@@ -137,6 +138,23 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
137138 if ( data ) setRawGraphData ( data )
138139 } , [ data ] )
139140
141+ // Handle tab visibility changes - force re-render when tab becomes visible
142+ useEffect ( ( ) => {
143+ const handleVisibilityChange = ( ) => {
144+ if ( document . visibilityState === 'visible' ) {
145+ // Force re-render by updating key
146+ setRenderKey ( k => k + 1 )
147+ // Also trigger fitView after a short delay
148+ setTimeout ( ( ) => {
149+ fitView ( { padding : 0.2 , duration : 200 } )
150+ } , 100 )
151+ }
152+ }
153+
154+ document . addEventListener ( 'visibilitychange' , handleVisibilityChange )
155+ return ( ) => document . removeEventListener ( 'visibilitychange' , handleVisibilityChange )
156+ } , [ fitView ] )
157+
140158 const visibleNodeIds = useMemo ( ( ) => {
141159 if ( ! rawGraphData || ! impact . isReady ) return new Set < string > ( )
142160
@@ -241,14 +259,17 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
241259 let flowNodes : Node [ ] = [ ]
242260 let flowEdges : Edge [ ] = [ ]
243261
244- if ( clusterByDir && clusteredData ) {
262+ // Only use cluster mode if we have clustered data ready
263+ const useClusterMode = clusterByDir && clusteredData && clusteredData . dirNodes . length > 0
264+
265+ if ( useClusterMode ) {
245266 // Safety: only apply selection highlighting if the selected node is actually visible
246267 const effectiveSelectedIdCluster = selectedNodeId &&
247- ( clusteredData . visibleFiles . has ( selectedNodeId ) || selectedNodeId . startsWith ( 'dir:' ) )
268+ ( clusteredData ! . visibleFiles . has ( selectedNodeId ) || selectedNodeId . startsWith ( 'dir:' ) )
248269 ? selectedNodeId : null
249270
250271 // Add directory nodes
251- clusteredData . dirNodes . forEach ( dir => {
272+ clusteredData ! . dirNodes . forEach ( dir => {
252273 flowNodes . push ( {
253274 id : dir . id ,
254275 type : 'directory' ,
@@ -259,7 +280,7 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
259280
260281 // Add visible file nodes
261282 rawGraphData . nodes
262- . filter ( ( node : any ) => clusteredData . visibleFiles . has ( node . id ) )
283+ . filter ( ( node : any ) => clusteredData ! . visibleFiles . has ( node . id ) )
263284 . forEach ( ( node : any ) => {
264285 const fileName = node . label || node . id . split ( '/' ) . pop ( )
265286 const metrics = impact . getFileMetrics ( node . id )
@@ -289,7 +310,7 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
289310 } )
290311
291312 // Add edges
292- clusteredData . edges . forEach ( ( [ source , target ] ) => {
313+ clusteredData ! . edges . forEach ( ( [ source , target ] ) => {
293314 flowEdges . push ( {
294315 id : `${ source } -${ target } ` ,
295316 source,
@@ -360,12 +381,14 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
360381 setEdges ( layoutedEdges )
361382 } , [ rawGraphData , impact . isReady , visibleNodeIds , selectedNodeId , selectedImpact , hoveredFileId , isDark , clusterByDir , clusteredData ] )
362383
384+ // Fit view when nodes change or panel opens/closes
363385 useEffect ( ( ) => {
364386 if ( nodes . length > 0 ) {
365387 const minZoom = nodes . length > 20 ? 0.5 : 0.3
366- setTimeout ( ( ) => fitView ( { padding : 0.2 , duration : 300 , minZoom } ) , 100 )
388+ // Delay to allow container resize when panel opens/closes
389+ setTimeout ( ( ) => fitView ( { padding : 0.2 , duration : 300 , minZoom } ) , 150 )
367390 }
368- } , [ showAll , showTests , clusterByDir , expandedDirs ] )
391+ } , [ nodes . length , selectedNodeId , showAll , showTests , clusterByDir , expandedDirs , fitView ] )
369392
370393 const handleNodeClick = useCallback ( ( _ : any , node : Node ) => {
371394 // Toggle directory expansion
@@ -492,6 +515,7 @@ function DependencyGraphInner({ repoId, apiUrl, apiKey }: DependencyGraphProps)
492515 < div className = "flex overflow-hidden" style = { { height : '600px' } } >
493516 < div className = "relative" style = { { flex : 1 , height : '600px' } } >
494517 < ReactFlow
518+ key = { renderKey }
495519 nodes = { nodes }
496520 edges = { edges }
497521 onNodesChange = { onNodesChange }
0 commit comments