Skip to content

Commit 3ad5e11

Browse files
authored
feat: add warning if workspace page becomes stale (#4375)
* added a warning summary component * added warning to workspace page * consolidated warnings * prettier * updated design
1 parent 9a670b9 commit 3ad5e11

File tree

7 files changed

+151
-66
lines changed

7 files changed

+151
-66
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Story } from "@storybook/react"
2+
import { WarningAlert, WarningAlertProps } from "./WarningAlert"
3+
import Button from "@material-ui/core/Button"
4+
5+
export default {
6+
title: "components/WarningAlert",
7+
component: WarningAlert,
8+
}
9+
10+
const Template: Story<WarningAlertProps> = (args) => <WarningAlert {...args} />
11+
12+
export const ExampleWithDismiss = Template.bind({})
13+
ExampleWithDismiss.args = {
14+
text: "This is a warning",
15+
dismissible: true,
16+
}
17+
18+
const ExampleAction = (
19+
<Button onClick={() => null} size="small">
20+
Button
21+
</Button>
22+
)
23+
24+
export const ExampleWithAction = Template.bind({})
25+
ExampleWithAction.args = {
26+
text: "This is a warning",
27+
actions: [ExampleAction],
28+
}
29+
30+
export const ExampleWithActionAndDismiss = Template.bind({})
31+
ExampleWithActionAndDismiss.args = {
32+
text: "This is a warning",
33+
actions: [ExampleAction],
34+
dismissible: true,
35+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { useState, FC, ReactElement } from "react"
2+
import Collapse from "@material-ui/core/Collapse"
3+
import { Stack } from "components/Stack/Stack"
4+
import { makeStyles, Theme } from "@material-ui/core/styles"
5+
import { colors } from "theme/colors"
6+
import ReportProblemOutlinedIcon from "@material-ui/icons/ReportProblemOutlined"
7+
import Button from "@material-ui/core/Button"
8+
import { useTranslation } from "react-i18next"
9+
10+
export interface WarningAlertProps {
11+
text: string
12+
dismissible?: boolean
13+
actions?: ReactElement[]
14+
}
15+
16+
export const WarningAlert: FC<WarningAlertProps> = ({
17+
text,
18+
dismissible = false,
19+
actions = [],
20+
}) => {
21+
const { t } = useTranslation("common")
22+
const [open, setOpen] = useState(true)
23+
const classes = useStyles()
24+
25+
return (
26+
<Collapse in={open}>
27+
<Stack
28+
className={classes.alertContainer}
29+
direction="row"
30+
alignItems="center"
31+
spacing={0}
32+
justifyContent="space-between"
33+
>
34+
<Stack direction="row" spacing={1}>
35+
<ReportProblemOutlinedIcon fontSize="small" className={classes.alertIcon} />
36+
{text}
37+
</Stack>
38+
<Stack direction="row">
39+
{actions.length > 0 && actions.map((action) => <div key={String(action)}>{action}</div>)}
40+
{dismissible && (
41+
<Button size="small" onClick={() => setOpen(false)} variant="outlined">
42+
{t("ctas.dismissCta")}
43+
</Button>
44+
)}
45+
</Stack>
46+
</Stack>
47+
</Collapse>
48+
)
49+
}
50+
51+
const useStyles = makeStyles<Theme>((theme) => ({
52+
alertContainer: {
53+
border: `1px solid ${colors.orange[7]}`,
54+
borderRadius: theme.shape.borderRadius,
55+
padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`,
56+
backgroundColor: `${colors.gray[16]}`,
57+
},
58+
alertIcon: {
59+
color: `${colors.orange[7]}`,
60+
},
61+
}))

site/src/components/Workspace/Workspace.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { WorkspaceScheduleBanner } from "../WorkspaceScheduleBanner/WorkspaceSch
1515
import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceScheduleButton"
1616
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
1717
import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats"
18+
import { WarningAlert } from "../WarningAlert/WarningAlert"
19+
import { useTranslation } from "react-i18next"
1820

1921
export enum WorkspaceErrors {
2022
GET_RESOURCES_ERROR = "getResourcesError",
@@ -71,19 +73,21 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
7173
buildInfo,
7274
applicationsHost,
7375
}) => {
76+
const { t } = useTranslation("workspacePage")
7477
const styles = useStyles()
7578
const navigate = useNavigate()
7679
const hasTemplateIcon = workspace.template_icon && workspace.template_icon !== ""
7780

78-
const buildError = workspaceErrors[WorkspaceErrors.BUILD_ERROR] ? (
81+
const buildError = Boolean(workspaceErrors[WorkspaceErrors.BUILD_ERROR]) && (
7982
<ErrorSummary error={workspaceErrors[WorkspaceErrors.BUILD_ERROR]} dismissible />
80-
) : (
81-
<></>
8283
)
83-
const cancellationError = workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR] ? (
84+
85+
const cancellationError = Boolean(workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]) && (
8486
<ErrorSummary error={workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]} dismissible />
85-
) : (
86-
<></>
87+
)
88+
89+
const workspaceRefreshWarning = Boolean(workspaceErrors[WorkspaceErrors.GET_RESOURCES_ERROR]) && (
90+
<WarningAlert text={t("warningsAndErrors.workspaceRefreshWarning")} dismissible />
8791
)
8892

8993
return (
@@ -127,6 +131,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
127131
<Stack direction="column" className={styles.firstColumnSpacer} spacing={2.5}>
128132
{buildError}
129133
{cancellationError}
134+
{workspaceRefreshWarning}
130135

131136
<WorkspaceScheduleBanner
132137
isLoading={bannerProps.isLoading}
Lines changed: 13 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
import Button from "@material-ui/core/Button"
2-
import { makeStyles } from "@material-ui/core/styles"
3-
import Alert from "@material-ui/lab/Alert"
4-
import AlertTitle from "@material-ui/lab/AlertTitle"
5-
import { Maybe } from "components/Conditionals/Maybe"
62
import { FC } from "react"
73
import * as TypesGen from "../../api/typesGenerated"
8-
9-
const Language = {
10-
bannerTitle: "This workspace has been deleted and cannot be edited.",
11-
createWorkspaceCta: "Create new workspace",
12-
}
4+
import { WarningAlert } from "components/WarningAlert/WarningAlert"
5+
import { useTranslation } from "react-i18next"
6+
import { Maybe } from "components/Conditionals/Maybe"
137

148
export interface WorkspaceDeletedBannerProps {
159
workspace: TypesGen.Workspace
@@ -20,32 +14,19 @@ export const WorkspaceDeletedBanner: FC<React.PropsWithChildren<WorkspaceDeleted
2014
workspace,
2115
handleClick,
2216
}) => {
23-
const styles = useStyles()
17+
const { t } = useTranslation("workspacePage")
18+
const NewWorkspaceButton = (
19+
<Button onClick={handleClick} size="small">
20+
{t("ctas.createWorkspaceCta")}
21+
</Button>
22+
)
2423

2524
return (
2625
<Maybe condition={workspace.latest_build.status === "deleted"}>
27-
<Alert
28-
className={styles.root}
29-
action={
30-
<Button color="inherit" onClick={handleClick} size="small">
31-
{Language.createWorkspaceCta}
32-
</Button>
33-
}
34-
severity="warning"
35-
>
36-
<AlertTitle>{Language.bannerTitle}</AlertTitle>
37-
</Alert>
26+
<WarningAlert
27+
text={t("warningsAndErrors.workspaceDeletedWarning")}
28+
actions={[NewWorkspaceButton]}
29+
/>
3830
</Maybe>
3931
)
4032
}
41-
42-
export const useStyles = makeStyles(() => {
43-
return {
44-
root: {
45-
alignItems: "center",
46-
"& .MuiAlertTitle-root": {
47-
marginBottom: "0px",
48-
},
49-
},
50-
}
51-
})
Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,16 @@
11
import Button from "@material-ui/core/Button"
2-
import Alert from "@material-ui/lab/Alert"
3-
import AlertTitle from "@material-ui/lab/AlertTitle"
42
import dayjs from "dayjs"
53
import isSameOrBefore from "dayjs/plugin/isSameOrBefore"
64
import utc from "dayjs/plugin/utc"
75
import { FC } from "react"
8-
import * as TypesGen from "../../api/typesGenerated"
9-
import { isWorkspaceOn } from "../../util/workspace"
6+
import * as TypesGen from "api/typesGenerated"
7+
import { isWorkspaceOn } from "util/workspace"
8+
import { WarningAlert } from "components/WarningAlert/WarningAlert"
9+
import { useTranslation } from "react-i18next"
1010

1111
dayjs.extend(utc)
1212
dayjs.extend(isSameOrBefore)
1313

14-
export const Language = {
15-
bannerAction: "Extend",
16-
bannerTitle: "Your workspace is scheduled to automatically shut down soon.",
17-
}
18-
1914
export interface WorkspaceScheduleBannerProps {
2015
isLoading?: boolean
2116
onExtend: () => void
@@ -36,26 +31,22 @@ export const WorkspaceScheduleBanner: FC<React.PropsWithChildren<WorkspaceSchedu
3631
onExtend,
3732
workspace,
3833
}) => {
34+
const { t } = useTranslation("workspacePage")
35+
3936
if (!shouldDisplay(workspace)) {
4037
return null
41-
} else {
42-
return (
43-
<Alert
44-
action={
45-
<Button
46-
variant="outlined"
47-
color="inherit"
48-
disabled={isLoading}
49-
onClick={onExtend}
50-
size="small"
51-
>
52-
{Language.bannerAction}
53-
</Button>
54-
}
55-
severity="warning"
56-
>
57-
<AlertTitle>{Language.bannerTitle}</AlertTitle>
58-
</Alert>
59-
)
6038
}
39+
40+
const ScheduleButton = (
41+
<Button variant="outlined" disabled={isLoading} onClick={onExtend} size="small">
42+
{t("ctas.extendScheduleCta")}
43+
</Button>
44+
)
45+
46+
return (
47+
<WarningAlert
48+
text={t("warningsAndErrors.workspaceShutdownWarning")}
49+
actions={[ScheduleButton]}
50+
/>
51+
)
6152
}

site/src/i18n/en/common.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,8 @@
1818
"confirm": "Are you sure you want to proceed? Type the name of this {{entity}} below to confirm.",
1919
"confirmLabel": "Name of {{entity}} to delete",
2020
"incorrectName": "Incorrect {{entity}} name."
21+
},
22+
"ctas": {
23+
"dismissCta": "Dismiss"
2124
}
2225
}

site/src/i18n/en/workspacePage.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
"editDeadlineMinus": "Subtract one hour",
88
"editDeadlinePlus": "Add one hour"
99
},
10+
"ctas": {
11+
"createWorkspaceCta": "Create new workspace",
12+
"extendScheduleCta": "Extend"
13+
},
14+
"warningsAndErrors": {
15+
"workspaceRefreshWarning": "We're having difficulty fetching the latest workspace state. Refresh the page to see the newest changes.",
16+
"workspaceDeletedWarning": "This workspace has been deleted and cannot be edited.",
17+
"workspaceShutdownWarning": "Your workspace is scheduled to automatically shut down soon."
18+
},
1019
"actionButton": {
1120
"start": "Start",
1221
"stop": "Stop",

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