feat: add warning if workspace page becomes stale (#4375)

* added a warning summary component

* added warning to workspace page

* consolidated warnings

* prettier

* updated design
This commit is contained in:
Kira Pilot
2022-10-05 18:46:46 -04:00
committed by GitHub
parent 9a670b90df
commit 3ad5e11d22
7 changed files with 151 additions and 66 deletions
@@ -0,0 +1,35 @@
import { Story } from "@storybook/react"
import { WarningAlert, WarningAlertProps } from "./WarningAlert"
import Button from "@material-ui/core/Button"
export default {
title: "components/WarningAlert",
component: WarningAlert,
}
const Template: Story<WarningAlertProps> = (args) => <WarningAlert {...args} />
export const ExampleWithDismiss = Template.bind({})
ExampleWithDismiss.args = {
text: "This is a warning",
dismissible: true,
}
const ExampleAction = (
<Button onClick={() => null} size="small">
Button
</Button>
)
export const ExampleWithAction = Template.bind({})
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,
}
@@ -0,0 +1,61 @@
import { useState, FC, ReactElement } from "react"
import Collapse from "@material-ui/core/Collapse"
import { Stack } from "components/Stack/Stack"
import { makeStyles, Theme } from "@material-ui/core/styles"
import { colors } from "theme/colors"
import ReportProblemOutlinedIcon from "@material-ui/icons/ReportProblemOutlined"
import Button from "@material-ui/core/Button"
import { useTranslation } from "react-i18next"
export interface WarningAlertProps {
text: string
dismissible?: boolean
actions?: ReactElement[]
}
export const WarningAlert: FC<WarningAlertProps> = ({
text,
dismissible = false,
actions = [],
}) => {
const { t } = useTranslation("common")
const [open, setOpen] = useState(true)
const classes = useStyles()
return (
<Collapse in={open}>
<Stack
className={classes.alertContainer}
direction="row"
alignItems="center"
spacing={0}
justifyContent="space-between"
>
<Stack direction="row" spacing={1}>
<ReportProblemOutlinedIcon fontSize="small" className={classes.alertIcon} />
{text}
</Stack>
<Stack direction="row">
{actions.length > 0 && actions.map((action) => <div key={String(action)}>{action}</div>)}
{dismissible && (
<Button size="small" onClick={() => setOpen(false)} variant="outlined">
{t("ctas.dismissCta")}
</Button>
)}
</Stack>
</Stack>
</Collapse>
)
}
const useStyles = makeStyles<Theme>((theme) => ({
alertContainer: {
border: `1px solid ${colors.orange[7]}`,
borderRadius: theme.shape.borderRadius,
padding: `${theme.spacing(1)}px ${theme.spacing(2)}px`,
backgroundColor: `${colors.gray[16]}`,
},
alertIcon: {
color: `${colors.orange[7]}`,
},
}))
+11 -6
View File
@@ -15,6 +15,8 @@ import { WorkspaceScheduleBanner } from "../WorkspaceScheduleBanner/WorkspaceSch
import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceScheduleButton"
import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection"
import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats"
import { WarningAlert } from "../WarningAlert/WarningAlert"
import { useTranslation } from "react-i18next"
export enum WorkspaceErrors {
GET_RESOURCES_ERROR = "getResourcesError",
@@ -71,19 +73,21 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
buildInfo,
applicationsHost,
}) => {
const { t } = useTranslation("workspacePage")
const styles = useStyles()
const navigate = useNavigate()
const hasTemplateIcon = workspace.template_icon && workspace.template_icon !== ""
const buildError = workspaceErrors[WorkspaceErrors.BUILD_ERROR] ? (
const buildError = Boolean(workspaceErrors[WorkspaceErrors.BUILD_ERROR]) && (
<ErrorSummary error={workspaceErrors[WorkspaceErrors.BUILD_ERROR]} dismissible />
) : (
<></>
)
const cancellationError = workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR] ? (
const cancellationError = Boolean(workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]) && (
<ErrorSummary error={workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]} dismissible />
) : (
<></>
)
const workspaceRefreshWarning = Boolean(workspaceErrors[WorkspaceErrors.GET_RESOURCES_ERROR]) && (
<WarningAlert text={t("warningsAndErrors.workspaceRefreshWarning")} dismissible />
)
return (
@@ -127,6 +131,7 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
<Stack direction="column" className={styles.firstColumnSpacer} spacing={2.5}>
{buildError}
{cancellationError}
{workspaceRefreshWarning}
<WorkspaceScheduleBanner
isLoading={bannerProps.isLoading}
@@ -1,15 +1,9 @@
import Button from "@material-ui/core/Button"
import { makeStyles } from "@material-ui/core/styles"
import Alert from "@material-ui/lab/Alert"
import AlertTitle from "@material-ui/lab/AlertTitle"
import { Maybe } from "components/Conditionals/Maybe"
import { FC } from "react"
import * as TypesGen from "../../api/typesGenerated"
const Language = {
bannerTitle: "This workspace has been deleted and cannot be edited.",
createWorkspaceCta: "Create new workspace",
}
import { WarningAlert } from "components/WarningAlert/WarningAlert"
import { useTranslation } from "react-i18next"
import { Maybe } from "components/Conditionals/Maybe"
export interface WorkspaceDeletedBannerProps {
workspace: TypesGen.Workspace
@@ -20,32 +14,19 @@ export const WorkspaceDeletedBanner: FC<React.PropsWithChildren<WorkspaceDeleted
workspace,
handleClick,
}) => {
const styles = useStyles()
const { t } = useTranslation("workspacePage")
const NewWorkspaceButton = (
<Button onClick={handleClick} size="small">
{t("ctas.createWorkspaceCta")}
</Button>
)
return (
<Maybe condition={workspace.latest_build.status === "deleted"}>
<Alert
className={styles.root}
action={
<Button color="inherit" onClick={handleClick} size="small">
{Language.createWorkspaceCta}
</Button>
}
severity="warning"
>
<AlertTitle>{Language.bannerTitle}</AlertTitle>
</Alert>
<WarningAlert
text={t("warningsAndErrors.workspaceDeletedWarning")}
actions={[NewWorkspaceButton]}
/>
</Maybe>
)
}
export const useStyles = makeStyles(() => {
return {
root: {
alignItems: "center",
"& .MuiAlertTitle-root": {
marginBottom: "0px",
},
},
}
})
@@ -1,21 +1,16 @@
import Button from "@material-ui/core/Button"
import Alert from "@material-ui/lab/Alert"
import AlertTitle from "@material-ui/lab/AlertTitle"
import dayjs from "dayjs"
import isSameOrBefore from "dayjs/plugin/isSameOrBefore"
import utc from "dayjs/plugin/utc"
import { FC } from "react"
import * as TypesGen from "../../api/typesGenerated"
import { isWorkspaceOn } from "../../util/workspace"
import * as TypesGen from "api/typesGenerated"
import { isWorkspaceOn } from "util/workspace"
import { WarningAlert } from "components/WarningAlert/WarningAlert"
import { useTranslation } from "react-i18next"
dayjs.extend(utc)
dayjs.extend(isSameOrBefore)
export const Language = {
bannerAction: "Extend",
bannerTitle: "Your workspace is scheduled to automatically shut down soon.",
}
export interface WorkspaceScheduleBannerProps {
isLoading?: boolean
onExtend: () => void
@@ -36,26 +31,22 @@ export const WorkspaceScheduleBanner: FC<React.PropsWithChildren<WorkspaceSchedu
onExtend,
workspace,
}) => {
const { t } = useTranslation("workspacePage")
if (!shouldDisplay(workspace)) {
return null
} else {
return (
<Alert
action={
<Button
variant="outlined"
color="inherit"
disabled={isLoading}
onClick={onExtend}
size="small"
>
{Language.bannerAction}
</Button>
}
severity="warning"
>
<AlertTitle>{Language.bannerTitle}</AlertTitle>
</Alert>
)
}
const ScheduleButton = (
<Button variant="outlined" disabled={isLoading} onClick={onExtend} size="small">
{t("ctas.extendScheduleCta")}
</Button>
)
return (
<WarningAlert
text={t("warningsAndErrors.workspaceShutdownWarning")}
actions={[ScheduleButton]}
/>
)
}
+3
View File
@@ -18,5 +18,8 @@
"confirm": "Are you sure you want to proceed? Type the name of this {{entity}} below to confirm.",
"confirmLabel": "Name of {{entity}} to delete",
"incorrectName": "Incorrect {{entity}} name."
},
"ctas": {
"dismissCta": "Dismiss"
}
}
+9
View File
@@ -7,6 +7,15 @@
"editDeadlineMinus": "Subtract one hour",
"editDeadlinePlus": "Add one hour"
},
"ctas": {
"createWorkspaceCta": "Create new workspace",
"extendScheduleCta": "Extend"
},
"warningsAndErrors": {
"workspaceRefreshWarning": "We're having difficulty fetching the latest workspace state. Refresh the page to see the newest changes.",
"workspaceDeletedWarning": "This workspace has been deleted and cannot be edited.",
"workspaceShutdownWarning": "Your workspace is scheduled to automatically shut down soon."
},
"actionButton": {
"start": "Start",
"stop": "Stop",