From 18a96d5e5b748d33bafebd94ebf6099ac2aeea73 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Mon, 10 Apr 2023 16:17:53 +0000 Subject: [PATCH 01/10] Combine build statuses --- site/src/components/WorkspaceStats/WorkspaceStats.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index d23f007b80d83..2da812c7229e6 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -9,6 +9,7 @@ import { } from "util/workspace" import { Workspace } from "../../api/typesGenerated" import { Stats, StatsItem } from "components/Stats/Stats" +import upperFirst from "lodash/upperFirst" const Language = { workspaceDetails: "Workspace Details", @@ -73,9 +74,13 @@ export const WorkspaceStats: FC = ({ /> + {upperFirst(createDayString(workspace.latest_build.created_at))} by{" "} + {initiatedBy} + + } /> - {workspace.latest_build.daily_cost > 0 && ( Date: Mon, 10 Apr 2023 16:29:16 +0000 Subject: [PATCH 02/10] Display schedule info as stats --- .../WorkspaceStats/WorkspaceStats.tsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 2da812c7229e6..9435177e70c80 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -6,10 +6,12 @@ import { createDayString } from "util/createDayString" import { getDisplayWorkspaceBuildInitiatedBy, getDisplayWorkspaceTemplateName, + isWorkspaceOn, } from "util/workspace" import { Workspace } from "../../api/typesGenerated" import { Stats, StatsItem } from "components/Stats/Stats" import upperFirst from "lodash/upperFirst" +import { autostopDisplay } from "util/schedule" const Language = { workspaceDetails: "Workspace Details", @@ -81,6 +83,12 @@ export const WorkspaceStats: FC = ({ } /> + {shouldDisplayScheduleLabel(workspace) && ( + + )} {workspace.latest_build.daily_cost > 0 && ( = ({ ) } + +export const canEditDeadline = (workspace: Workspace): boolean => { + return isWorkspaceOn(workspace) && Boolean(workspace.latest_build.deadline) +} + +export const shouldDisplayScheduleLabel = (workspace: Workspace): boolean => { + if (canEditDeadline(workspace)) { + return true + } + if (isWorkspaceOn(workspace)) { + return false + } + return Boolean(workspace.autostart_schedule) +} + +const getScheduleLabel = (workspace: Workspace) => { + return isWorkspaceOn(workspace) ? "Stops at" : "Starts at" +} From d305787a710b06db4cd38dcacd0e526047685c54 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Mon, 10 Apr 2023 19:09:04 +0000 Subject: [PATCH 03/10] Add increase popover --- site/src/components/Workspace/Workspace.tsx | 2 + .../WorkspaceStats/WorkspaceStats.tsx | 259 ++++++++++++++---- 2 files changed, 212 insertions(+), 49 deletions(-) diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index ceb18f2483107..fc2589be4890d 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -194,6 +194,8 @@ export const Workspace: FC> = ({ workspace={workspace} quota_budget={quota_budget} handleUpdate={handleUpdate} + maxDeadlineDecrease={scheduleProps.maxDeadlineDecrease} + maxDeadlineIncrease={scheduleProps.maxDeadlineIncrease} /> {failedBuildLogs && ( diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 9435177e70c80..52b7cffeac27e 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -1,6 +1,6 @@ import Link from "@material-ui/core/Link" import { OutdatedHelpTooltip } from "components/Tooltips" -import { FC } from "react" +import { FC, useRef, useState } from "react" import { Link as RouterLink } from "react-router-dom" import { createDayString } from "util/createDayString" import { @@ -12,6 +12,14 @@ import { Workspace } from "../../api/typesGenerated" import { Stats, StatsItem } from "components/Stats/Stats" import upperFirst from "lodash/upperFirst" import { autostopDisplay } from "util/schedule" +import IconButton from "@material-ui/core/IconButton" +import RemoveIcon from "@material-ui/icons/RemoveOutlined" +import { makeStyles } from "@material-ui/core/styles" +import AddIcon from "@material-ui/icons/AddOutlined" +import Popover from "@material-ui/core/Popover" +import TextField from "@material-ui/core/TextField" +import { Stack } from "components/Stack/Stack" +import Button from "@material-ui/core/Button" const Language = { workspaceDetails: "Workspace Details", @@ -27,6 +35,8 @@ const Language = { export interface WorkspaceStatsProps { workspace: Workspace + maxDeadlineIncrease: number + maxDeadlineDecrease: number quota_budget?: number handleUpdate: () => void } @@ -34,70 +44,155 @@ export interface WorkspaceStatsProps { export const WorkspaceStats: FC = ({ workspace, quota_budget, + maxDeadlineDecrease, + maxDeadlineIncrease, handleUpdate, }) => { const initiatedBy = getDisplayWorkspaceBuildInitiatedBy( workspace.latest_build, ) const displayTemplateName = getDisplayWorkspaceTemplateName(workspace) + const styles = useStyles() + const deadlinePlusEnabled = maxDeadlineIncrease >= 1 + const deadlineMinusEnabled = maxDeadlineDecrease >= 1 + const addingButtonRef = useRef(null) + const [isAddingTime, setIsAddingTime] = useState(false) return ( - - - {displayTemplateName} - - } - /> - + <> + + - {workspace.latest_build.template_version_name} + {displayTemplateName} - - {workspace.outdated && ( - - )} - - } - /> - - {upperFirst(createDayString(workspace.latest_build.created_at))} by{" "} - {initiatedBy} - - } - /> - {shouldDisplayScheduleLabel(workspace) && ( + } + /> + + {workspace.latest_build.template_version_name} + + + {workspace.outdated && ( + + )} + + } /> - )} - {workspace.latest_build.daily_cost > 0 && ( + {upperFirst(createDayString(workspace.latest_build.created_at))}{" "} + by {initiatedBy} + + } /> - )} - + {shouldDisplayScheduleLabel(workspace) && ( + + + {autostopDisplay(workspace)} + + + + + + setIsAddingTime(true)} + > + + + + + } + /> + )} + {workspace.latest_build.daily_cost > 0 && ( + + )} + + + setIsAddingTime(false)} + anchorOrigin={{ + vertical: "bottom", + horizontal: "right", + }} + transformOrigin={{ + vertical: "top", + horizontal: "right", + }} + > + Add hours to deadline + + Delay the shutdown of this workspace for a few more hours. This is + only applied once. + +
+ + + + +
+ ) } @@ -118,3 +213,69 @@ export const shouldDisplayScheduleLabel = (workspace: Workspace): boolean => { const getScheduleLabel = (workspace: Workspace) => { return isWorkspaceOn(workspace) ? "Stops at" : "Starts at" } + +const useStyles = makeStyles((theme) => ({ + scheduleValue: { + display: "flex", + alignItems: "center", + gap: theme.spacing(1.5), + }, + + scheduleControls: { + display: "flex", + alignItems: "center", + gap: theme.spacing(0.5), + }, + + scheduleButton: { + border: `1px solid ${theme.palette.divider}`, + borderRadius: 4, + + "& svg.MuiSvgIcon-root": { + width: theme.spacing(1.5), + height: theme.spacing(1.5), + }, + }, + + timePopoverPaper: { + padding: theme.spacing(3), + maxWidth: theme.spacing(36), + marginTop: theme.spacing(1), + borderRadius: 4, + display: "flex", + flexDirection: "column", + gap: theme.spacing(1), + }, + + timePopoverTitle: { + fontWeight: 600, + }, + + timePopoverDescription: { + color: theme.palette.text.secondary, + }, + + timePopoverForm: { + display: "flex", + alignItems: "center", + gap: theme.spacing(1), + padding: theme.spacing(1, 0), + }, + + timePopoverField: { + margin: 0, + }, + + timePopoverFieldInput: { + fontSize: 14, + padding: theme.spacing(0), + borderRadius: 4, + }, + + timePopoverButton: { + borderRadius: 4, + paddingLeft: theme.spacing(2), + paddingRight: theme.spacing(2), + flexShrink: 0, + }, +})) From 34d64dea48150ab74d1a96c2e97967b596741ca2 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 11 Apr 2023 12:09:45 +0000 Subject: [PATCH 04/10] Remove uncessary component --- site/src/components/WorkspaceStats/WorkspaceStats.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 52b7cffeac27e..33b38484e9bbe 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -18,7 +18,6 @@ import { makeStyles } from "@material-ui/core/styles" import AddIcon from "@material-ui/icons/AddOutlined" import Popover from "@material-ui/core/Popover" import TextField from "@material-ui/core/TextField" -import { Stack } from "components/Stack/Stack" import Button from "@material-ui/core/Button" const Language = { From a8b8b54d374789cdd34e234cf5fd5481b3264f2a Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 11 Apr 2023 12:38:51 +0000 Subject: [PATCH 05/10] Fix time label --- site/src/components/WorkspaceStats/WorkspaceStats.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 33b38484e9bbe..b9ef54397c541 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -11,7 +11,7 @@ import { import { Workspace } from "../../api/typesGenerated" import { Stats, StatsItem } from "components/Stats/Stats" import upperFirst from "lodash/upperFirst" -import { autostopDisplay } from "util/schedule" +import { autostartDisplay, autostopDisplay } from "util/schedule" import IconButton from "@material-ui/core/IconButton" import RemoveIcon from "@material-ui/icons/RemoveOutlined" import { makeStyles } from "@material-ui/core/styles" @@ -110,7 +110,9 @@ export const WorkspaceStats: FC = ({ to="settings/schedule" title="Schedule settings" > - {autostopDisplay(workspace)} + {isWorkspaceOn(workspace) + ? autostopDisplay(workspace) + : autostartDisplay(workspace.autostart_schedule)} Date: Tue, 11 Apr 2023 12:41:00 +0000 Subject: [PATCH 06/10] Fix controls --- site/src/components/Workspace/Workspace.tsx | 1 + .../WorkspaceStats/WorkspaceStats.tsx | 44 ++++++++++--------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index fc2589be4890d..f1bebfd7ceb3a 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -196,6 +196,7 @@ export const Workspace: FC> = ({ handleUpdate={handleUpdate} maxDeadlineDecrease={scheduleProps.maxDeadlineDecrease} maxDeadlineIncrease={scheduleProps.maxDeadlineIncrease} + canUpdateWorkspace={canUpdateWorkspace} /> {failedBuildLogs && ( diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index b9ef54397c541..8d47f50ba2b52 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -36,6 +36,7 @@ export interface WorkspaceStatsProps { workspace: Workspace maxDeadlineIncrease: number maxDeadlineDecrease: number + canUpdateWorkspace: boolean quota_budget?: number handleUpdate: () => void } @@ -46,6 +47,7 @@ export const WorkspaceStats: FC = ({ maxDeadlineDecrease, maxDeadlineIncrease, handleUpdate, + canUpdateWorkspace, }) => { const initiatedBy = getDisplayWorkspaceBuildInitiatedBy( workspace.latest_build, @@ -114,26 +116,28 @@ export const WorkspaceStats: FC = ({ ? autostopDisplay(workspace) : autostartDisplay(workspace.autostart_schedule)} - - - - - setIsAddingTime(true)} - > - - - + {canUpdateWorkspace && canEditDeadline(workspace) && ( + + + + + setIsAddingTime(true)} + > + + + + )} } /> From 06a6b2e40384dfe52831359aecbb5d72f1ac75dc Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 11 Apr 2023 12:56:43 +0000 Subject: [PATCH 07/10] Make schedule controls work --- site/src/components/Workspace/Workspace.tsx | 2 + .../WorkspaceStats/WorkspaceStats.tsx | 86 +++++++++++++++++-- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index f1bebfd7ceb3a..22f9e5c181c10 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -197,6 +197,8 @@ export const Workspace: FC> = ({ maxDeadlineDecrease={scheduleProps.maxDeadlineDecrease} maxDeadlineIncrease={scheduleProps.maxDeadlineIncrease} canUpdateWorkspace={canUpdateWorkspace} + onDeadlineMinus={scheduleProps.onDeadlineMinus} + onDeadlinePlus={scheduleProps.onDeadlinePlus} /> {failedBuildLogs && ( diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 8d47f50ba2b52..e699435f4f194 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -38,6 +38,8 @@ export interface WorkspaceStatsProps { maxDeadlineDecrease: number canUpdateWorkspace: boolean quota_budget?: number + onDeadlinePlus: (hours: number) => void + onDeadlineMinus: (hours: number) => void handleUpdate: () => void } @@ -46,8 +48,10 @@ export const WorkspaceStats: FC = ({ quota_budget, maxDeadlineDecrease, maxDeadlineIncrease, - handleUpdate, canUpdateWorkspace, + handleUpdate, + onDeadlineMinus, + onDeadlinePlus, }) => { const initiatedBy = getDisplayWorkspaceBuildInitiatedBy( workspace.latest_build, @@ -56,8 +60,10 @@ export const WorkspaceStats: FC = ({ const styles = useStyles() const deadlinePlusEnabled = maxDeadlineIncrease >= 1 const deadlineMinusEnabled = maxDeadlineDecrease >= 1 - const addingButtonRef = useRef(null) + const addButtonRef = useRef(null) + const subButtonRef = useRef(null) const [isAddingTime, setIsAddingTime] = useState(false) + const [isSubTime, setIsSubTime] = useState(false) return ( <> @@ -123,6 +129,8 @@ export const WorkspaceStats: FC = ({ size="small" title="Subtract hours from deadline" className={styles.scheduleButton} + ref={subButtonRef} + onClick={() => setIsSubTime(true)} > @@ -131,7 +139,7 @@ export const WorkspaceStats: FC = ({ size="small" title="Add hours to deadline" className={styles.scheduleButton} - ref={addingButtonRef} + ref={addButtonRef} onClick={() => setIsAddingTime(true)} > @@ -156,7 +164,7 @@ export const WorkspaceStats: FC = ({ id="schedule-add" classes={{ paper: styles.timePopoverPaper }} open={isAddingTime} - anchorEl={addingButtonRef.current} + anchorEl={addButtonRef.current} onClose={() => setIsAddingTime(false)} anchorOrigin={{ vertical: "bottom", @@ -172,8 +180,18 @@ export const WorkspaceStats: FC = ({ Delay the shutdown of this workspace for a few more hours. This is only applied once. -
+ { + e.preventDefault() + const formData = new FormData(e.currentTarget) + const hours = Number(formData.get("hours")) + onDeadlinePlus(hours) + setIsAddingTime(false) + }} + > = ({ + + setIsSubTime(false)} + anchorOrigin={{ + vertical: "bottom", + horizontal: "right", + }} + transformOrigin={{ + vertical: "top", + horizontal: "right", + }} + > + + Subtract hours to deadline + + + Anticipate the shutdown of this workspace for a few more hours. This + is only applied once. + +
{ + e.preventDefault() + const formData = new FormData(e.currentTarget) + const hours = Number(formData.get("hours")) + onDeadlineMinus(hours) + setIsSubTime(false) + }} + > + + + + +
) } From 5059b3b8900b3f861e89b57dbc312081644eab31 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 11 Apr 2023 12:58:21 +0000 Subject: [PATCH 08/10] Remove workspace schedule button --- site/src/components/Workspace/Workspace.tsx | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index 22f9e5c181c10..b0377eeb29847 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -25,7 +25,6 @@ import { Resources } from "../Resources/Resources" import { Stack } from "../Stack/Stack" import { WorkspaceActions } from "../WorkspaceActions/WorkspaceActions" import { WorkspaceDeletedBanner } from "../WorkspaceDeletedBanner/WorkspaceDeletedBanner" -import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceScheduleButton" import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats" export enum WorkspaceErrors { @@ -33,7 +32,6 @@ export enum WorkspaceErrors { BUILD_ERROR = "buildError", CANCELLATION_ERROR = "cancellationError", } - export interface WorkspaceProps { scheduleProps: { onDeadlinePlus: (hours: number) => void @@ -129,14 +127,6 @@ export const Workspace: FC> = ({ - > = ({ workspace={workspace} quota_budget={quota_budget} handleUpdate={handleUpdate} + canUpdateWorkspace={canUpdateWorkspace} maxDeadlineDecrease={scheduleProps.maxDeadlineDecrease} maxDeadlineIncrease={scheduleProps.maxDeadlineIncrease} - canUpdateWorkspace={canUpdateWorkspace} onDeadlineMinus={scheduleProps.onDeadlineMinus} onDeadlinePlus={scheduleProps.onDeadlinePlus} /> From 0d5a87f9ee9fa01ef69d7fe118f94f1c1bab6097 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 11 Apr 2023 12:58:56 +0000 Subject: [PATCH 09/10] Schedule button code --- .../WorkspaceScheduleButton/EditHours.tsx | 54 ---- .../WorkspaceScheduleButton.stories.tsx | 121 -------- .../WorkspaceScheduleButton.test.tsx | 88 ------ .../WorkspaceScheduleButton.tsx | 270 ------------------ .../WorkspaceScheduleLabel.tsx | 63 ---- 5 files changed, 596 deletions(-) delete mode 100644 site/src/components/WorkspaceScheduleButton/EditHours.tsx delete mode 100644 site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.stories.tsx delete mode 100644 site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.test.tsx delete mode 100644 site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx delete mode 100644 site/src/components/WorkspaceScheduleButton/WorkspaceScheduleLabel.tsx diff --git a/site/src/components/WorkspaceScheduleButton/EditHours.tsx b/site/src/components/WorkspaceScheduleButton/EditHours.tsx deleted file mode 100644 index 3e9a274d48e26..0000000000000 --- a/site/src/components/WorkspaceScheduleButton/EditHours.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import Button from "@material-ui/core/Button" -import { makeStyles } from "@material-ui/core/styles" -import TextField from "@material-ui/core/TextField" -import { Stack } from "components/Stack/Stack" -import { useState } from "react" -import { useTranslation } from "react-i18next" - -interface EditHoursProps { - handleSubmit: (hours: number) => void - max: number -} - -export const EditHours = ({ - handleSubmit, - max, -}: EditHoursProps): JSX.Element => { - const { t } = useTranslation("workspacePage") - const [hours, setHours] = useState(1) - const styles = useStyles() - - return ( - // hours is NaN when user deletes the value, so treat it as 0 -
handleSubmit(Number.isNaN(hours) ? 0 : hours)}> - - setHours(parseInt(e.target.value))} - type="number" - /> - - -
- ) -} - -const useStyles = makeStyles(() => ({ - inputField: { - width: "70px", - "& .MuiOutlinedInput-root": { - height: "30px", - }, - }, - button: { - "&.MuiButton-root": { - minHeight: "30px", - height: "30px", - }, - }, -})) diff --git a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.stories.tsx b/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.stories.tsx deleted file mode 100644 index 033c9698ced01..0000000000000 --- a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.stories.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { Story } from "@storybook/react" -import dayjs from "dayjs" -import utc from "dayjs/plugin/utc" -import * as Mocks from "../../testHelpers/entities" -import { - WorkspaceScheduleButton, - WorkspaceScheduleButtonProps, -} from "./WorkspaceScheduleButton" - -dayjs.extend(utc) - -export default { - title: "components/WorkspaceScheduleButton", - component: WorkspaceScheduleButton, - argTypes: { - canUpdateWorkspace: { - defaultValue: true, - }, - deadlineMinusEnabled: { - defaultValue: (): boolean => false, - }, - deadlinePlusEnabled: { - defaultValue: (): boolean => false, - }, - }, -} - -const Template: Story = (args) => ( - -) - -export const NoScheduleNoTTL = Template.bind({}) -NoScheduleNoTTL.args = { - workspace: { - ...Mocks.MockWorkspace, - - latest_build: { - ...Mocks.MockWorkspaceBuild, - transition: "stop", - }, - autostart_schedule: undefined, - ttl_ms: undefined, - }, -} - -export const NoTTL = Template.bind({}) -NoTTL.args = { - workspace: { - ...Mocks.MockWorkspace, - latest_build: { - ...Mocks.MockWorkspaceBuild, - deadline: undefined, - }, - ttl_ms: undefined, - }, -} - -export const WorkspaceOffShort = Template.bind({}) -WorkspaceOffShort.args = { - workspace: { - ...Mocks.MockWorkspace, - - latest_build: { - ...Mocks.MockWorkspaceBuild, - transition: "stop", - }, - ttl_ms: 2 * 60 * 60 * 1000, // 2 hours - }, -} - -export const WorkspaceOffLong = Template.bind({}) -WorkspaceOffLong.args = { - deadlinePlusEnabled: () => true, - workspace: { - ...Mocks.MockWorkspace, - - latest_build: { - ...Mocks.MockWorkspaceBuild, - transition: "stop", - }, - ttl_ms: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years - }, -} - -export const WorkspaceOn = Template.bind({}) -WorkspaceOn.args = { - deadlineMinusEnabled: () => true, - deadlinePlusEnabled: () => true, - workspace: { - ...Mocks.MockWorkspace, - - latest_build: { - ...Mocks.MockWorkspaceBuild, - transition: "start", - deadline: "2022-05-17T23:59:00.00Z", - }, - ttl_ms: 2 * 365 * 24 * 60 * 60 * 1000, // 2 years - }, -} - -export const CannotEdit = Template.bind({}) -CannotEdit.args = { - workspace: { - ...Mocks.MockWorkspace, - - latest_build: { - ...Mocks.MockWorkspaceBuild, - transition: "stop", - }, - ttl_ms: 2 * 60 * 60 * 1000, // 2 hours - }, - canUpdateWorkspace: false, -} - -export const SmallViewport = Template.bind({}) -SmallViewport.args = { - ...WorkspaceOffShort.args, -} -SmallViewport.parameters = { - chromatic: { viewports: [320] }, -} diff --git a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.test.tsx b/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.test.tsx deleted file mode 100644 index 8e504bfa115b4..0000000000000 --- a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.test.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { screen } from "@testing-library/react" -import dayjs from "dayjs" -import utc from "dayjs/plugin/utc" -import { render } from "testHelpers/renderHelpers" -import * as TypesGen from "../../api/typesGenerated" -import * as Mocks from "../../testHelpers/entities" -import { - canEditDeadline, - WorkspaceScheduleButton, -} from "./WorkspaceScheduleButton" - -dayjs.extend(utc) - -describe("WorkspaceScheduleButton", () => { - describe("shouldDisplayPlusMinus", () => { - it("should not display if the workspace is not running", () => { - // Given: a stopped workspace - const workspace: TypesGen.Workspace = Mocks.MockStoppedWorkspace - - // Then: shouldDisplayPlusMinus should be false - expect(canEditDeadline(workspace)).toBeFalsy() - }) - - it("should display if the workspace is running", () => { - // Given: a stopped workspace - const workspace: TypesGen.Workspace = Mocks.MockWorkspace - - // Then: shouldDisplayPlusMinus should be false - expect(canEditDeadline(workspace)).toBeTruthy() - }) - }) - describe("enabling plus and minus buttons", () => { - it("should enable plus and minus buttons when deadline can be changed in either direction", async () => { - render( - , - ) - const plusButton = await screen.findByLabelText("Add hours to deadline") - const minusButton = await screen.findByLabelText( - "Subtract hours from deadline", - ) - expect(plusButton).toBeEnabled() - expect(minusButton).toBeEnabled() - }) - it("should disable plus button when deadline can't be extended", async () => { - render( - , - ) - const plusButton = await screen.findByLabelText("Add hours to deadline") - const minusButton = await screen.findByLabelText( - "Subtract hours from deadline", - ) - expect(plusButton).toBeDisabled() - expect(minusButton).toBeEnabled() - }) - it("should disable minus button when deadline can't be reduced", async () => { - render( - , - ) - const plusButton = await screen.findByLabelText("Add hours to deadline") - const minusButton = await screen.findByLabelText( - "Subtract hours from deadline", - ) - expect(plusButton).toBeEnabled() - expect(minusButton).toBeDisabled() - }) - }) -}) diff --git a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx b/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx deleted file mode 100644 index 9493a22481472..0000000000000 --- a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx +++ /dev/null @@ -1,270 +0,0 @@ -import Button from "@material-ui/core/Button" -import IconButton from "@material-ui/core/IconButton" -import Popover from "@material-ui/core/Popover" -import { makeStyles, Theme } from "@material-ui/core/styles" -import Tooltip from "@material-ui/core/Tooltip" -import AddIcon from "@material-ui/icons/Add" -import RemoveIcon from "@material-ui/icons/Remove" -import ScheduleIcon from "@material-ui/icons/Schedule" -import { Maybe } from "components/Conditionals/Maybe" -import { Stack } from "components/Stack/Stack" -import dayjs from "dayjs" -import advancedFormat from "dayjs/plugin/advancedFormat" -import duration from "dayjs/plugin/duration" -import relativeTime from "dayjs/plugin/relativeTime" -import timezone from "dayjs/plugin/timezone" -import utc from "dayjs/plugin/utc" -import { useRef, useState } from "react" -import { useTranslation } from "react-i18next" -import { colors } from "theme/colors" -import { Workspace } from "../../api/typesGenerated" -import { isWorkspaceOn } from "../../util/workspace" -import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule" -import { EditHours } from "./EditHours" -import { WorkspaceScheduleLabel } from "./WorkspaceScheduleLabel" - -// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're -// sorted alphabetically. -dayjs.extend(utc) -dayjs.extend(advancedFormat) -dayjs.extend(duration) -dayjs.extend(relativeTime) -dayjs.extend(timezone) - -export const canEditDeadline = (workspace: Workspace): boolean => { - return isWorkspaceOn(workspace) && Boolean(workspace.latest_build.deadline) -} - -export const shouldDisplayScheduleLabel = (workspace: Workspace): boolean => { - if (canEditDeadline(workspace)) { - return true - } - if (isWorkspaceOn(workspace)) { - return false - } - return Boolean(workspace.autostart_schedule) -} - -export interface WorkspaceScheduleButtonProps { - workspace: Workspace - onDeadlinePlus: (hours: number) => void - onDeadlineMinus: (hours: number) => void - maxDeadlineIncrease: number - maxDeadlineDecrease: number - canUpdateWorkspace: boolean -} - -export type EditMode = "add" | "subtract" | "off" - -export const WorkspaceScheduleButton: React.FC< - WorkspaceScheduleButtonProps -> = ({ - workspace, - onDeadlinePlus, - onDeadlineMinus, - maxDeadlineDecrease, - maxDeadlineIncrease, - canUpdateWorkspace, -}) => { - const { t } = useTranslation("workspacePage") - const anchorRef = useRef(null) - const [isOpen, setIsOpen] = useState(false) - const [editMode, setEditMode] = useState("off") - const id = isOpen ? "schedule-popover" : undefined - const styles = useStyles({ editMode }) - const deadlinePlusEnabled = maxDeadlineIncrease >= 1 - const deadlineMinusEnabled = maxDeadlineDecrease >= 1 - - const onClose = () => { - setIsOpen(false) - } - - const handleSubmitHours = (hours: number) => { - if (hours !== 0) { - if (editMode === "add") { - onDeadlinePlus(hours) - } - if (editMode === "subtract") { - onDeadlineMinus(hours) - } - } - setEditMode("off") - } - - return ( - - - - - - - - { - setEditMode("subtract") - }} - > - - - - - { - setEditMode("add") - }} - > - - - - - - - - - - - - - <> - - - - - - - ) -} - -interface StyleProps { - editMode: EditMode -} - -const useStyles = makeStyles((theme) => ({ - wrapper: { - display: "inline-flex", - alignItems: "center", - - [theme.breakpoints.down("sm")]: { - flexDirection: "column", - }, - }, - label: { - padding: theme.spacing(0, 2), - color: theme.palette.text.secondary, - borderRadius: theme.shape.borderRadius, - border: `1px solid ${colors.gray[11]}`, // Same as outlined button - display: "flex", - height: theme.spacing(5), // Same as button - alignItems: "center", - borderTopRightRadius: 0, - borderBottomRightRadius: 0, - borderRight: 0, - - [theme.breakpoints.down("sm")]: { - width: "100%", - padding: theme.spacing(1.5, 2), - flexDirection: "column", - }, - }, - actions: { - [theme.breakpoints.down("sm")]: { - marginLeft: "auto", - display: "flex", - paddingLeft: theme.spacing(1), - marginRight: -theme.spacing(1), - }, - }, - scheduleButton: { - flexShrink: 0, - - "&.label": { - borderRadius: `0px ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px 0px`, - }, - - [theme.breakpoints.down("sm")]: { - width: "100%", - - "&.label": { - borderRadius: `0 0 ${theme.shape.borderRadius}px ${theme.shape.borderRadius}px`, - borderLeft: 0, - borderTop: `1px solid ${theme.palette.divider}`, - }, - }, - }, - addButton: { - borderRadius: theme.shape.borderRadius, - border: ({ editMode }) => - editMode === "add" - ? `2px solid ${theme.palette.primary.main}` - : "2px solid transparent", - }, - subtractButton: { - borderRadius: theme.shape.borderRadius, - border: ({ editMode }) => - editMode === "subtract" - ? `2px solid ${theme.palette.primary.main}` - : "2px solid transparent", - }, - popoverPaper: { - padding: `${theme.spacing(2)}px ${theme.spacing(3)}px ${theme.spacing( - 3, - )}px`, - }, -})) diff --git a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleLabel.tsx b/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleLabel.tsx deleted file mode 100644 index 24bec420d9863..0000000000000 --- a/site/src/components/WorkspaceScheduleButton/WorkspaceScheduleLabel.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { makeStyles } from "@material-ui/core/styles" -import { ChooseOne, Cond } from "components/Conditionals/ChooseOne" -import { Maybe } from "components/Conditionals/Maybe" -import { useTranslation } from "react-i18next" -import { Workspace } from "../../api/typesGenerated" -import { combineClasses } from "../../util/combineClasses" -import { - autostartDisplay, - autostopDisplay, - isShuttingDown, -} from "../../util/schedule" -import { isWorkspaceOn } from "../../util/workspace" - -export const WorkspaceScheduleLabel: React.FC<{ workspace: Workspace }> = ({ - workspace, -}) => { - const styles = useStyles() - const { t } = useTranslation("common") - - return ( - - - - - {t("schedule.autostopLabel")} - {" "} - {autostopDisplay(workspace)} - - - - - {t("schedule.autostartLabel")}{" "} - - {autostartDisplay(workspace.autostart_schedule)} - - - - - ) -} - -const useStyles = makeStyles((theme) => ({ - labelText: { - marginRight: theme.spacing(1), - marginLeft: theme.spacing(1), - lineHeight: "160%", - - [theme.breakpoints.down("sm")]: { - marginRight: 0, - width: "100%", - }, - }, - - value: { - [theme.breakpoints.down("sm")]: { - whiteSpace: "nowrap", - }, - }, -})) From 960046970aaa0db5ba34d8fe95e27b1caa516aa4 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Tue, 11 Apr 2023 15:17:25 +0000 Subject: [PATCH 10/10] Make stats wrap --- site/src/components/Stats/Stats.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/site/src/components/Stats/Stats.tsx b/site/src/components/Stats/Stats.tsx index fadcd302e7edd..0b2880979876c 100644 --- a/site/src/components/Stats/Stats.tsx +++ b/site/src/components/Stats/Stats.tsx @@ -30,6 +30,7 @@ const useStyles = makeStyles((theme) => ({ alignItems: "center", color: theme.palette.text.secondary, margin: "0px", + flexWrap: "wrap", [theme.breakpoints.down("sm")]: { display: "block",