Thanks to visit codestin.com
Credit goes to github.com

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
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

+22-52
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}
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
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)