@@ -14,6 +14,100 @@ import * as jotai from "jotai";
1414import { OverlayScrollbarsComponent } from "overlayscrollbars-react" ;
1515import * as React from "react" ;
1616
17+ function formatElapsedTime ( elapsedMs : number ) : string {
18+ if ( elapsedMs <= 0 ) {
19+ return "" ;
20+ }
21+
22+ const elapsedSeconds = Math . floor ( elapsedMs / 1000 ) ;
23+
24+ if ( elapsedSeconds < 60 ) {
25+ return `${ elapsedSeconds } s` ;
26+ }
27+
28+ const elapsedMinutes = Math . floor ( elapsedSeconds / 60 ) ;
29+ if ( elapsedMinutes < 60 ) {
30+ return `${ elapsedMinutes } m` ;
31+ }
32+
33+ const elapsedHours = Math . floor ( elapsedMinutes / 60 ) ;
34+ const remainingMinutes = elapsedMinutes % 60 ;
35+
36+ if ( elapsedHours < 24 ) {
37+ if ( remainingMinutes === 0 ) {
38+ return `${ elapsedHours } h` ;
39+ }
40+ return `${ elapsedHours } h${ remainingMinutes } m` ;
41+ }
42+
43+ return "more than a day" ;
44+ }
45+
46+ const StalledOverlay = React . memo (
47+ ( {
48+ connName,
49+ connStatus,
50+ overlayRefCallback,
51+ } : {
52+ connName : string ;
53+ connStatus : ConnStatus ;
54+ overlayRefCallback : ( el : HTMLDivElement | null ) => void ;
55+ } ) => {
56+ const [ elapsedTime , setElapsedTime ] = React . useState < string > ( "" ) ;
57+
58+ const handleDisconnect = React . useCallback ( ( ) => {
59+ const prtn = RpcApi . ConnDisconnectCommand ( TabRpcClient , connName , { timeout : 5000 } ) ;
60+ prtn . catch ( ( e ) => console . log ( "error disconnecting" , connName , e ) ) ;
61+ } , [ connName ] ) ;
62+
63+ React . useEffect ( ( ) => {
64+ if ( ! connStatus . lastactivitybeforestalledtime ) {
65+ return ;
66+ }
67+
68+ const updateElapsed = ( ) => {
69+ const now = Date . now ( ) ;
70+ const lastActivity = connStatus . lastactivitybeforestalledtime ! ;
71+ const elapsed = now - lastActivity ;
72+ setElapsedTime ( formatElapsedTime ( elapsed ) ) ;
73+ } ;
74+
75+ updateElapsed ( ) ;
76+ const interval = setInterval ( updateElapsed , 1000 ) ;
77+
78+ return ( ) => clearInterval ( interval ) ;
79+ } , [ connStatus . lastactivitybeforestalledtime ] ) ;
80+
81+ return (
82+ < div
83+ className = "@container absolute top-[calc(var(--header-height)+6px)] left-1.5 right-1.5 z-[var(--zindex-block-mask-inner)] overflow-hidden rounded-md bg-[var(--conn-status-overlay-bg-color)] backdrop-blur-[50px] shadow-lg opacity-85"
84+ ref = { overlayRefCallback }
85+ >
86+ < div className = "flex items-center gap-3 w-full pt-2.5 pb-2.5 pr-2 pl-3" >
87+ < i
88+ className = "fa-solid fa-triangle-exclamation text-warning text-base shrink-0"
89+ title = "Connection Stalled"
90+ > </ i >
91+ < div className = "text-[11px] font-semibold leading-4 tracking-[0.11px] text-white min-w-0 flex-1 break-words @max-xxs:hidden" >
92+ Connection to "{ connName } " is stalled
93+ { elapsedTime && ` (no activity for ${ elapsedTime } )` }
94+ </ div >
95+ < div className = "flex-1 hidden @max-xxs:block" > </ div >
96+ < Button
97+ className = "outlined grey text-[11px] py-[3px] px-[7px] @max-w350:text-[12px] @max-w350:py-[5px] @max-w350:px-[6px]"
98+ onClick = { handleDisconnect }
99+ title = "Disconnect"
100+ >
101+ < span className = "@max-w350:hidden!" > Disconnect</ span >
102+ < i className = "fa-solid fa-link-slash hidden! @max-w350:inline!" > </ i >
103+ </ Button >
104+ </ div >
105+ </ div >
106+ ) ;
107+ }
108+ ) ;
109+ StalledOverlay . displayName = "StalledOverlay" ;
110+
17111export const ConnStatusOverlay = React . memo (
18112 ( {
19113 nodeModel,
@@ -121,10 +215,17 @@ export const ConnStatusOverlay = React.memo(
121215 [ showError , showWshError , connStatus . error , connStatus . wsherror ]
122216 ) ;
123217
124- if ( ! showWshError && ( isLayoutMode || connStatus . status == "connected" || connModalOpen ) ) {
218+ let showStalled = connStatus . status == "connected" && connStatus . connhealthstatus == "stalled" ;
219+ if ( ! showWshError && ! showStalled && ( isLayoutMode || connStatus . status == "connected" || connModalOpen ) ) {
125220 return null ;
126221 }
127222
223+ if ( showStalled && ! showWshError ) {
224+ return (
225+ < StalledOverlay connName = { connName } connStatus = { connStatus } overlayRefCallback = { overlayRefCallback } />
226+ ) ;
227+ }
228+
128229 return (
129230 < div className = "connstatus-overlay" ref = { overlayRefCallback } >
130231 < div className = "connstatus-content" >
0 commit comments