@@ -13,19 +13,146 @@ import {
13
13
import { useRef , useState } from "react"
14
14
import Link from "@material-ui/core/Link"
15
15
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 = ( ) => {
17
22
const styles = useStyles ( )
18
23
const { t } = useTranslation ( "workspacePage" )
19
24
20
25
return (
21
26
< div
22
27
role = "status"
23
- aria-label = { t ( "agentStatus.connected" ) }
28
+ aria-label = { t ( "agentStatus.connected.ready " ) }
24
29
className = { combineClasses ( [ styles . status , styles . connected ] ) }
25
30
/>
26
31
)
27
32
}
28
33
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
+
29
156
const DisconnectedStatus : React . FC = ( ) => {
30
157
const styles = useStyles ( )
31
158
const { t } = useTranslation ( "workspacePage" )
@@ -105,7 +232,7 @@ export const AgentStatus: React.FC<{
105
232
return (
106
233
< ChooseOne >
107
234
< Cond condition = { agent . status === "connected" } >
108
- < ConnectedStatus />
235
+ < ConnectedStatus agent = { agent } />
109
236
</ Cond >
110
237
< Cond condition = { agent . status === "disconnected" } >
111
238
< DisconnectedStatus />
@@ -160,4 +287,12 @@ const useStyles = makeStyles((theme) => ({
160
287
position : "relative" ,
161
288
top : theme . spacing ( 1 ) ,
162
289
} ,
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
+ } ,
163
298
} ) )
0 commit comments