Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit a564dcb

Browse files
committedJul 1, 2022
Cleaning up components
1 parent ead1ff9 commit a564dcb

File tree

4 files changed

+124
-138
lines changed

4 files changed

+124
-138
lines changed
 

‎site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx

Lines changed: 10 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import Link from "@material-ui/core/Link"
22
import { makeStyles } from "@material-ui/core/styles"
3-
import cronstrue from "cronstrue"
43
import dayjs from "dayjs"
54
import advancedFormat from "dayjs/plugin/advancedFormat"
65
import duration from "dayjs/plugin/duration"
@@ -11,8 +10,12 @@ import { FC } from "react"
1110
import { Link as RouterLink } from "react-router-dom"
1211
import { Workspace } from "../../api/typesGenerated"
1312
import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
14-
import { extractTimezone, stripTimezone } from "../../util/schedule"
15-
import { isWorkspaceOn } from "../../util/workspace"
13+
import {
14+
autoStartDisplay,
15+
autoStopDisplay,
16+
extractTimezone,
17+
Language as ScheduleLanguage,
18+
} from "../../util/schedule"
1619
import { Stack } from "../Stack/Stack"
1720

1821
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
@@ -24,45 +27,6 @@ dayjs.extend(relativeTime)
2427
dayjs.extend(timezone)
2528

2629
export const Language = {
27-
autoStartDisplay: (schedule: string | undefined): string => {
28-
if (schedule) {
29-
return cronstrue.toString(stripTimezone(schedule), { throwExceptionOnParseError: false })
30-
} else {
31-
return "Manual"
32-
}
33-
},
34-
autoStartLabel: "Starts at",
35-
autoStopLabel: "Stops at",
36-
autoStopDisplay: (workspace: Workspace): string => {
37-
const deadline = dayjs(workspace.latest_build.deadline).utc()
38-
// a manual shutdown has a deadline of '"0001-01-01T00:00:00Z"'
39-
// SEE: #1834
40-
const hasDeadline = deadline.year() > 1
41-
const ttl = workspace.ttl_ms
42-
43-
if (isWorkspaceOn(workspace) && hasDeadline) {
44-
// Workspace is on --> derive from latest_build.deadline. Note that the
45-
// user may modify their workspace object (ttl) while the workspace is
46-
// running and depending on system semantics, the deadline may still
47-
// represent the previously defined ttl. Thus, we always derive from the
48-
// deadline as the source of truth.
49-
const now = dayjs().utc()
50-
if (now.isAfter(deadline)) {
51-
return "Workspace is shutting down"
52-
} else {
53-
return deadline.tz(dayjs.tz.guess()).format("MMM D, YYYY h:mm A")
54-
}
55-
} else if (!ttl || ttl < 1) {
56-
// If the workspace is not on, and the ttl is 0 or undefined, then the
57-
// workspace is set to manually shutdown.
58-
return "Manual"
59-
} else {
60-
// The workspace has a ttl set, but is either in an unknown state or is
61-
// not running. Therefore, we derive from workspace.ttl.
62-
const duration = dayjs.duration(ttl, "milliseconds")
63-
return `${duration.humanize()} after start`
64-
}
65-
},
6630
editScheduleLink: "Edit schedule",
6731
timezoneLabel: "Timezone",
6832
}
@@ -85,16 +49,16 @@ export const WorkspaceSchedule: FC<WorkspaceScheduleProps> = ({ workspace }) =>
8549
<span className={styles.scheduleValue}>{timezone}</span>
8650
</div>
8751
<div>
88-
<span className={styles.scheduleLabel}>{Language.autoStartLabel}</span>
52+
<span className={styles.scheduleLabel}>{ScheduleLanguage.autoStartLabel}</span>
8953
<span className={[styles.scheduleValue, "chromatic-ignore"].join(" ")}>
90-
{Language.autoStartDisplay(workspace.autostart_schedule)}
54+
{autoStartDisplay(workspace.autostart_schedule)}
9155
</span>
9256
</div>
9357
<div>
94-
<span className={styles.scheduleLabel}>{Language.autoStopLabel}</span>
58+
<span className={styles.scheduleLabel}>{ScheduleLanguage.autoStopLabel}</span>
9559
<Stack direction="row">
9660
<span className={[styles.scheduleValue, "chromatic-ignore"].join(" ")}>
97-
{Language.autoStopDisplay(workspace)}
61+
{autoStopDisplay(workspace)}
9862
</span>
9963
</Stack>
10064
</div>

