@@ -13,19 +13,146 @@ import {
1313import { useRef , useState } from "react"
1414import Link from "@material-ui/core/Link"
1515
16- const ConnectedStatus : React . FC = ( ) => {
16+ // If we think in the agent status and lifecycle into a single enum/state I’d
17+ // say we would have: connecting, timeout, disconnected, connected:created,
18+ // connected:starting, connected:start_timeout, connected:start_error,
19+ // connected:ready
20+
21+ const ReadyLifeCycle : React . FC = ( ) => {
1722 const styles = useStyles ( )
1823 const { t } = useTranslation ( "workspacePage" )
1924
2025 return (
2126 < div
2227 role = "status"
23- aria-label = { t ( "agentStatus.connected" ) }
28+ aria-label = { t ( "agentStatus.connected.ready " ) }
2429 className = { combineClasses ( [ styles . status , styles . connected ] ) }
2530 />
2631 )
2732}
2833
34+ const StartingLifecycle : React . FC = ( ) => {
35+ const styles = useStyles ( )
36+ const { t } = useTranslation ( "workspacePage" )
37+
38+ return (
39+ < Tooltip title = { t ( "agentStatus.connected.starting" ) } >
40+ < div
41+ role = "status"
42+ aria-label = { t ( "agentStatus.connected.starting" ) }
43+ className = { combineClasses ( [ styles . status , styles . connecting ] ) }
44+ />
45+ </ Tooltip >
46+ )
47+ }
48+
49+ const StartTimeoutLifecycle : React . FC < {
50+ agent : WorkspaceAgent
51+ } > = ( { agent } ) => {
52+ const { t } = useTranslation ( "agent" )
53+ const styles = useStyles ( )
54+ const anchorRef = useRef < SVGSVGElement > ( null )
55+ const [ isOpen , setIsOpen ] = useState ( false )
56+ const id = isOpen ? "timeout-popover" : undefined
57+
58+ return (
59+ < >
60+ < WarningRounded
61+ ref = { anchorRef }
62+ onMouseEnter = { ( ) => setIsOpen ( true ) }
63+ onMouseLeave = { ( ) => setIsOpen ( false ) }
64+ role = "status"
65+ aria-label = { t ( "status.startTimeout" ) }
66+ className = { styles . timeoutWarning }
67+ />
68+ < HelpPopover
69+ id = { id }
70+ open = { isOpen }
71+ anchorEl = { anchorRef . current }
72+ onOpen = { ( ) => setIsOpen ( true ) }
73+ onClose = { ( ) => setIsOpen ( false ) }
74+ >
75+ < HelpTooltipTitle > { t ( "startTimeoutTooltip.title" ) } </ HelpTooltipTitle >
76+ < HelpTooltipText >
77+ { t ( "startTimeoutTooltip.message" ) } { " " }
78+ < Link
79+ target = "_blank"
80+ rel = "noreferrer"
81+ href = { agent . troubleshooting_url }
82+ >
83+ { t ( "startTimeoutTooltip.link" ) }
84+ </ Link >
85+ .
86+ </ HelpTooltipText >
87+ </ HelpPopover >
88+ </ >
89+ )
90+ }
91+
92+ const StartErrorLifecycle : React . FC < {
93+ agent : WorkspaceAgent
94+ } > = ( { agent } ) => {
95+ const { t } = useTranslation ( "agent" )
96+ const styles = useStyles ( )
97+ const anchorRef = useRef < SVGSVGElement > ( null )
98+ const [ isOpen , setIsOpen ] = useState ( false )
99+ const id = isOpen ? "timeout-popover" : undefined
100+
101+ return (
102+ < >
103+ < WarningRounded
104+ ref = { anchorRef }
105+ onMouseEnter = { ( ) => setIsOpen ( true ) }
106+ onMouseLeave = { ( ) => setIsOpen ( false ) }
107+ role = "status"
108+ aria-label = { t ( "status.error" ) }
109+ className = { styles . errorWarning }
110+ />
111+ < HelpPopover
112+ id = { id }
113+ open = { isOpen }
114+ anchorEl = { anchorRef . current }
115+ onOpen = { ( ) => setIsOpen ( true ) }
116+ onClose = { ( ) => setIsOpen ( false ) }
117+ >
118+ < HelpTooltipTitle > { t ( "startErrorTooltip.title" ) } </ HelpTooltipTitle >
119+ < HelpTooltipText >
120+ { t ( "startErrorTooltip.message" ) } { " " }
121+ < Link
122+ target = "_blank"
123+ rel = "noreferrer"
124+ href = { agent . troubleshooting_url }
125+ >
126+ { t ( "startErrorTooltip.link" ) }
127+ </ Link >
128+ .
129+ </ HelpTooltipText >
130+ </ HelpPopover >
131+ </ >
132+ )
133+ }
134+
135+ const ConnectedStatus : React . FC < {
136+ agent : WorkspaceAgent
137+ } > = ( { agent } ) => {
138+ return (
139+ < ChooseOne >
140+ < Cond condition = { agent . lifecycle_state === "ready" } >
141+ < ReadyLifeCycle />
142+ </ Cond >
143+ < Cond condition = { agent . lifecycle_state === "start_timeout" } >
144+ < StartTimeoutLifecycle agent = { agent } />
145+ </ Cond >
146+ < Cond condition = { agent . lifecycle_state === "start_error" } >
147+ < StartErrorLifecycle agent = { agent } />
148+ </ Cond >
149+ < Cond >
150+ < StartingLifecycle />
151+ </ Cond >
152+ </ ChooseOne >
153+ )
154+ }
155+
29156const DisconnectedStatus : React . FC = ( ) => {
30157 const styles = useStyles ( )
31158 const { t } = useTranslation ( "workspacePage" )
@@ -105,7 +232,7 @@ export const AgentStatus: React.FC<{
105232 return (
106233 < ChooseOne >
107234 < Cond condition = { agent . status === "connected" } >
108- < ConnectedStatus />
235+ < ConnectedStatus agent = { agent } />
109236 </ Cond >
110237 < Cond condition = { agent . status === "disconnected" } >
111238 < DisconnectedStatus />
@@ -160,4 +287,12 @@ const useStyles = makeStyles((theme) => ({
160287 position : "relative" ,
161288 top : theme . spacing ( 1 ) ,
162289 } ,
290+
291+ errorWarning : {
292+ color : theme . palette . error . main ,
293+ width : theme . spacing ( 2.5 ) ,
294+ height : theme . spacing ( 2.5 ) ,
295+ position : "relative" ,
296+ top : theme . spacing ( 1 ) ,
297+ } ,
163298} ) )
0 commit comments