From 585376004cf0de3d91de3469d3ce659960263693 Mon Sep 17 00:00:00 2001 From: BrunoQuaresma Date: Fri, 17 Nov 2023 13:51:38 +0000 Subject: [PATCH] refactor(site): add minor improvements to the schedule controls --- .../pages/WorkspacePage/WorkspaceStats.tsx | 86 ++++++++++++++++--- site/src/utils/schedule.ts | 25 ++++-- 2 files changed, 92 insertions(+), 19 deletions(-) diff --git a/site/src/pages/WorkspacePage/WorkspaceStats.tsx b/site/src/pages/WorkspacePage/WorkspaceStats.tsx index a173d04d1b339..b63a9a686a4c7 100644 --- a/site/src/pages/WorkspacePage/WorkspaceStats.tsx +++ b/site/src/pages/WorkspacePage/WorkspaceStats.tsx @@ -1,8 +1,8 @@ import { css } from "@emotion/css"; import { type Interpolation, type Theme } from "@emotion/react"; -import Link from "@mui/material/Link"; +import Link, { LinkProps } from "@mui/material/Link"; import { WorkspaceOutdatedTooltip } from "components/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip"; -import { type FC } from "react"; +import { forwardRef, type FC } from "react"; import { Link as RouterLink } from "react-router-dom"; import { getDisplayWorkspaceTemplateName, @@ -26,6 +26,8 @@ import { } from "components/Popover/Popover"; import { workspaceQuota } from "api/queries/workspaceQuota"; import { useQuery } from "react-query"; +import Tooltip from "@mui/material/Tooltip"; +import _ from "lodash"; const Language = { workspaceDetails: "Workspace Details", @@ -120,16 +122,15 @@ export const WorkspaceStats: FC = ({ css={styles.statsItem} label={getScheduleLabel(workspace)} value={ - - - {isWorkspaceOn(workspace) - ? autostopDisplay(workspace) - : autostartDisplay(workspace.autostart_schedule)} - +
+ {isWorkspaceOn(workspace) ? ( + + ) : ( + + {autostartDisplay(workspace.autostart_schedule)} + + )} + {canUpdateWorkspace && canEditDeadline(workspace) && ( @@ -178,7 +179,7 @@ export const WorkspaceStats: FC = ({ )} - +
} /> )} @@ -220,6 +221,7 @@ const AddTimeContent = (props: { }} > { + const { workspace } = props; + const display = autostopDisplay(workspace); + + if (display.tooltip) { + return ( + + ({ + color: isShutdownSoon(workspace) + ? `${theme.palette.warning.light} !important` + : undefined, + })} + > + {display.message} + + + ); + } + + return {display.message}; +}; + +const ScheduleSettingsLink = forwardRef( + (props, ref) => { + return ( + + ); + }, +); + export const canEditDeadline = (workspace: Workspace): boolean => { return isWorkspaceOn(workspace) && Boolean(workspace.latest_build.deadline); }; @@ -307,7 +351,19 @@ export const shouldDisplayScheduleLabel = (workspace: Workspace): boolean => { }; const getScheduleLabel = (workspace: Workspace) => { - return isWorkspaceOn(workspace) ? "Stops at" : "Starts at"; + return isWorkspaceOn(workspace) ? "Stops" : "Starts at"; +}; + +const isShutdownSoon = (workspace: Workspace): boolean => { + const deadline = workspace.latest_build.deadline; + if (!deadline) { + return false; + } + const deadlineDate = new Date(deadline); + const now = new Date(); + const diff = deadlineDate.getTime() - now.getTime(); + const oneHour = 1000 * 60 * 60; + return diff < oneHour; }; const timePopoverFieldInputStyles = css` @@ -369,6 +425,7 @@ const styles = { timePopoverTitle: { fontWeight: 600, + marginBottom: 8, }, timePopoverDescription: (theme) => ({ @@ -380,6 +437,7 @@ const styles = { alignItems: "center", gap: 8, padding: "8px 0", + marginTop: 12, }, timePopoverField: { diff --git a/site/src/utils/schedule.ts b/site/src/utils/schedule.ts index 8827261cd9273..c2a9a77f9e4ab 100644 --- a/site/src/utils/schedule.ts +++ b/site/src/utils/schedule.ts @@ -88,7 +88,12 @@ export const isShuttingDown = ( return isWorkspaceOn(workspace) && now.isAfter(deadline); }; -export const autostopDisplay = (workspace: Workspace): string => { +export const autostopDisplay = ( + workspace: Workspace, +): { + message: string; + tooltip?: string; +} => { const ttl = workspace.ttl_ms; if (isWorkspaceOn(workspace) && workspace.latest_build.deadline) { @@ -100,19 +105,29 @@ export const autostopDisplay = (workspace: Workspace): string => { const deadline = dayjs(workspace.latest_build.deadline).utc(); if (isShuttingDown(workspace, deadline)) { - return Language.workspaceShuttingDownLabel; + return { + message: Language.workspaceShuttingDownLabel, + }; } else { - return deadline.tz(dayjs.tz.guess()).format("MMMM D, YYYY h:mm A"); + const deadlineTz = deadline.tz(dayjs.tz.guess()); + return { + message: deadlineTz.fromNow(), + tooltip: deadlineTz.format("MMMM D, YYYY h:mm A"), + }; } } else if (!ttl || ttl < 1) { // If the workspace is not on, and the ttl is 0 or undefined, then the // workspace is set to manually shutdown. - return Language.manual; + return { + message: Language.manual, + }; } else { // The workspace has a ttl set, but is either in an unknown state or is // not running. Therefore, we derive from workspace.ttl. const duration = dayjs.duration(ttl, "milliseconds"); - return `${duration.humanize()} ${Language.afterStart}`; + return { + message: `${duration.humanize()} ${Language.afterStart}`, + }; } };