feat(site): add documentation links to webterminal notifications (#8019)

* feat(site): add documentation links to webterminal notifications

* change button variant
This commit is contained in:
Rodrigo Maia
2023-06-13 19:27:40 -05:00
committed by GitHub
parent 7a7ee63225
commit 1da2570e14
4 changed files with 194 additions and 69 deletions

View File

@ -1,18 +1,21 @@
import { Story } from "@storybook/react"
import { WarningAlert, WarningAlertProps } from "./WarningAlert"
import { Meta, StoryObj } from "@storybook/react"
import { WarningAlert } from "./WarningAlert"
import Button from "@mui/material/Button"
export default {
const meta: Meta<typeof WarningAlert> = {
title: "components/WarningAlert",
component: WarningAlert,
}
const Template: Story<WarningAlertProps> = (args) => <WarningAlert {...args} />
export default meta
export const ExampleWithDismiss = Template.bind({})
ExampleWithDismiss.args = {
text: "This is a warning",
dismissible: true,
type Story = StoryObj<typeof WarningAlert>
export const ExampleWithDismiss: Story = {
args: {
text: "This is a warning",
dismissible: true,
},
}
const ExampleAction = (
@ -21,15 +24,17 @@ const ExampleAction = (
</Button>
)
export const ExampleWithAction = Template.bind({})
ExampleWithAction.args = {
text: "This is a warning",
actions: [ExampleAction],
export const ExampleWithAction = {
args: {
text: "This is a warning",
actions: [ExampleAction],
},
}
export const ExampleWithActionAndDismiss = Template.bind({})
ExampleWithActionAndDismiss.args = {
text: "This is a warning",
actions: [ExampleAction],
dismissible: true,
export const ExampleWithActionAndDismiss = {
args: {
text: "This is a warning",
actions: [ExampleAction],
dismissible: true,
},
}

View File

@ -1,7 +1,4 @@
import Button from "@mui/material/Button"
import { makeStyles, useTheme } from "@mui/styles"
import WarningIcon from "@mui/icons-material/ErrorOutlineRounded"
import RefreshOutlined from "@mui/icons-material/RefreshOutlined"
import { useMachine } from "@xstate/react"
import { portForwardURL } from "components/PortForwardButton/PortForwardButton"
import { Stack } from "components/Stack/Stack"
@ -18,13 +15,13 @@ import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
import { pageTitle } from "../../utils/page"
import { terminalMachine } from "../../xServices/terminal/terminalXService"
import { useProxy } from "contexts/ProxyContext"
import { combineClasses } from "utils/combineClasses"
import Box from "@mui/material/Box"
import { useDashboard } from "components/Dashboard/DashboardProvider"
import { Region } from "api/typesGenerated"
import { getLatencyColor } from "utils/latency"
import Popover from "@mui/material/Popover"
import { ProxyStatusLatency } from "components/ProxyStatusLatency/ProxyStatusLatency"
import TerminalPageAlert, { TerminalPageAlertType } from "./TerminalPageAlert"
export const Language = {
workspaceErrorMessagePrefix: "Unable to fetch workspace: ",
@ -80,12 +77,26 @@ const TerminalPage: FC = () => {
websocketError,
} = terminalState.context
const reloading = useReloading(isDisconnected)
const shouldDisplayStartupWarning = workspaceAgent
? ["starting", "starting_timeout"].includes(workspaceAgent.lifecycle_state)
: false
const shouldDisplayStartupError = workspaceAgent
? workspaceAgent.lifecycle_state === "start_error"
: false
const lifecycleState = workspaceAgent?.lifecycle_state
const [startupWarning, setStartupWarning] = useState<
TerminalPageAlertType | undefined
>(undefined)
useEffect(() => {
if (lifecycleState === "start_error") {
setStartupWarning("error")
} else if (lifecycleState === "starting") {
setStartupWarning("starting")
} else {
setStartupWarning((prev) => {
if (prev === "starting") {
return "success"
}
return undefined
})
}
}, [lifecycleState])
const dashboard = useDashboard()
const proxyContext = useProxy()
const selectedProxy = proxyContext.proxy.proxy
@ -305,49 +316,8 @@ const TerminalPage: FC = () => {
</Stack>
)}
</div>
{shouldDisplayStartupError && (
<div
className={combineClasses([styles.alert, styles.alertError])}
role="alert"
>
<WarningIcon className={styles.alertIcon} />
<div>
<div className={styles.alertTitle}>Startup script failed</div>
<div className={styles.alertMessage}>
You can continue using this terminal, but something may be missing
or not fully set up.
</div>
</div>
</div>
)}
<Box display="flex" flexDirection="column" height="100vh">
{shouldDisplayStartupWarning && (
<div className={styles.alert} role="alert">
<WarningIcon className={styles.alertIcon} />
<div>
<div className={styles.alertTitle}>
Startup script is still running
</div>
<div className={styles.alertMessage}>
You can continue using this terminal, but something may be
missing or not fully set up.
</div>
</div>
<div className={styles.alertActions}>
<Button
startIcon={<RefreshOutlined />}
size="small"
onClick={() => {
// By redirecting the user without the session in the URL we
// create a new one
window.location.href = window.location.pathname
}}
>
Refresh session
</Button>
</div>
</div>
)}
{startupWarning && <TerminalPageAlert alertType={startupWarning} />}
<div
className={styles.terminal}
ref={xtermRef}

View File

@ -0,0 +1,37 @@
import type { Meta, StoryObj } from "@storybook/react"
import TerminalPageAlert from "./TerminalPageAlert"
const meta: Meta<typeof TerminalPageAlert> = {
component: TerminalPageAlert,
title: "components/TerminalPageAlert",
argTypes: {
alertType: {
control: {
type: "radio",
},
options: ["error", "starting", "success"],
},
},
}
type Story = StoryObj<typeof TerminalPageAlert>
export const Error: Story = {
args: {
alertType: "error",
},
}
export const Starting: Story = {
args: {
alertType: "starting",
},
}
export const Success: Story = {
args: {
alertType: "success",
},
}
export default meta

View File

@ -0,0 +1,113 @@
import { AlertColor } from "@mui/material/Alert/Alert"
import Button from "@mui/material/Button"
import Link from "@mui/material/Link"
import { Alert } from "components/Alert/Alert"
import { ReactNode } from "react"
export type TerminalPageAlertType = "error" | "starting" | "success"
type MapAlertTypeToComponent = {
[key in TerminalPageAlertType]: {
severity: AlertColor
children: ReactNode | undefined
}
}
const mapAlertTypeToText: MapAlertTypeToComponent = {
error: {
severity: "warning",
children: (
<>
The workspace{" "}
<Link
title="startup script has exited with an error"
href="https://coder.com/docs/v2/latest/templates#startup-script-exited-with-an-error"
target="_blank"
rel="noreferrer"
>
startup script has exited with an error
</Link>
, we recommend reloading this session and{" "}
<Link
title=" debugging the startup script"
href="https://coder.com/docs/v2/latest/templates#debugging-the-startup-script"
target="_blank"
rel="noreferrer"
>
debugging the startup script
</Link>{" "}
because{" "}
<Link
title="your workspace may be incomplete."
href="https://coder.com/docs/v2/latest/templates#your-workspace-may-be-incomplete"
target="_blank"
rel="noreferrer"
>
your workspace may be incomplete.
</Link>{" "}
</>
),
},
starting: {
severity: "info",
children: (
<>
Startup script is still running. You can continue using this terminal,
but{" "}
<Link
title="your workspace may be incomplete."
href="https://coder.com/docs/v2/latest/templates#your-workspace-may-be-incomplete"
target="_blank"
rel="noreferrer"
>
{" "}
your workspace may be incomplete.
</Link>
</>
),
},
success: {
severity: "success",
children: (
<>
Startup script has completed successfully. The workspace is ready but
this{" "}
<Link
title="session was started before the startup script finished"
href="https://coder.com/docs/v2/latest/templates#your-workspace-may-be-incomplete"
target="_blank"
rel="noreferrer"
>
session was started before the startup script finished.
</Link>{" "}
To ensure your shell environment is up-to-date, we recommend reloading
this session.
</>
),
},
}
export default ({ alertType }: { alertType: TerminalPageAlertType }) => {
return (
<Alert
severity={mapAlertTypeToText[alertType].severity}
dismissible
actions={[
<Button
key="refresh-session"
size="small"
variant="text"
onClick={() => {
// By redirecting the user without the session in the URL we
// create a new one
window.location.href = window.location.pathname
}}
>
Refresh session
</Button>,
]}
>
{mapAlertTypeToText[alertType].children}
</Alert>
)
}