‎site/src/components/WorkspaceScheduleButton/WorkspaceScheduleButton.tsx

Lines changed: 3 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import Tooltip from "@material-ui/core/Tooltip"
66
import AddIcon from "@material-ui/icons/Add"
77
import RemoveIcon from "@material-ui/icons/Remove"
88
import ScheduleIcon from "@material-ui/icons/Schedule"
9-
import cronstrue from "cronstrue"
109
import dayjs from "dayjs"
1110
import advancedFormat from "dayjs/plugin/advancedFormat"
1211
import duration from "dayjs/plugin/duration"
@@ -15,10 +14,10 @@ import timezone from "dayjs/plugin/timezone"
1514
import utc from "dayjs/plugin/utc"
1615
import { useRef, useState } from "react"
1716
import { Workspace } from "../../api/typesGenerated"
18-
import { extractTimezone, stripTimezone } from "../../util/schedule"
1917
import { isWorkspaceOn } from "../../util/workspace"
2018
import { Stack } from "../Stack/Stack"
2119
import { WorkspaceSchedule } from "../WorkspaceSchedule/WorkspaceSchedule"
20+
import { WorkspaceScheduleLabel } from "./WorkspaceScheduleLabel"
2221

2322
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
2423
// sorted alphabetically.
@@ -29,60 +28,8 @@ dayjs.extend(relativeTime)
2928
dayjs.extend(timezone)
3029

3130
export const Language = {
32-
autoStartDisplay: (schedule: string | undefined): string => {
33-
if (schedule) {
34-
return (
35-
cronstrue
36-
.toString(stripTimezone(schedule), { throwExceptionOnParseError: false })
37-
// We don't want to keep the At because it is on the label
38-
.replace("At", "")
39-
)
40-
} else {
41-
return "Manual"
42-
}
43-
},
44-
autoStartLabel: "Starts at",
45-
autoStopLabel: "Stops at",
46-
workspaceShuttingDownLabel: "Workspace is shutting down",
47-
autoStopDisplay: (workspace: Workspace): string => {
48-
const deadline = dayjs(workspace.latest_build.deadline).utc()
49-
// a manual shutdown has a deadline of '"0001-01-01T00:00:00Z"'
50-
// SEE: #1834
51-
const hasDeadline = deadline.year() > 1
52-
const ttl = workspace.ttl_ms
53-
54-
if (isWorkspaceOn(workspace) && hasDeadline) {
55-
// Workspace is on --> derive from latest_build.deadline. Note that the
56-
// user may modify their workspace object (ttl) while the workspace is
57-
// running and depending on system semantics, the deadline may still
58-
// represent the previously defined ttl. Thus, we always derive from the
59-
// deadline as the source of truth.
60-
const now = dayjs().utc()
61-
if (now.isAfter(deadline)) {
62-
return Language.workspaceShuttingDownLabel
63-
} else {
64-
return deadline.tz(dayjs.tz.guess()).format("MMM D, YYYY h:mm A")
65-
}
66-
} else if (!ttl || ttl < 1) {
67-
// If the workspace is not on, and the ttl is 0 or undefined, then the
68-
// workspace is set to manually shutdown.
69-
return "Manual"
70-
} else {
71-
// The workspace has a ttl set, but is either in an unknown state or is
72-
// not running. Therefore, we derive from workspace.ttl.
73-
const duration = dayjs.duration(ttl, "milliseconds")
74-
return `${duration.humanize()} after start`
75-
}
76-
},
77-
editScheduleLink: "Edit schedule",
7831
editDeadlineMinus: "Subtract one hour",
7932
editDeadlinePlus: "Add one hour",
80-
scheduleHeader: (workspace: Workspace): string => {
81-
const tz = workspace.autostart_schedule
82-
? extractTimezone(workspace.autostart_schedule)
83-
: dayjs.tz.guess()
84-
return `Schedule (${tz})`
85-
},
8633
}
8734

