@@ -1519,6 +1519,23 @@ export function App() {
15191519 const streamSessionEventCountRef = useRef ( 0 ) ;
15201520 const devVerificationStartedRef = useRef ( false ) ;
15211521 const permissionsEndpointAvailableRef = useRef ( true ) ;
1522+ const browserHealthProbeRef = useRef ( null ) ;
1523+ const connectionDialogAutoPromptSuppressedRef = useRef ( false ) ;
1524+
1525+ const openConnectionDialog = useCallback ( ( ) => {
1526+ connectionDialogAutoPromptSuppressedRef . current = false ;
1527+ setShowConnectionDialog ( true ) ;
1528+ } , [ ] ) ;
1529+
1530+ const dismissConnectionDialog = useCallback ( ( ) => {
1531+ connectionDialogAutoPromptSuppressedRef . current = true ;
1532+ setShowConnectionDialog ( false ) ;
1533+ } , [ ] ) ;
1534+
1535+ const closeConnectionDialog = useCallback ( ( ) => {
1536+ connectionDialogAutoPromptSuppressedRef . current = false ;
1537+ setShowConnectionDialog ( false ) ;
1538+ } , [ ] ) ;
15221539
15231540 const changePanel = useCallback ( ( nextPanel ) => {
15241541 if ( ! PANEL_SEQUENCE_KEYS . has ( nextPanel ) || nextPanel === panel ) {
@@ -1880,6 +1897,7 @@ export function App() {
18801897 if ( invokeRef . current ) {
18811898 try {
18821899 const state = { ...EMPTY_DAEMON , ...( await call ( "daemon_status" ) ) } ;
1900+ browserHealthProbeRef . current = null ;
18831901 setDaemonState ( state ) ;
18841902 return state ;
18851903 } catch {
@@ -1890,8 +1908,10 @@ export function App() {
18901908 let health ;
18911909 try {
18921910 health = await api ( "/health" ) ;
1911+ browserHealthProbeRef . current = health || null ;
18931912 } catch {
18941913 // daemon unreachable is an expected state, not an error
1914+ browserHealthProbeRef . current = null ;
18951915 }
18961916 if ( isReachableHealthPayload ( health ) ) {
18971917 const nextState = {
@@ -1928,11 +1948,14 @@ export function App() {
19281948 } , [ api ] ) ;
19291949
19301950 const refreshHealth = useCallback ( async ( ) => {
1931- let health ;
1932- try {
1933- health = await api ( "/health" ) ;
1934- } catch {
1935- // daemon unreachable -- show dashes
1951+ let health = browserHealthProbeRef . current ;
1952+ browserHealthProbeRef . current = null ;
1953+ if ( ! health ) {
1954+ try {
1955+ health = await api ( "/health" ) ;
1956+ } catch {
1957+ // daemon unreachable -- show dashes
1958+ }
19361959 }
19371960 if ( ! health ) {
19381961 const readinessReady = await probeReadiness ( ) ;
@@ -2566,11 +2589,16 @@ export function App() {
25662589 setDaemonTimeoutStaleSummary ( "" ) ;
25672590 clearRecoveryRetry ( ) ;
25682591 setFeedbackMessage ( summarizeDashboardErrors ( unique ) ) ;
2569- if ( ! invokeRef . current && unique . every ( ( error ) => isAuthFailure ( error ) ) ) {
2592+ if (
2593+ ! invokeRef . current
2594+ && unique . every ( ( error ) => isAuthFailure ( error ) )
2595+ && ! connectionDialogAutoPromptSuppressedRef . current
2596+ ) {
25702597 setShowConnectionDialog ( true ) ;
25712598 }
25722599 }
25732600 } else {
2601+ connectionDialogAutoPromptSuppressedRef . current = false ;
25742602 clearRecoveryRetry ( ) ;
25752603 const uniqueSecondary = [ ...new Set ( secondaryErrors ) ] ;
25762604 if ( uniqueSecondary . length ) {
@@ -4007,7 +4035,7 @@ export function App() {
40074035 < span className = "topbar-stat" > < span className = "topbar-label" > DEC</ span > { stats . decisions } </ span >
40084036 < span className = "topbar-stat" > < span className = "topbar-label" > EVT</ span > { stats . events } </ span >
40094037 < span className = "topbar-stat" > < span className = "topbar-label" > AGENTS</ span > { normalizedSessions . length } </ span >
4010- < span className = "topbar-stat topbar-connection" onClick = { ( ) => setShowConnectionDialog ( true ) } title = "Click to change connection" >
4038+ < span className = "topbar-stat topbar-connection" onClick = { openConnectionDialog } title = "Click to change connection" >
40114039 < span className = "topbar-label" > HOST</ span >
40124040 { hostLabel }
40134041 </ span >
@@ -4082,15 +4110,15 @@ export function App() {
40824110 ) }
40834111
40844112 { showConnectionDialog && (
4085- < div className = "connection-overlay" onClick = { ( ) => setShowConnectionDialog ( false ) } >
4113+ < div className = "connection-overlay" onClick = { dismissConnectionDialog } >
40864114 < div className = "connection-dialog" onClick = { e => e . stopPropagation ( ) } >
40874115 < div className = "connection-dialog-header" >
40884116 < h2 > Connection Settings</ h2 >
40894117 < button
40904118 type = "button"
40914119 className = "connection-dialog-close"
40924120 aria-label = "Close connection settings"
4093- onClick = { ( ) => setShowConnectionDialog ( false ) }
4121+ onClick = { dismissConnectionDialog }
40944122 >
40954123 ×
40964124 </ button >
@@ -4106,7 +4134,7 @@ export function App() {
41064134 setCortexBase ( DEFAULT_CORTEX_BASE ) ;
41074135 tokenRef . current = "" ;
41084136 persistBrowserAuthToken ( "" ) ;
4109- setShowConnectionDialog ( false ) ;
4137+ closeConnectionDialog ( ) ;
41104138 queueMicrotask ( ( ) => refreshAllRef . current ( ) ) ;
41114139 return ;
41124140 }
@@ -4117,7 +4145,7 @@ export function App() {
41174145 setCortexBase ( `http://${ host } :${ port } ` ) ;
41184146 tokenRef . current = token || "" ;
41194147 persistBrowserAuthToken ( token || "" ) ;
4120- setShowConnectionDialog ( false ) ;
4148+ closeConnectionDialog ( ) ;
41214149 queueMicrotask ( ( ) => refreshAllRef . current ( ) ) ;
41224150 } } >
41234151 < label className = "connection-field" >
@@ -4152,7 +4180,7 @@ export function App() {
41524180 setCortexBase ( DEFAULT_CORTEX_BASE ) ;
41534181 tokenRef . current = "" ;
41544182 persistBrowserAuthToken ( "" ) ;
4155- setShowConnectionDialog ( false ) ;
4183+ closeConnectionDialog ( ) ;
41564184 readAuthToken ( { suppressFeedback : true } ) ;
41574185 queueMicrotask ( ( ) => refreshAllRef . current ( ) ) ;
41584186 } } > Reset to Local</ button >
0 commit comments