From 7da8608e080c8550bad4a378a284eb7d733cde32 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Tue, 4 Oct 2022 19:17:45 +0000 Subject: [PATCH 1/5] added a warning summary component --- .../WarningSummary/WarningSummary.stories.tsx | 14 ++++ .../WarningSummary/WarningSummary.tsx | 64 +++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 site/src/components/WarningSummary/WarningSummary.stories.tsx create mode 100644 site/src/components/WarningSummary/WarningSummary.tsx diff --git a/site/src/components/WarningSummary/WarningSummary.stories.tsx b/site/src/components/WarningSummary/WarningSummary.stories.tsx new file mode 100644 index 0000000000000..01277ae5d7781 --- /dev/null +++ b/site/src/components/WarningSummary/WarningSummary.stories.tsx @@ -0,0 +1,14 @@ +import { Story } from "@storybook/react" +import { WarningSummary, WarningSummaryProps } from "./WarningSummary" + +export default { + title: "components/WarningSummary", + component: WarningSummary, +} + +const Template: Story = (args) => + +export const Example = Template.bind({}) +Example.args = { + warningString: "This is a warning", +} diff --git a/site/src/components/WarningSummary/WarningSummary.tsx b/site/src/components/WarningSummary/WarningSummary.tsx new file mode 100644 index 0000000000000..5a3c946cead48 --- /dev/null +++ b/site/src/components/WarningSummary/WarningSummary.tsx @@ -0,0 +1,64 @@ +import { FC, useState } from "react" +import { Stack } from "components/Stack/Stack" +import { makeStyles, Theme } from "@material-ui/core/styles" +import CloseIcon from "@material-ui/icons/Close" +import ReportProblemOutlinedIcon from "@material-ui/icons/ReportProblemOutlined" +import IconButton from "@material-ui/core/IconButton" +import { colors } from "theme/colors" + +export interface WarningSummaryProps { + warningString: string +} + +export const WarningSummary: FC = ({ warningString }) => { + const styles = useStyles() + const [isOpen, setOpen] = useState(true) + + const closeWarning = () => { + setOpen(false) + } + + if (!isOpen) { + return null + } + + return ( + + + + {warningString} + + + + + + + ) +} +const useStyles = makeStyles((theme) => ({ + root: { + border: `2px solid ${colors.orange[7]}`, + padding: `8px`, + borderRadius: theme.shape.borderRadius, + gap: 0, + color: `${colors.orange[7]}`, // icon inherits color from parent + }, + errorMessage: { + marginRight: `${theme.spacing(1)}px`, + marginLeft: "10px", + color: `${colors.orange[4]}`, + }, + iconButton: { + padding: 0, + }, + closeIcon: { + width: 25, + height: 25, + color: `${colors.orange[7]}`, + }, +})) From a15a59fc4d9d69e5943ad0527f5a0f56c782fe9e Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Tue, 4 Oct 2022 19:46:33 +0000 Subject: [PATCH 2/5] added warning to workspace page --- .../WarningSummary/WarningSummary.tsx | 2 +- site/src/components/Workspace/Workspace.tsx | 17 +++++++++++------ site/src/i18n/en/workspacePage.json | 3 +++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/site/src/components/WarningSummary/WarningSummary.tsx b/site/src/components/WarningSummary/WarningSummary.tsx index 5a3c946cead48..3b7a86eb22718 100644 --- a/site/src/components/WarningSummary/WarningSummary.tsx +++ b/site/src/components/WarningSummary/WarningSummary.tsx @@ -43,7 +43,7 @@ export const WarningSummary: FC = ({ warningString }) => { const useStyles = makeStyles((theme) => ({ root: { border: `2px solid ${colors.orange[7]}`, - padding: `8px`, + padding: `${theme.spacing(1)}px`, borderRadius: theme.shape.borderRadius, gap: 0, color: `${colors.orange[7]}`, // icon inherits color from parent diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index e8c1a82a41b76..a7d000f7c5215 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -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 { WarningSummary } from "../WarningSummary/WarningSummary" +import { useTranslation } from "react-i18next" export enum WorkspaceErrors { GET_RESOURCES_ERROR = "getResourcesError", @@ -71,19 +73,21 @@ export const Workspace: FC> = ({ 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]) && ( - ) : ( - <> ) - const cancellationError = workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR] ? ( + + const cancellationError = Boolean(workspaceErrors[WorkspaceErrors.CANCELLATION_ERROR]) && ( - ) : ( - <> + ) + + const workspaceRefreshWarning = Boolean(workspaceErrors[WorkspaceErrors.GET_RESOURCES_ERROR]) && ( + ) return ( @@ -126,6 +130,7 @@ export const Workspace: FC> = ({ {buildError} {cancellationError} + {workspaceRefreshWarning} Date: Wed, 5 Oct 2022 14:53:32 +0000 Subject: [PATCH 3/5] consolidated warnings --- .../WarningAlert/WarningAlert.stories.tsx | 27 ++++++++ .../components/WarningAlert/WarningAlert.tsx | 43 +++++++++++++ .../WarningSummary/WarningSummary.stories.tsx | 14 ---- .../WarningSummary/WarningSummary.tsx | 64 ------------------- site/src/components/Workspace/Workspace.tsx | 4 +- .../WorkspaceDeletedBanner.tsx | 44 ++++--------- .../WorkspaceScheduleBanner.tsx | 44 +++++-------- site/src/i18n/en/workspacePage.json | 11 +++- 8 files changed, 110 insertions(+), 141 deletions(-) create mode 100644 site/src/components/WarningAlert/WarningAlert.stories.tsx create mode 100644 site/src/components/WarningAlert/WarningAlert.tsx delete mode 100644 site/src/components/WarningSummary/WarningSummary.stories.tsx delete mode 100644 site/src/components/WarningSummary/WarningSummary.tsx diff --git a/site/src/components/WarningAlert/WarningAlert.stories.tsx b/site/src/components/WarningAlert/WarningAlert.stories.tsx new file mode 100644 index 0000000000000..166a754b76031 --- /dev/null +++ b/site/src/components/WarningAlert/WarningAlert.stories.tsx @@ -0,0 +1,27 @@ +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 = (args) => + +export const ExampleWithClose = Template.bind({}) +ExampleWithClose.args = { + text: "This is a warning", +} + +const ExampleAction = ( + +) + +export const ExampleWithAction = Template.bind({}) +ExampleWithAction.args = { + text: "This is a warning", + action: ExampleAction, +} diff --git a/site/src/components/WarningAlert/WarningAlert.tsx b/site/src/components/WarningAlert/WarningAlert.tsx new file mode 100644 index 0000000000000..189b2f9e498f7 --- /dev/null +++ b/site/src/components/WarningAlert/WarningAlert.tsx @@ -0,0 +1,43 @@ +import { useState, FC, ReactElement } from "react" +import Alert from "@material-ui/lab/Alert" +import IconButton from "@material-ui/core/IconButton" +import Collapse from "@material-ui/core/Collapse" +import { Stack } from "components/Stack/Stack" +import CloseIcon from "@material-ui/icons/Close" + +export interface WarningAlertProps { + text: string + action?: ReactElement +} + +export const WarningAlert: FC = ({ text, action }) => { + const [open, setOpen] = useState(true) + + return ( + + + { + setOpen(false) + }} + > + + + ) + } + > + {text} + + + + ) +} diff --git a/site/src/components/WarningSummary/WarningSummary.stories.tsx b/site/src/components/WarningSummary/WarningSummary.stories.tsx deleted file mode 100644 index 01277ae5d7781..0000000000000 --- a/site/src/components/WarningSummary/WarningSummary.stories.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Story } from "@storybook/react" -import { WarningSummary, WarningSummaryProps } from "./WarningSummary" - -export default { - title: "components/WarningSummary", - component: WarningSummary, -} - -const Template: Story = (args) => - -export const Example = Template.bind({}) -Example.args = { - warningString: "This is a warning", -} diff --git a/site/src/components/WarningSummary/WarningSummary.tsx b/site/src/components/WarningSummary/WarningSummary.tsx deleted file mode 100644 index 3b7a86eb22718..0000000000000 --- a/site/src/components/WarningSummary/WarningSummary.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { FC, useState } from "react" -import { Stack } from "components/Stack/Stack" -import { makeStyles, Theme } from "@material-ui/core/styles" -import CloseIcon from "@material-ui/icons/Close" -import ReportProblemOutlinedIcon from "@material-ui/icons/ReportProblemOutlined" -import IconButton from "@material-ui/core/IconButton" -import { colors } from "theme/colors" - -export interface WarningSummaryProps { - warningString: string -} - -export const WarningSummary: FC = ({ warningString }) => { - const styles = useStyles() - const [isOpen, setOpen] = useState(true) - - const closeWarning = () => { - setOpen(false) - } - - if (!isOpen) { - return null - } - - return ( - - - - {warningString} - - - - - - - ) -} -const useStyles = makeStyles((theme) => ({ - root: { - border: `2px solid ${colors.orange[7]}`, - padding: `${theme.spacing(1)}px`, - borderRadius: theme.shape.borderRadius, - gap: 0, - color: `${colors.orange[7]}`, // icon inherits color from parent - }, - errorMessage: { - marginRight: `${theme.spacing(1)}px`, - marginLeft: "10px", - color: `${colors.orange[4]}`, - }, - iconButton: { - padding: 0, - }, - closeIcon: { - width: 25, - height: 25, - color: `${colors.orange[7]}`, - }, -})) diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index a7d000f7c5215..9f5e2ea684c0d 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -15,7 +15,7 @@ import { WorkspaceScheduleBanner } from "../WorkspaceScheduleBanner/WorkspaceSch import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceScheduleButton" import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection" import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats" -import { WarningSummary } from "../WarningSummary/WarningSummary" +import { WarningAlert } from "../WarningAlert/WarningAlert" import { useTranslation } from "react-i18next" export enum WorkspaceErrors { @@ -87,7 +87,7 @@ export const Workspace: FC> = ({ ) const workspaceRefreshWarning = Boolean(workspaceErrors[WorkspaceErrors.GET_RESOURCES_ERROR]) && ( - + ) return ( diff --git a/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx b/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx index 604de7a6d19de..cb41bf9e2150d 100644 --- a/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx +++ b/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx @@ -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 { FC } from "react" import * as TypesGen from "../../api/typesGenerated" import { isWorkspaceDeleted } from "../../util/workspace" - -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" export interface WorkspaceDeletedBannerProps { workspace: TypesGen.Workspace @@ -20,34 +14,22 @@ export const WorkspaceDeletedBanner: FC { - const styles = useStyles() + const { t } = useTranslation("workspacePage") if (!isWorkspaceDeleted(workspace)) { return null } + const NewWorkspaceButton = ( + + ) + return ( - - {Language.createWorkspaceCta} - - } - severity="warning" - > - {Language.bannerTitle} - + ) } - -export const useStyles = makeStyles(() => { - return { - root: { - alignItems: "center", - "& .MuiAlertTitle-root": { - marginBottom: "0px", - }, - }, - } -}) diff --git a/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx b/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx index 81538af5352df..e6cd565e7f969 100644 --- a/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx +++ b/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx @@ -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,19 @@ export const WorkspaceScheduleBanner: FC { + const { t } = useTranslation("workspacePage") + if (!shouldDisplay(workspace)) { return null - } else { - return ( - - {Language.bannerAction} - - } - severity="warning" - > - {Language.bannerTitle} - - ) } + + const ScheduleButton = ( + + ) + + return ( + + ) } diff --git a/site/src/i18n/en/workspacePage.json b/site/src/i18n/en/workspacePage.json index f4b1ab6eb9762..bbc199734661a 100644 --- a/site/src/i18n/en/workspacePage.json +++ b/site/src/i18n/en/workspacePage.json @@ -6,8 +6,15 @@ "schedule": "Schedule", "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." + "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." } } From 5db509bab209bdb0e8aa564ad9055f11ec972880 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 5 Oct 2022 15:08:59 +0000 Subject: [PATCH 4/5] prettier --- site/src/i18n/en/workspacePage.json | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/i18n/en/workspacePage.json b/site/src/i18n/en/workspacePage.json index bbc199734661a..2d98f12d4da56 100644 --- a/site/src/i18n/en/workspacePage.json +++ b/site/src/i18n/en/workspacePage.json @@ -10,7 +10,6 @@ "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.", From 5aeb6e2bc0af8f9d672c99acd9d972ed20fb294d Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 5 Oct 2022 20:05:24 +0000 Subject: [PATCH 5/5] updated design --- .../WarningAlert/WarningAlert.stories.tsx | 16 +++- .../components/WarningAlert/WarningAlert.tsx | 76 ++++++++++++------- site/src/components/Workspace/Workspace.tsx | 2 +- .../WorkspaceDeletedBanner.tsx | 4 +- .../WorkspaceScheduleBanner.tsx | 7 +- site/src/i18n/en/common.json | 3 + 6 files changed, 70 insertions(+), 38 deletions(-) diff --git a/site/src/components/WarningAlert/WarningAlert.stories.tsx b/site/src/components/WarningAlert/WarningAlert.stories.tsx index 166a754b76031..dc8eed293441e 100644 --- a/site/src/components/WarningAlert/WarningAlert.stories.tsx +++ b/site/src/components/WarningAlert/WarningAlert.stories.tsx @@ -9,13 +9,14 @@ export default { const Template: Story = (args) => -export const ExampleWithClose = Template.bind({}) -ExampleWithClose.args = { +export const ExampleWithDismiss = Template.bind({}) +ExampleWithDismiss.args = { text: "This is a warning", + dismissible: true, } const ExampleAction = ( - ) @@ -23,5 +24,12 @@ const ExampleAction = ( export const ExampleWithAction = Template.bind({}) ExampleWithAction.args = { text: "This is a warning", - action: ExampleAction, + actions: [ExampleAction], +} + +export const ExampleWithActionAndDismiss = Template.bind({}) +ExampleWithActionAndDismiss.args = { + text: "This is a warning", + actions: [ExampleAction], + dismissible: true, } diff --git a/site/src/components/WarningAlert/WarningAlert.tsx b/site/src/components/WarningAlert/WarningAlert.tsx index 189b2f9e498f7..7b0a024927913 100644 --- a/site/src/components/WarningAlert/WarningAlert.tsx +++ b/site/src/components/WarningAlert/WarningAlert.tsx @@ -1,43 +1,61 @@ import { useState, FC, ReactElement } from "react" -import Alert from "@material-ui/lab/Alert" -import IconButton from "@material-ui/core/IconButton" import Collapse from "@material-ui/core/Collapse" import { Stack } from "components/Stack/Stack" -import CloseIcon from "@material-ui/icons/Close" +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 - action?: ReactElement + dismissible?: boolean + actions?: ReactElement[] } -export const WarningAlert: FC = ({ text, action }) => { +export const WarningAlert: FC = ({ + text, + dismissible = false, + actions = [], +}) => { + const { t } = useTranslation("common") const [open, setOpen] = useState(true) + const classes = useStyles() return ( - - - { - setOpen(false) - }} - > - - - ) - } - > + + + + {text} - - - + + + {actions.length > 0 && actions.map((action) =>
{action}
)} + {dismissible && ( + + )} +
+ + ) } + +const useStyles = makeStyles((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]}`, + }, +})) diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index 9f5e2ea684c0d..945258a836467 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -87,7 +87,7 @@ export const Workspace: FC> = ({ ) const workspaceRefreshWarning = Boolean(workspaceErrors[WorkspaceErrors.GET_RESOURCES_ERROR]) && ( - + ) return ( diff --git a/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx b/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx index cb41bf9e2150d..c398047ee96fc 100644 --- a/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx +++ b/site/src/components/WorkspaceDeletedBanner/WorkspaceDeletedBanner.tsx @@ -21,7 +21,7 @@ export const WorkspaceDeletedBanner: FC + ) @@ -29,7 +29,7 @@ export const WorkspaceDeletedBanner: FC ) } diff --git a/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx b/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx index e6cd565e7f969..2ff5ca57096e1 100644 --- a/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx +++ b/site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx @@ -38,12 +38,15 @@ export const WorkspaceScheduleBanner: FC + ) return ( - + ) } diff --git a/site/src/i18n/en/common.json b/site/src/i18n/en/common.json index 514205e9da8c2..99dda7c9e541d 100644 --- a/site/src/i18n/en/common.json +++ b/site/src/i18n/en/common.json @@ -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" } }