1
- import { makeStyles } from "@material-ui/core/styles"
1
+ import Link from "@material-ui/core/Link"
2
+ import Popover from "@material-ui/core/Popover"
3
+ import { makeStyles , useTheme } from "@material-ui/core/styles"
4
+ import PlayCircleOutlined from "@material-ui/icons/PlayCircleFilledOutlined"
5
+ import VisibilityOffOutlined from "@material-ui/icons/VisibilityOffOutlined"
6
+ import VisibilityOutlined from "@material-ui/icons/VisibilityOutlined"
2
7
import { Skeleton } from "@material-ui/lab"
8
+ import { useMachine } from "@xstate/react"
9
+ import { AppLinkSkeleton } from "components/AppLink/AppLinkSkeleton"
10
+ import { Maybe } from "components/Conditionals/Maybe"
11
+ import { Line , Logs } from "components/Logs/Logs"
3
12
import { PortForwardButton } from "components/PortForwardButton/PortForwardButton"
4
- import { FC } from "react"
13
+ import { VSCodeDesktopButton } from "components/VSCodeDesktopButton/VSCodeDesktopButton"
14
+ import { FC , useEffect , useRef , useState } from "react"
15
+ import { useTranslation } from "react-i18next"
16
+ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
17
+ import { darcula } from "react-syntax-highlighter/dist/cjs/styles/prism"
18
+ import { workspaceAgentLogsMachine } from "xServices/workspaceAgentLogs/workspaceAgentLogsXService"
5
19
import { Workspace , WorkspaceAgent } from "../../api/typesGenerated"
6
20
import { AppLink } from "../AppLink/AppLink"
7
21
import { SSHButton } from "../SSHButton/SSHButton"
8
22
import { Stack } from "../Stack/Stack"
9
23
import { TerminalLink } from "../TerminalLink/TerminalLink"
10
24
import { AgentLatency } from "./AgentLatency"
11
- import { AgentVersion } from "./AgentVersion"
12
- import { Maybe } from "components/Conditionals/Maybe"
13
25
import { AgentStatus } from "./AgentStatus"
14
- import { AppLinkSkeleton } from "components/AppLink/AppLinkSkeleton"
15
- import { useTranslation } from "react-i18next"
16
- import { VSCodeDesktopButton } from "components/VSCodeDesktopButton/VSCodeDesktopButton"
17
- import { useMachine } from "@xstate/react"
18
- import { workspaceAgentLogsMachine } from "xServices/workspaceAgentLogs/workspaceAgentLogsXService"
19
- import { Line , Logs } from "components/Logs/Logs"
20
- import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
21
- import { darcula } from "react-syntax-highlighter/dist/cjs/styles/prism"
26
+ import { AgentVersion } from "./AgentVersion"
22
27
23
28
export interface AgentRowProps {
24
29
agent : WorkspaceAgent
@@ -43,14 +48,33 @@ export const AgentRow: FC<AgentRowProps> = ({
43
48
} ) => {
44
49
const styles = useStyles ( )
45
50
const { t } = useTranslation ( "agent" )
46
- const [ logsMachine ] = useMachine ( workspaceAgentLogsMachine , {
51
+ const [ logsMachine , sendLogsEvent ] = useMachine ( workspaceAgentLogsMachine , {
47
52
context : { agentID : agent . id } ,
48
53
} )
49
-
50
- console . log ( "drac" , darcula )
54
+ const theme = useTheme ( )
55
+ const startupScriptAnchorRef = useRef < HTMLLinkElement > ( null )
56
+ const [ startupScriptOpen , setStartupScriptOpen ] = useState ( false )
57
+ const [ showStartupLogs , setShowStartupLogs ] = useState (
58
+ agent . lifecycle_state !== "ready" ,
59
+ )
60
+ useEffect ( ( ) => {
61
+ setShowStartupLogs ( agent . lifecycle_state !== "ready" )
62
+ } , [ agent . lifecycle_state ] )
63
+ useEffect ( ( ) => {
64
+ // We only want to fetch logs when they are actually shown,
65
+ // otherwise we can make a lot of requests that aren't necessary.
66
+ if ( showStartupLogs ) {
67
+ sendLogsEvent ( "FETCH_STARTUP_LOGS" )
68
+ }
69
+ } , [ sendLogsEvent , showStartupLogs ] )
51
70
52
71
return (
53
- < Stack direction = "column" key = { agent . id } spacing = { 0 } >
72
+ < Stack
73
+ direction = "column"
74
+ key = { agent . id }
75
+ spacing = { 0 }
76
+ className = { styles . agentWrapper }
77
+ >
54
78
< Stack
55
79
direction = "row"
56
80
alignItems = "center"
@@ -91,6 +115,79 @@ export const AgentRow: FC<AgentRowProps> = ({
91
115
{ t ( "unableToConnect" ) }
92
116
</ Maybe >
93
117
</ Stack >
118
+
119
+ < Stack
120
+ direction = "row"
121
+ alignItems = "baseline"
122
+ spacing = { 1 }
123
+ className = { styles . startupLinks }
124
+ >
125
+ { ( logsMachine . context . startupLogs || agent . startup_script ) && (
126
+ < Link
127
+ className = { styles . startupLink }
128
+ variant = "body2"
129
+ onClick = { ( ) => {
130
+ setShowStartupLogs ( ! showStartupLogs )
131
+ } }
132
+ >
133
+ { showStartupLogs ? (
134
+ < VisibilityOffOutlined />
135
+ ) : (
136
+ < VisibilityOutlined />
137
+ ) }
138
+ { showStartupLogs ? "Hide" : "Show" } Startup Logs
139
+ </ Link >
140
+ ) }
141
+
142
+ { agent . startup_script && (
143
+ < Link
144
+ className = { styles . startupLink }
145
+ variant = "body2"
146
+ ref = { startupScriptAnchorRef }
147
+ onClick = { ( ) => {
148
+ setStartupScriptOpen ( ! startupScriptOpen )
149
+ } }
150
+ >
151
+ < PlayCircleOutlined />
152
+ View Startup Script
153
+ </ Link >
154
+ ) }
155
+
156
+ < Popover
157
+ classes = { {
158
+ paper : styles . startupScriptPopover ,
159
+ } }
160
+ open = { startupScriptOpen }
161
+ onClose = { ( ) => setStartupScriptOpen ( false ) }
162
+ anchorEl = { startupScriptAnchorRef . current }
163
+ anchorOrigin = { {
164
+ vertical : "bottom" ,
165
+ horizontal : "left" ,
166
+ } }
167
+ transformOrigin = { {
168
+ vertical : "top" ,
169
+ horizontal : "left" ,
170
+ } }
171
+ >
172
+ < div >
173
+ < SyntaxHighlighter
174
+ style = { darcula }
175
+ language = "shell"
176
+ showLineNumbers
177
+ // Use inline styles does not work correctly
178
+ // https://github.com/react-syntax-highlighter/react-syntax-highlighter/issues/329
179
+ codeTagProps = { { style : { } } }
180
+ customStyle = { {
181
+ background : theme . palette . background . default ,
182
+ maxWidth : 600 ,
183
+ margin : 0 ,
184
+ } }
185
+ >
186
+ { agent . startup_script || "" }
187
+ </ SyntaxHighlighter >
188
+ </ div >
189
+ </ Popover >
190
+ </ Stack >
94
191
</ div >
95
192
</ Stack >
96
193
@@ -151,45 +248,68 @@ export const AgentRow: FC<AgentRowProps> = ({
151
248
) }
152
249
</ Stack >
153
250
</ Stack >
154
-
155
- < div >
156
- Startup Script
157
- < SyntaxHighlighter
158
- style = { darcula }
159
- language = "bash"
160
- useInlineStyles = { false }
161
- codeTagProps = { { style : { } } }
162
- >
163
- { String ( agent . startup_script ) }
164
- </ SyntaxHighlighter >
165
- { logsMachine . context . startupLogs && (
166
- < Logs
167
- className = { styles . agentStartupLogs }
168
- lines = { logsMachine . context . startupLogs . map (
251
+ { showStartupLogs && (
252
+ < Logs
253
+ className = { styles . startupLogs }
254
+ lineNumbers
255
+ lines = {
256
+ logsMachine . context . startupLogs ?. map (
169
257
( log ) : Line => ( {
170
258
level : "info" ,
171
259
output : log . output ,
172
260
time : log . created_at ,
173
261
} ) ,
174
- ) }
175
- />
176
- ) }
177
- </ div >
262
+ ) || [ ]
263
+ }
264
+ />
265
+ ) }
178
266
</ Stack >
179
267
)
180
268
}
181
269
182
270
const useStyles = makeStyles ( ( theme ) => ( {
271
+ agentWrapper : {
272
+ "&:not(:last-child)" : {
273
+ borderBottom : `1px solid ${ theme . palette . divider } ` ,
274
+ } ,
275
+ } ,
276
+
183
277
agentRow : {
184
278
padding : theme . spacing ( 3 , 4 ) ,
185
279
backgroundColor : theme . palette . background . paperLight ,
186
280
fontSize : 16 ,
281
+ } ,
187
282
188
- "&:not(:last-child)" : {
189
- borderBottom : `1px solid ${ theme . palette . divider } ` ,
283
+ startupLinks : {
284
+ display : "flex" ,
285
+ alignItems : "center" ,
286
+ gap : theme . spacing ( 2 ) ,
287
+ marginTop : theme . spacing ( 0.5 ) ,
288
+ } ,
289
+
290
+ startupLink : {
291
+ cursor : "pointer" ,
292
+ display : "flex" ,
293
+ gap : 4 ,
294
+ alignItems : "center" ,
295
+ userSelect : "none" ,
296
+
297
+ "& svg" : {
298
+ width : 12 ,
299
+ height : 12 ,
190
300
} ,
191
301
} ,
192
302
303
+ startupLogs : {
304
+ maxHeight : 256 ,
305
+ display : "flex" ,
306
+ flexDirection : "column-reverse" ,
307
+ } ,
308
+
309
+ startupScriptPopover : {
310
+ backgroundColor : theme . palette . background . default ,
311
+ } ,
312
+
193
313
agentStatusWrapper : {
194
314
width : theme . spacing ( 4.5 ) ,
195
315
display : "flex" ,
0 commit comments