From aca872391f0b420361b0a1aa93bda4da8afa1174 Mon Sep 17 00:00:00 2001 From: Bruno Date: Mon, 23 May 2022 14:20:08 +0000 Subject: [PATCH] refactor: Move schedule info to the sidebar --- site/src/components/Workspace/Workspace.tsx | 29 ++++- .../WorkspaceSchedule.stories.tsx | 17 +++ .../WorkspaceSchedule/WorkspaceSchedule.tsx | 118 ++++++++++++++++++ .../WorkspaceStats/WorkspaceStats.tsx | 55 -------- 4 files changed, 158 insertions(+), 61 deletions(-) create mode 100644 site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx create mode 100644 site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx diff --git a/site/src/components/Workspace/Workspace.tsx b/site/src/components/Workspace/Workspace.tsx index 8f494ef69673e..60e9ef7d3f5e6 100644 --- a/site/src/components/Workspace/Workspace.tsx +++ b/site/src/components/Workspace/Workspace.tsx @@ -8,6 +8,7 @@ import { BuildsTable } from "../BuildsTable/BuildsTable" import { Resources } from "../Resources/Resources" import { Stack } from "../Stack/Stack" import { WorkspaceActions } from "../WorkspaceActions/WorkspaceActions" +import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule" import { WorkspaceSection } from "../WorkspaceSection/WorkspaceSection" import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats" @@ -64,12 +65,18 @@ export const Workspace: React.FC = ({ - - - - - - + + + + + + + + + + + + ) @@ -99,6 +106,16 @@ export const useStyles = makeStyles((theme) => { fontFamily: "inherit", marginTop: theme.spacing(0.5), }, + layout: { + alignItems: "flex-start", + }, + main: { + width: "100%", + }, + sidebar: { + width: theme.spacing(32), + flexShrink: 0, + }, timelineContents: { margin: 0, }, diff --git a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx new file mode 100644 index 0000000000000..407810bf264a1 --- /dev/null +++ b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.stories.tsx @@ -0,0 +1,17 @@ +import { Story } from "@storybook/react" +import React from "react" +import { MockWorkspace } from "../../testHelpers/renderHelpers" +import { WorkspaceSchedule, WorkspaceScheduleProps } from "./WorkspaceSchedule" + +export default { + title: "components/WorkspaceSchedule", + component: WorkspaceSchedule, + argTypes: {}, +} + +const Template: Story = (args) => + +export const Example = Template.bind({}) +Example.args = { + workspace: MockWorkspace, +} diff --git a/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx new file mode 100644 index 0000000000000..8e3b33af0f52d --- /dev/null +++ b/site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx @@ -0,0 +1,118 @@ +import Link from "@material-ui/core/Link" +import { makeStyles } from "@material-ui/core/styles" +import Typography from "@material-ui/core/Typography" +import ScheduleIcon from "@material-ui/icons/Schedule" +import cronstrue from "cronstrue" +import dayjs from "dayjs" +import duration from "dayjs/plugin/duration" +import relativeTime from "dayjs/plugin/relativeTime" +import React from "react" +import { Workspace } from "../../api/typesGenerated" +import { MONOSPACE_FONT_FAMILY } from "../../theme/constants" +import { extractTimezone, stripTimezone } from "../../util/schedule" +import { Stack } from "../Stack/Stack" + +dayjs.extend(duration) +dayjs.extend(relativeTime) + +const autoStartLabel = (schedule: string): string => { + const prefix = "Start" + + if (schedule) { + return `${prefix} (${extractTimezone(schedule)})` + } else { + return prefix + } +} + +const autoStartDisplay = (schedule: string): string => { + if (schedule) { + return cronstrue.toString(stripTimezone(schedule), { throwExceptionOnParseError: false }) + } + return "Manual" +} + +const autoStopDisplay = (workspace: Workspace): string => { + const latest = workspace.latest_build + + if (!workspace.ttl || workspace.ttl < 1) { + return "Manual" + } + + if (latest.transition === "start") { + const now = dayjs() + const updatedAt = dayjs(latest.updated_at) + const deadline = updatedAt.add(workspace.ttl / 1_000_000, "ms") + if (now.isAfter(deadline)) { + return "Workspace is shutting down now" + } + return now.to(deadline) + } + + const duration = dayjs.duration(workspace.ttl / 1_000_000, "milliseconds") + return `${duration.humanize()} after start` +} + +export interface WorkspaceScheduleProps { + workspace: Workspace +} + +export const WorkspaceSchedule: React.FC = ({ workspace }) => { + const styles = useStyles() + + return ( +
+ + + + Schedule + +
+ {autoStartLabel(workspace.autostart_schedule)} + {autoStartDisplay(workspace.autostart_schedule)} +
+
+ Shutdown + {autoStopDisplay(workspace)} +
+
+ Edit schedule +
+
+
+ ) +} + +const useStyles = makeStyles((theme) => ({ + schedule: { + fontFamily: MONOSPACE_FONT_FAMILY, + }, + title: { + fontWeight: 600, + + fontFamily: "inherit", + display: "flex", + alignItems: "center", + }, + scheduleIcon: { + width: 16, + height: 16, + marginRight: theme.spacing(1), + }, + scheduleLabel: { + fontSize: 12, + textTransform: "uppercase", + display: "block", + fontWeight: 600, + color: theme.palette.text.secondary, + }, + scheduleValue: { + fontSize: 16, + marginTop: theme.spacing(0.25), + display: "inline-block", + color: theme.palette.text.secondary, + }, + scheduleAction: { + cursor: "pointer", + }, +})) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index e22e800a74149..d22e91e0eee1c 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -1,58 +1,13 @@ import Link from "@material-ui/core/Link" import { makeStyles, useTheme } from "@material-ui/core/styles" -import cronstrue from "cronstrue" import dayjs from "dayjs" -import duration from "dayjs/plugin/duration" -import relativeTime from "dayjs/plugin/relativeTime" import React from "react" import { Link as RouterLink } from "react-router-dom" import { Workspace } from "../../api/typesGenerated" import { CardRadius, MONOSPACE_FONT_FAMILY } from "../../theme/constants" import { combineClasses } from "../../util/combineClasses" -import { extractTimezone, stripTimezone } from "../../util/schedule" import { getDisplayStatus } from "../../util/workspace" -dayjs.extend(duration) -dayjs.extend(relativeTime) - -const autoStartLabel = (schedule: string): string => { - const prefix = "Start" - - if (schedule) { - return `${prefix} (${extractTimezone(schedule)})` - } else { - return prefix - } -} - -const autoStartDisplay = (schedule: string): string => { - if (schedule) { - return cronstrue.toString(stripTimezone(schedule), { throwExceptionOnParseError: false }) - } - return "Manual" -} - -const autoStopDisplay = (workspace: Workspace): string => { - const latest = workspace.latest_build - - if (!workspace.ttl || workspace.ttl < 1) { - return "Manual" - } - - if (latest.transition === "start") { - const now = dayjs() - const updatedAt = dayjs(latest.updated_at) - const deadline = updatedAt.add(workspace.ttl / 1_000_000, "ms") - if (now.isAfter(deadline)) { - return "workspace is shutting down now" - } - return now.to(deadline) - } - - const duration = dayjs.duration(workspace.ttl / 1_000_000, "milliseconds") - return `${duration.humanize()} after start` -} - export interface WorkspaceStatsProps { workspace: Workspace } @@ -99,16 +54,6 @@ export const WorkspaceStats: React.FC = ({ workspace }) => Last Built {dayjs().to(dayjs(workspace.latest_build.created_at))} -
-
- {autoStartLabel(workspace.autostart_schedule)} - {autoStartDisplay(workspace.autostart_schedule)} -
-
-
- Shutdown - {autoStopDisplay(workspace)} -
) }