-
Notifications
You must be signed in to change notification settings - Fork 577
/
WorkspaceSchedule.tsx
148 lines (139 loc) · 4.77 KB
/
WorkspaceSchedule.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
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 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 { FC } from "react"
import { Link as RouterLink } from "react-router-dom"
import { Workspace } from "../../api/typesGenerated"
import { MONOSPACE_FONT_FAMILY } from "../../theme/constants"
import { extractTimezone, stripTimezone } from "../../util/schedule"
import { isWorkspaceOn } from "../../util/workspace"
import { Stack } from "../Stack/Stack"
dayjs.extend(advancedFormat)
dayjs.extend(utc)
dayjs.extend(duration)
dayjs.extend(relativeTime)
dayjs.extend(timezone)
export const Language = {
autoStartDisplay: (schedule: string | undefined): string => {
if (schedule) {
return cronstrue.toString(stripTimezone(schedule), { throwExceptionOnParseError: false })
} else {
return "Manual"
}
},
autoStartLabel: (schedule: string | undefined): string => {
const prefix = "Start"
const timezone = schedule ? extractTimezone(schedule) : dayjs.tz.guess()
if (schedule) {
return `${prefix} (${dayjs().tz(timezone).format("z")})`
} else {
return prefix
}
},
autoStopDisplay: (workspace: Workspace): string => {
const schedule = workspace.autostart_schedule
const deadline = dayjs(workspace.latest_build.deadline).utc()
// a mannual shutdown has a deadline of '"0001-01-01T00:00:00Z"'
// SEE: #1834
const hasDeadline = deadline.year() > 1
const ttl = workspace.ttl_ms
if (isWorkspaceOn(workspace) && hasDeadline) {
// Workspace is on --> derive from latest_build.deadline. Note that the
// user may modify their workspace object (ttl) while the workspace is
// running and depending on system semantics, the deadline may still
// represent the previously defined ttl. Thus, we always derive from the
// deadline as the source of truth.
const now = dayjs().utc()
if (now.isAfter(deadline)) {
return "Workspace is shutting down"
} else {
const timezone = schedule ? extractTimezone(schedule) : dayjs.tz.guess()
return deadline.tz(timezone).format("HH: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 "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()} after start`
}
},
editScheduleLink: "Edit schedule",
schedule: "Schedule",
}
export interface WorkspaceScheduleProps {
workspace: Workspace
}
export const WorkspaceSchedule: FC<WorkspaceScheduleProps> = ({ workspace }) => {
const styles = useStyles()
return (
<div className={styles.schedule}>
<Stack spacing={2}>
<Typography variant="body1" className={styles.title}>
<ScheduleIcon className={styles.scheduleIcon} />
{Language.schedule}
</Typography>
<div>
<span className={styles.scheduleLabel}>{Language.autoStartLabel(workspace.autostart_schedule)}</span>
<span className={styles.scheduleValue}>{Language.autoStartDisplay(workspace.autostart_schedule)}</span>
</div>
<div>
<span className={styles.scheduleLabel}>Shutdown</span>
<span className={styles.scheduleValue}>{Language.autoStopDisplay(workspace)}</span>
</div>
<div>
<Link
className={styles.scheduleAction}
component={RouterLink}
to={`/@${workspace.owner_name}/${workspace.name}/schedule`}
>
{Language.editScheduleLink}
</Link>
</div>
</Stack>
</div>
)
}
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",
},
}))