refactor(site): add minor improvements to the schedule controls (#10756)

Demo:

https://github.com/coder/coder/assets/3165839/d6ea83c0-6390-42d9-bd48-3438fc8685db
This commit is contained in:
Bruno Quaresma
2023-11-17 12:03:44 -03:00
committed by GitHub
parent 20c2dda13f
commit e6f11a383a
2 changed files with 92 additions and 19 deletions
+72 -14
View File
@@ -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<WorkspaceStatsProps> = ({
css={styles.statsItem}
label={getScheduleLabel(workspace)}
value={
<span css={styles.scheduleValue}>
<Link
component={RouterLink}
to="settings/schedule"
title="Schedule settings"
>
{isWorkspaceOn(workspace)
? autostopDisplay(workspace)
: autostartDisplay(workspace.autostart_schedule)}
</Link>
<div css={styles.scheduleValue}>
{isWorkspaceOn(workspace) ? (
<AutoStopDisplay workspace={workspace} />
) : (
<ScheduleSettingsLink>
{autostartDisplay(workspace.autostart_schedule)}
</ScheduleSettingsLink>
)}
{canUpdateWorkspace && canEditDeadline(workspace) && (
<span css={styles.scheduleControls}>
<Popover>
@@ -178,7 +179,7 @@ export const WorkspaceStats: FC<WorkspaceStatsProps> = ({
</Popover>
</span>
)}
</span>
</div>
}
/>
)}
@@ -220,6 +221,7 @@ const AddTimeContent = (props: {
}}
>
<TextField
autoFocus
name="hours"
type="number"
size="small"
@@ -268,6 +270,7 @@ export const DecreaseTimeContent = (props: {
}}
>
<TextField
autoFocus
name="hours"
type="number"
size="small"
@@ -292,6 +295,47 @@ export const DecreaseTimeContent = (props: {
);
};
const AutoStopDisplay = (props: { workspace: Workspace }) => {
const { workspace } = props;
const display = autostopDisplay(workspace);
if (display.tooltip) {
return (
<Tooltip title={display.tooltip}>
<ScheduleSettingsLink
css={(theme) => ({
color: isShutdownSoon(workspace)
? `${theme.palette.warning.light} !important`
: undefined,
})}
>
{display.message}
</ScheduleSettingsLink>
</Tooltip>
);
}
return <ScheduleSettingsLink>{display.message}</ScheduleSettingsLink>;
};
const ScheduleSettingsLink = forwardRef<HTMLAnchorElement, LinkProps>(
(props, ref) => {
return (
<Link
ref={ref}
component={RouterLink}
to="settings/schedule"
css={{
"&:first-letter": {
textTransform: "uppercase",
},
}}
{...props}
/>
);
},
);
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: {
+20 -5
View File
@@ -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}`,
};
}
};