8835
export const shouldDisplayPlusMinus = (workspace: Workspace): boolean => {
@@ -103,44 +50,16 @@ export const deadlinePlusDisabled = (workspace: Workspace, now: dayjs.Dayjs): bo
10350
return delta >= 24 * 60 * 60 * 1000 // 24 hours
10451
}
10552

106-
const WorkspaceScheduleLabel: React.FC<{ workspace: Workspace }> = ({ workspace }) => {
107-
const styles = useStyles()
108-
109-
if (isWorkspaceOn(workspace)) {
110-
const stopLabel = Language.autoStopDisplay(workspace)
111-
const isShuttingDown = stopLabel === Language.workspaceShuttingDownLabel
112-
113-
// If it is shutting down, we don't need to display the auto stop label
114-
return (
115-
<span className={styles.labelText}>
116-
{!isShuttingDown && (
117-
<strong className={styles.labelStrong}>{Language.autoStopLabel}</strong>
118-
)}
119-
{stopLabel}
120-
</span>
121-
)
122-
}
123-
124-
return (
125-
<span className={styles.labelText}>
126-
<strong className={styles.labelStrong}>{Language.autoStartLabel}</strong>
127-
{Language.autoStartDisplay(workspace.autostart_schedule)}
128-
</span>
129-
)
130-
}
131-
13253
export interface WorkspaceScheduleButtonProps {
13354
workspace: Workspace
13455
onDeadlinePlus: () => void
13556
onDeadlineMinus: () => void
136-
now?: dayjs.Dayjs
13757
}
13858

