Skip to content

Commit 1da2570

Browse files
authored
feat(site): add documentation links to webterminal notifications (#8019)
* feat(site): add documentation links to webterminal notifications * change button variant
1 parent 7a7ee63 commit 1da2570

File tree

4 files changed

+194
-69
lines changed

4 files changed

+194
-69
lines changed
Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import { Story } from "@storybook/react"
2-
import { WarningAlert, WarningAlertProps } from "./WarningAlert"
1+
import { Meta, StoryObj } from "@storybook/react"
2+
import { WarningAlert } from "./WarningAlert"
33
import Button from "@mui/material/Button"
44

5-
export default {
5+
const meta: Meta<typeof WarningAlert> = {
66
title: "components/WarningAlert",
77
component: WarningAlert,
88
}
99

10-
const Template: Story<WarningAlertProps> = (args) => <WarningAlert {...args} />
10+
export default meta
1111

12-
export const ExampleWithDismiss = Template.bind({})
13-
ExampleWithDismiss.args = {
14-
text: "This is a warning",
15-
dismissible: true,
12+
type Story = StoryObj<typeof WarningAlert>
13+
14+
export const ExampleWithDismiss: Story = {
15+
args: {
16+
text: "This is a warning",
17+
dismissible: true,
18+
},
1619
}
1720

1821
const ExampleAction = (
@@ -21,15 +24,17 @@ const ExampleAction = (
2124
</Button>
2225
)
2326

24-
export const ExampleWithAction = Template.bind({})
25-
ExampleWithAction.args = {
26-
text: "This is a warning",
27-
actions: [ExampleAction],
27+
export const ExampleWithAction = {
28+
args: {
29+
text: "This is a warning",
30+
actions: [ExampleAction],
31+
},
2832
}
2933

30-
export const ExampleWithActionAndDismiss = Template.bind({})
31-
ExampleWithActionAndDismiss.args = {
32-
text: "This is a warning",
33-
actions: [ExampleAction],
34-
dismissible: true,
34+
export const ExampleWithActionAndDismiss = {
35+
args: {
36+
text: "This is a warning",
37+
actions: [ExampleAction],
38+
dismissible: true,
39+
},
3540
}

site/src/pages/TerminalPage/TerminalPage.tsx

Lines changed: 22 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
import Button from "@mui/material/Button"
21
import { makeStyles, useTheme } from "@mui/styles"
3-
import WarningIcon from "@mui/icons-material/ErrorOutlineRounded"
4-
import RefreshOutlined from "@mui/icons-material/RefreshOutlined"
52
import { useMachine } from "@xstate/react"
63
import { portForwardURL } from "components/PortForwardButton/PortForwardButton"
74
import { Stack } from "components/Stack/Stack"
@@ -18,13 +15,13 @@ import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
1815
import { pageTitle } from "../../utils/page"
1916
import { terminalMachine } from "../../xServices/terminal/terminalXService"
2017
import { useProxy } from "contexts/ProxyContext"
21-
import { combineClasses } from "utils/combineClasses"
2218
import Box from "@mui/material/Box"
2319
import { useDashboard } from "components/Dashboard/DashboardProvider"
2420
import { Region } from "api/typesGenerated"
2521
import { getLatencyColor } from "utils/latency"
2622
import Popover from "@mui/material/Popover"
2723
import { ProxyStatusLatency } from "components/ProxyStatusLatency/ProxyStatusLatency"
24+
import TerminalPageAlert, { TerminalPageAlertType } from "./TerminalPageAlert"
2825

2926
export const Language = {
3027
workspaceErrorMessagePrefix: "Unable to fetch workspace: ",
@@ -80,12 +77,26 @@ const TerminalPage: FC = () => {
8077
websocketError,
8178
} = terminalState.context
8279
const reloading = useReloading(isDisconnected)
83-
const shouldDisplayStartupWarning = workspaceAgent
84-
? ["starting", "starting_timeout"].includes(workspaceAgent.lifecycle_state)
85-
: false
86-
const shouldDisplayStartupError = workspaceAgent
87-
? workspaceAgent.lifecycle_state === "start_error"
88-
: false
80+
const lifecycleState = workspaceAgent?.lifecycle_state
81+
const [startupWarning, setStartupWarning] = useState<
82+
TerminalPageAlertType | undefined
83+
>(undefined)
84+
85+
useEffect(() => {
86+
if (lifecycleState === "start_error") {
87+
setStartupWarning("error")
88+
} else if (lifecycleState === "starting") {
89+
setStartupWarning("starting")
90+
} else {
91+
setStartupWarning((prev) => {
92+
if (prev === "starting") {
93+
return "success"
94+
}
95+
return undefined
96+
})
97+
}
98+
}, [lifecycleState])
99+
89100
const dashboard = useDashboard()
90101
const proxyContext = useProxy()
91102
const selectedProxy = proxyContext.proxy.proxy
@@ -305,49 +316,8 @@ const TerminalPage: FC = () => {
305316
</Stack>
306317
)}
307318
</div>
308-
{shouldDisplayStartupError && (
309-
<div
310-
className={combineClasses([styles.alert, styles.alertError])}
311-
role="alert"
312-
>
313-
<WarningIcon className={styles.alertIcon} />
314-
<div>
315-
<div className={styles.alertTitle}>Startup script failed</div>
316-
<div className={styles.alertMessage}>
317-
You can continue using this terminal, but something may be missing
318-
or not fully set up.
319-
</div>
320-
</div>
321-
</div>
322-
)}
323319
<Box display="flex" flexDirection="column" height="100vh">
324-
{shouldDisplayStartupWarning && (
325-
<div className={styles.alert} role="alert">
326-
<WarningIcon className={styles.alertIcon} />
327-
<div>
328-
<div className={styles.alertTitle}>
329-
Startup script is still running
330-
</div>
331-
<div className={styles.alertMessage}>
332-
You can continue using this terminal, but something may be
333-
missing or not fully set up.
334-
</div>
335-
</div>
336-
<div className={styles.alertActions}>
337-
<Button
338-
startIcon={<RefreshOutlined />}
339-
size="small"
340-
onClick={() => {
341-
// By redirecting the user without the session in the URL we
342-
// create a new one
343-
window.location.href = window.location.pathname
344-
}}
345-
>
346-
Refresh session
347-
</Button>
348-
</div>
349-
</div>
350-
)}
320+
{startupWarning && <TerminalPageAlert alertType={startupWarning} />}
351321
<div
352322
className={styles.terminal}
353323
ref={xtermRef}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { Meta, StoryObj } from "@storybook/react"
2+
3+
import TerminalPageAlert from "./TerminalPageAlert"
4+
5+
const meta: Meta<typeof TerminalPageAlert> = {
6+
component: TerminalPageAlert,
7+
title: "components/TerminalPageAlert",
8+
argTypes: {
9+
alertType: {
10+
control: {
11+
type: "radio",
12+
},
13+
options: ["error", "starting", "success"],
14+
},
15+
},
16+
}
17+
type Story = StoryObj<typeof TerminalPageAlert>
18+
19+
export const Error: Story = {
20+
args: {
21+
alertType: "error",
22+
},
23+
}
24+
25+
export const Starting: Story = {
26+
args: {
27+
alertType: "starting",
28+
},
29+
}
30+
31+
export const Success: Story = {
32+
args: {
33+
alertType: "success",
34+
},
35+
}
36+
37+
export default meta
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import { AlertColor } from "@mui/material/Alert/Alert"
2+
import Button from "@mui/material/Button"
3+
import Link from "@mui/material/Link"
4+
import { Alert } from "components/Alert/Alert"
5+
import { ReactNode } from "react"
6+
7+
export type TerminalPageAlertType = "error" | "starting" | "success"
8+
9+
type MapAlertTypeToComponent = {
10+
[key in TerminalPageAlertType]: {
11+
severity: AlertColor
12+
children: ReactNode | undefined
13+
}
14+
}
15+
16+
const mapAlertTypeToText: MapAlertTypeToComponent = {
17+
error: {
18+
severity: "warning",
19+
children: (
20+
<>
21+
The workspace{" "}
22+
<Link
23+
title="startup script has exited with an error"
24+
href="https://coder.com/docs/v2/latest/templates#startup-script-exited-with-an-error"
25+
target="_blank"
26+
rel="noreferrer"
27+
>
28+
startup script has exited with an error
29+
</Link>
30+
, we recommend reloading this session and{" "}
31+
<Link
32+
title=" debugging the startup script"
33+
href="https://coder.com/docs/v2/latest/templates#debugging-the-startup-script"
34+
target="_blank"
35+
rel="noreferrer"
36+
>
37+
debugging the startup script
38+
</Link>{" "}
39+
because{" "}
40+
<Link
41+
title="your workspace may be incomplete."
42+
href="https://coder.com/docs/v2/latest/templates#your-workspace-may-be-incomplete"
43+
target="_blank"
44+
rel="noreferrer"
45+
>
46+
your workspace may be incomplete.
47+
</Link>{" "}
48+
</>
49+
),
50+
},
51+
starting: {
52+
severity: "info",
53+
children: (
54+
<>
55+
Startup script is still running. You can continue using this terminal,
56+
but{" "}
57+
<Link
58+
title="your workspace may be incomplete."
59+
href="https://coder.com/docs/v2/latest/templates#your-workspace-may-be-incomplete"
60+
target="_blank"
61+
rel="noreferrer"
62+
>
63+
{" "}
64+
your workspace may be incomplete.
65+
</Link>
66+
</>
67+
),
68+
},
69+
success: {
70+
severity: "success",
71+
children: (
72+
<>
73+
Startup script has completed successfully. The workspace is ready but
74+
this{" "}
75+
<Link
76+
title="session was started before the startup script finished"
77+
href="https://coder.com/docs/v2/latest/templates#your-workspace-may-be-incomplete"
78+
target="_blank"
79+
rel="noreferrer"
80+
>
81+
session was started before the startup script finished.
82+
</Link>{" "}
83+
To ensure your shell environment is up-to-date, we recommend reloading
84+
this session.
85+
</>
86+
),
87+
},
88+
}
89+
90+
export default ({ alertType }: { alertType: TerminalPageAlertType }) => {
91+
return (
92+
<Alert
93+
severity={mapAlertTypeToText[alertType].severity}
94+
dismissible
95+
actions={[
96+
<Button
97+
key="refresh-session"
98+
size="small"
99+
variant="text"
100+
onClick={() => {
101+
// By redirecting the user without the session in the URL we
102+
// create a new one
103+
window.location.href = window.location.pathname
104+
}}
105+
>
106+
Refresh session
107+
</Button>,
108+
]}
109+
>
110+
{mapAlertTypeToText[alertType].children}
111+
</Alert>
112+
)
113+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy