@@ -68,37 +68,39 @@ export default function Terminal() {
6868 } ;
6969 } , [ isFullscreen ] ) ;
7070
71- // Pin the instance so a background refetch can't silently move us to another pod.
72- useEffect ( ( ) => {
73- if ( ! data ) return ;
74- if ( data . data . length === 0 ) return ;
75- setSelectedPod ( ( prev ) => {
76- if ( prev && data . data . some ( ( p ) => p . kubernetes_name === prev ) ) return prev ;
77- return ( data . data . find ( ( p ) => p . instances . some ( ( i ) => i . ready ) ) ?? data . data [ 0 ] )
78- . kubernetes_name ;
79- } ) ;
80- } , [ data ] ) ;
71+ // `selectedPod`/`selectedContainer` are *user overrides* layered on top of a derived default —
72+ // never the source of truth that has to be populated before anything renders. Resolving the
73+ // active pod/container purely during render means there's no frame where `data` exists but the
74+ // selection hasn't "caught up" yet, which is what used to flash the empty state.
75+ const pinnedPodRef = useRef < string | null > ( null ) ;
8176
8277 const activePod = useMemo ( ( ) => {
83- if ( ! selectedPod || ! data ) return undefined ;
84- return (
85- data . data . find ( ( p ) => p . kubernetes_name === selectedPod ) ??
86- data . data . find ( ( p ) => p . instances . some ( ( i ) => i . ready ) ) ??
87- data . data [ 0 ]
88- ) ;
78+ if ( ! data || data . data . length === 0 ) return undefined ;
79+ // 1. explicit user selection, if it still exists
80+ if ( selectedPod ) {
81+ const match = data . data . find ( ( p ) => p . kubernetes_name === selectedPod ) ;
82+ if ( match ) return match ;
83+ }
84+ // 2. the pod we previously resolved to, so a background refetch can't silently move us
85+ if ( pinnedPodRef . current ) {
86+ const match = data . data . find ( ( p ) => p . kubernetes_name === pinnedPodRef . current ) ;
87+ if ( match ) return match ;
88+ }
89+ // 3. first ready pod, else first pod
90+ return data . data . find ( ( p ) => p . instances . some ( ( i ) => i . ready ) ) ?? data . data [ 0 ] ;
8991 } , [ data , selectedPod ] ) ;
9092
93+ // Cache the resolved pod for the pin above. This only writes a ref — it never gates rendering,
94+ // so it can't reintroduce the empty-state flash.
95+ useEffect ( ( ) => {
96+ if ( activePod ) pinnedPodRef . current = activePod . kubernetes_name ;
97+ } , [ activePod ] ) ;
98+
9199 const containers = useMemo ( ( ) => {
92100 if ( ! activePod ) return undefined ;
93101 return activePod . instances . map ( ( i ) => i . kubernetes_name ) ;
94102 } , [ activePod ] ) ;
95103
96- useEffect ( ( ) => {
97- if ( ! containers ) return ;
98- if ( containers . length === 0 ) return ;
99- setSelectedContainer ( ( prev ) => ( prev && containers . includes ( prev ) ? prev : containers [ 0 ] ) ) ;
100- } , [ containers ] ) ;
101-
102104 const activeContainer = useMemo ( ( ) => {
103105 if ( ! containers || containers . length === 0 ) return ;
104106 if ( selectedContainer && containers . includes ( selectedContainer ) ) return selectedContainer ;
0 commit comments