13959
export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = ({
14060
workspace,
14161
onDeadlinePlus,
14262
onDeadlineMinus,
143-
now,
14463
}) => {
14564
const anchorRef = useRef<HTMLButtonElement>(null)
14665
const [isOpen, setIsOpen] = useState(false)
@@ -160,7 +79,7 @@ export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = (
16079
<IconButton
16180
className={styles.iconButton}
16281
size="small"
163-
disabled={deadlineMinusDisabled(workspace, now ?? dayjs())}
82+
disabled={deadlineMinusDisabled(workspace, dayjs())}
16483
onClick={onDeadlineMinus}
16584
>
16685
<Tooltip title={Language.editDeadlineMinus}>
@@ -170,7 +89,7 @@ export const WorkspaceScheduleButton: React.FC<WorkspaceScheduleButtonProps> = (
17089
<IconButton
17190
className={styles.iconButton}
17291
size="small"
173-
disabled={deadlinePlusDisabled(workspace, now ?? dayjs())}
92+
disabled={deadlinePlusDisabled(workspace, dayjs())}
17493
onClick={onDeadlinePlus}
17594
>
17695
<Tooltip title={Language.editDeadlinePlus}>
@@ -231,14 +150,6 @@ const useStyles = makeStyles((theme) => ({
231150
minHeight: 42,
232151
},
233152

234-
labelText: {
235-
marginRight: theme.spacing(2),
236-
},
237-
238-
labelStrong: {
239-
marginRight: theme.spacing(0.5),
240-
},
241-
242153
iconButton: {
243154
borderRadius: 2,
244155
},
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { makeStyles } from "@material-ui/core/styles"
2+
import { Workspace } from "../../api/typesGenerated"
3+
import { autoStartDisplay, autoStopDisplay, Language } from "../../util/schedule"
4+
import { isWorkspaceOn } from "../../util/workspace"
5+
6+
export const WorkspaceScheduleLabel: React.FC<{ workspace: Workspace }> = ({ workspace }) => {
7+
const styles = useStyles()
8+
9+
if (isWorkspaceOn(workspace)) {
10+
const stopLabel = autoStopDisplay(workspace)
11+
const isShuttingDown = stopLabel === Language.workspaceShuttingDownLabel
12+
13+
// If it is shutting down, we don't need to display the auto stop label
14+
return (
15+
<span className={styles.labelText}>
16+
{!isShuttingDown && (
17+
<strong className={styles.labelStrong}>{Language.autoStopLabel}</strong>
18+
)}
19+
{stopLabel}
20+
</span>
21+
)
22+
}
23+
24+
return (
25+
<span className={styles.labelText}>
26+
<strong className={styles.labelStrong}>{Language.autoStartLabel}</strong>
27+
{autoStartDisplay(workspace.autostart_schedule)}
28+
</span>
29+
)
30+
}
31+
32+
const useStyles = makeStyles((theme) => ({
33+
labelText: {
34+
marginRight: theme.spacing(2),
35+
},
36+
37+
labelStrong: {
38+
marginRight: theme.spacing(0.5),
39+
},
40+
}))

‎site/src/util/schedule.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
import cronstrue from "cronstrue"
2+
import dayjs from "dayjs"
3+
import advancedFormat from "dayjs/plugin/advancedFormat"
4+
import duration from "dayjs/plugin/duration"
5+
import relativeTime from "dayjs/plugin/relativeTime"
6+
import timezone from "dayjs/plugin/timezone"
7+
import utc from "dayjs/plugin/utc"
8+
import { Workspace } from "../api/typesGenerated"
9+
import { isWorkspaceOn } from "./workspace"
10+
11+
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
12+
// sorted alphabetically.
13+
dayjs.extend(utc)
14+
dayjs.extend(advancedFormat)
15+
dayjs.extend(duration)
16+
dayjs.extend(relativeTime)
17+
dayjs.extend(timezone)
18+
119
/**
220
* @fileoverview Client-side counterpart of the coderd/autostart/schedule Go
321
* package. This package is a variation on crontab that uses minute, hour and
@@ -30,3 +48,56 @@ export const extractTimezone = (raw: string, defaultTZ = DEFAULT_TIMEZONE): stri
3048
return defaultTZ
3149
}
3250
}
51+
52+
/** Language used in the schedule components */
53+
export const Language = {
54+
manual: "Manual",
55+
workspaceShuttingDownLabel: "Workspace is shutting down",
56+
afterStart: "after start",
57+
autoStartLabel: "Starts at",
58+
autoStopLabel: "Stops at",
59+
}
60+
61+
export const autoStartDisplay = (schedule: string | undefined): string => {
62+
if (schedule) {
63+
return (
64+
cronstrue
65+
.toString(stripTimezone(schedule), { throwExceptionOnParseError: false })
66+
// We don't want to keep the At because it is on the label
67+
.replace("At", "")
68+
)
69+
} else {
70+
return Language.manual
71+
}
72+
}
73+
74+
export const autoStopDisplay = (workspace: Workspace): string => {
75+
const deadline = dayjs(workspace.latest_build.deadline).utc()
76+
// a manual shutdown has a deadline of '"0001-01-01T00:00:00Z"'
77+
// SEE: #1834
78+
const hasDeadline = deadline.year() > 1
79+
const ttl = workspace.ttl_ms
80+
81+
if (isWorkspaceOn(workspace) && hasDeadline) {
82+
// Workspace is on --> derive from latest_build.deadline. Note that the
83+
// user may modify their workspace object (ttl) while the workspace is
84+
// running and depending on system semantics, the deadline may still
85+
// represent the previously defined ttl. Thus, we always derive from the
86+
// deadline as the source of truth.
87+
const now = dayjs().utc()
88+
if (now.isAfter(deadline)) {
89+
return Language.workspaceShuttingDownLabel
90+
} else {
91+
return deadline.tz(dayjs.tz.guess()).format("MMM D, YYYY h:mm A")
92+
}
93+
} else if (!ttl || ttl < 1) {
94+
// If the workspace is not on, and the ttl is 0 or undefined, then the
95+
// workspace is set to manually shutdown.
96+
return Language.manual
97+
} else {
98+
// The workspace has a ttl set, but is either in an unknown state or is
99+
// not running. Therefore, we derive from workspace.ttl.
100+
const duration = dayjs.duration(ttl, "milliseconds")
101+
return `${duration.humanize()} ${Language.afterStart}`
102+
}
103+
}

0 commit comments

Comments
 (0)
Failed to load comments.