Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 928958c

Browse files
authored
fix: workspace schedule time displays (coder#2249)
Summary: Various time displays weren't quite right. Details: - Display date (not just time) of upcoming workspace stop in workspace page - Fix ttlShutdownAt for various cases + tests - manual to non-manual - unchanged/unmodified - isBefore --> isSameOrBefore - use the delta (off by _ error) - pluralize units in dayjs.add
1 parent 1a9e572 commit 928958c

File tree

4 files changed

+118
-35
lines changed

4 files changed

+118
-35
lines changed

site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ import { stripTimezone } from "../../util/schedule"
1717
import { isWorkspaceOn } from "../../util/workspace"
1818
import { Stack } from "../Stack/Stack"
1919

20-
dayjs.extend(advancedFormat)
20+
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
21+
// sorted alphabetically.
2122
dayjs.extend(utc)
23+
dayjs.extend(advancedFormat)
2224
dayjs.extend(duration)
2325
dayjs.extend(relativeTime)
2426
dayjs.extend(timezone)
@@ -50,7 +52,7 @@ export const Language = {
5052
if (now.isAfter(deadline)) {
5153
return "Workspace is shutting down"
5254
} else {
53-
return deadline.tz(dayjs.tz.guess()).format("hh:mm A")
55+
return deadline.tz(dayjs.tz.guess()).format("MMM D, YYYY h:mm A")
5456
}
5557
} else if (!ttl || ttl < 1) {
5658
// If the workspace is not on, and the ttl is 0 or undefined, then the

site/src/components/WorkspaceScheduleForm/WorkspaceScheduleForm.stories.tsx

+11-9
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const WorkspaceNotRunning = Template.bind({})
2222
WorkspaceNotRunning.args = {
2323
now: dayjs("2022-05-17T17:40:00Z"),
2424
initialValues: {
25-
...defaultWorkspaceSchedule(5, "asdfasdf"),
25+
...defaultWorkspaceSchedule(5),
2626
timezone: "UTC",
2727
},
2828
workspace: {
@@ -41,7 +41,7 @@ export const WorkspaceWillNotShutDown = Template.bind({})
4141
WorkspaceWillNotShutDown.args = {
4242
now: dayjs("2022-05-17T17:40:00Z"),
4343
initialValues: {
44-
...defaultWorkspaceSchedule(5, "asdfasdf"),
44+
...defaultWorkspaceSchedule(5),
4545
timezone: "UTC",
4646
ttl: 0,
4747
},
@@ -60,7 +60,7 @@ export const WorkspaceWillShutdown = Template.bind({})
6060
WorkspaceWillShutdown.args = {
6161
now: dayjs("2022-05-17T17:40:00Z"),
6262
initialValues: {
63-
...defaultWorkspaceSchedule(5, "asdfasdf"),
63+
...defaultWorkspaceSchedule(5),
6464
timezone: "UTC",
6565
},
6666
workspace: {
@@ -76,37 +76,39 @@ WorkspaceWillShutdown.args = {
7676

7777
export const WorkspaceWillShutdownSoon = Template.bind({})
7878
WorkspaceWillShutdownSoon.args = {
79-
now: dayjs("2022-05-17T18:10:00Z"),
79+
now: dayjs("2022-05-17T16:39:00Z"),
8080
initialValues: {
81-
...defaultWorkspaceSchedule(5, "asdfasdf"),
81+
...defaultWorkspaceSchedule(2),
8282
timezone: "UTC",
8383
ttl: 1,
8484
},
8585
workspace: {
8686
...Mocks.MockWorkspace,
8787
latest_build: {
8888
...Mocks.MockWorkspaceBuild,
89-
updated_at: "2022-05-17T17:39:00Z",
89+
deadline: "2022-05-17T18:09:00Z",
9090
},
91+
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours = shuts off at 18:09
9192
},
9293
onCancel: () => action("onCancel"),
9394
onSubmit: () => action("onSubmit"),
9495
}
9596

9697
export const WorkspaceWillShutdownImmediately = Template.bind({})
9798
WorkspaceWillShutdownImmediately.args = {
98-
now: dayjs("2022-05-17T18:40:00Z"),
99+
now: dayjs("2022-05-17T17:09:00Z"),
99100
initialValues: {
100-
...defaultWorkspaceSchedule(5, "asdfasdf"),
101+
...defaultWorkspaceSchedule(1),
101102
timezone: "UTC",
102103
ttl: 1,
103104
},
104105
workspace: {
105106
...Mocks.MockWorkspace,
106107
latest_build: {
107108
...Mocks.MockWorkspaceBuild,
108-
updated_at: "2022-05-17T17:39:00Z",
109+
deadline: "2022-05-17T18:09:00Z",
109110
},
111+
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours = shuts off at 18:09
110112
},
111113
onCancel: () => action("onCancel"),
112114
onSubmit: () => action("onSubmit"),

site/src/components/WorkspaceScheduleForm/WorkspaceScheduleForm.test.ts

+78-10
Original file line numberDiff line numberDiff line change
@@ -160,31 +160,99 @@ describe("validationSchema", () => {
160160
})
161161

162162
describe("ttlShutdownAt", () => {
163-
it.each<[dayjs.Dayjs, Workspace, string, number, string]>([
164-
[dayjs("2022-05-17T18:09:00Z"), Mocks.MockStoppedWorkspace, "America/Chicago", 1, Language.ttlHelperText],
165-
[dayjs("2022-05-17T18:09:00Z"), Mocks.MockWorkspace, "America/Chicago", 0, Language.ttlCausesNoShutdownHelperText],
163+
it.each<[string, dayjs.Dayjs, Workspace, string, number, string]>([
166164
[
165+
"Workspace is stopped --> helper text",
167166
dayjs("2022-05-17T18:09:00Z"),
168-
Mocks.MockWorkspace,
167+
Mocks.MockStoppedWorkspace,
169168
"America/Chicago",
170169
1,
171-
`${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownAt} 01:39 PM CDT.`,
170+
Language.ttlHelperText,
172171
],
173172
[
174-
dayjs("2022-05-17T18:10:00Z"),
173+
"TTL is not modified --> helper text",
174+
dayjs("2022-05-17T16:09:00Z"),
175+
{
176+
...Mocks.MockWorkspace,
177+
latest_build: {
178+
...Mocks.MockWorkspaceBuild,
179+
deadline: "2022-05-17T18:09:00Z",
180+
},
181+
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours = shuts off at 18:09
182+
},
183+
"America/Chicago",
184+
2,
185+
Language.ttlHelperText,
186+
],
187+
[
188+
"TTL becomes 0 --> manual helper text",
189+
dayjs("2022-05-17T18:09:00Z"),
175190
Mocks.MockWorkspace,
176191
"America/Chicago",
192+
0,
193+
Language.ttlCausesNoShutdownHelperText,
194+
],
195+
[
196+
"Deadline of 18:09 becomes 17:09 at 17:09 --> immediate shutdown",
197+
dayjs("2022-05-17T17:09:00Z"),
198+
{
199+
...Mocks.MockWorkspace,
200+
latest_build: {
201+
...Mocks.MockWorkspaceBuild,
202+
deadline: "2022-05-17T18:09:00Z",
203+
},
204+
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours = shuts off at 18:09
205+
},
206+
"America/Chicago",
207+
1,
208+
`⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownImmediately} ⚠️`,
209+
],
210+
[
211+
"Deadline of 18:09 becomes 17:09 at 16:39 --> display shutdown soon",
212+
dayjs("2022-05-17T16:39:00Z"),
213+
{
214+
...Mocks.MockWorkspace,
215+
latest_build: {
216+
...Mocks.MockWorkspaceBuild,
217+
deadline: "2022-05-17T18:09:00Z",
218+
},
219+
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours = shuts off at 18:09
220+
},
221+
"America/Chicago",
177222
1,
178223
`⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownSoon} ⚠️`,
179224
],
180225
[
181-
dayjs("2022-05-17T18:40:00Z"),
182-
Mocks.MockWorkspace,
226+
"Deadline of 18:09 becomes 17:09 at 16:09 --> display 12:09 CDT",
227+
dayjs("2022-05-17T16:09:00Z"),
228+
{
229+
...Mocks.MockWorkspace,
230+
latest_build: {
231+
...Mocks.MockWorkspaceBuild,
232+
deadline: "2022-05-17T18:09:00Z",
233+
},
234+
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours = shuts off at 18:09
235+
},
183236
"America/Chicago",
184237
1,
185-
`⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownImmediately} ⚠️`,
238+
`${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownAt} May 17, 2022 12:09 PM.`,
239+
],
240+
[
241+
"Manual workspace gets new deadline of 18:09 at 17:09 --> display 1:09 CDT",
242+
dayjs("2022-05-17T17:09:00Z"),
243+
{
244+
...Mocks.MockWorkspace,
245+
latest_build: {
246+
...Mocks.MockWorkspaceBuild,
247+
deadline: "0001-01-01T00:00:00Z",
248+
},
249+
ttl_ms: 0,
250+
},
251+
"America/Chicago",
252+
1,
253+
`${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownAt} May 17, 2022 1:09 PM.`,
186254
],
187-
])("ttlShutdownAt(%p, %p, %p, %p) returns %p", (now, workspace, timezone, ttlHours, expected) => {
255+
])("%p", (_, now, workspace, timezone, ttlHours, expected) => {
188256
expect(ttlShutdownAt(now, workspace, timezone, ttlHours)).toEqual(expected)
189257
})
190258
})

site/src/components/WorkspaceScheduleForm/WorkspaceScheduleForm.tsx

+25-14
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import makeStyles from "@material-ui/core/styles/makeStyles"
99
import TextField from "@material-ui/core/TextField"
1010
import dayjs from "dayjs"
1111
import advancedFormat from "dayjs/plugin/advancedFormat"
12+
import isSameOrBefore from "dayjs/plugin/isSameOrBefore"
1213
import timezone from "dayjs/plugin/timezone"
1314
import utc from "dayjs/plugin/utc"
1415
import { useFormik } from "formik"
@@ -23,11 +24,11 @@ import { FullPageForm } from "../FullPageForm/FullPageForm"
2324
import { Stack } from "../Stack/Stack"
2425
import { zones } from "./zones"
2526

26-
// REMARK: timezone plugin depends on UTC
27-
//
28-
// SEE: https://day.js.org/docs/en/timezone/timezone
29-
dayjs.extend(advancedFormat)
27+
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
28+
// sorted alphabetically.
3029
dayjs.extend(utc)
30+
dayjs.extend(advancedFormat)
31+
dayjs.extend(isSameOrBefore)
3132
dayjs.extend(timezone)
3233

3334
export const Language = {
@@ -282,19 +283,29 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
282283
)
283284
}
284285

285-
export const ttlShutdownAt = (now: dayjs.Dayjs, workspace: Workspace, tz: string, newTTL: number): string => {
286-
const newDeadline = dayjs(workspace.latest_build.updated_at).add(newTTL, "hour")
287-
if (!isWorkspaceOn(workspace)) {
286+
export const ttlShutdownAt = (now: dayjs.Dayjs, workspace: Workspace, tz: string, formTTL: number): string => {
287+
// a manual shutdown has a deadline of '"0001-01-01T00:00:00Z"'
288+
// SEE: #1834
289+
const deadline = dayjs(workspace.latest_build.deadline).utc()
290+
const hasDeadline = deadline.year() > 1
291+
const ttl = workspace.ttl_ms ? workspace.ttl_ms / (1000 * 60 * 60) : 0
292+
const delta = formTTL - ttl
293+
294+
if (delta === 0 || !isWorkspaceOn(workspace)) {
288295
return Language.ttlHelperText
289-
} else if (newTTL === 0) {
296+
} else if (formTTL === 0) {
290297
return Language.ttlCausesNoShutdownHelperText
291-
} else if (newDeadline.isBefore(now)) {
292-
return `⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownImmediately} ⚠️`
293-
} else if (newDeadline.isBefore(now.add(30, "minute"))) {
294-
return `⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownSoon} ⚠️`
295298
} else {
296-
const newDeadlineString = newDeadline.tz(tz).format("hh:mm A z")
297-
return `${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownAt} ${newDeadlineString}.`
299+
const newDeadline = dayjs(hasDeadline ? deadline : now).add(delta, "hours")
300+
if (newDeadline.isSameOrBefore(now)) {
301+
return `⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownImmediately} ⚠️`
302+
} else if (newDeadline.isSameOrBefore(now.add(30, "minutes"))) {
303+
return `⚠️ ${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownSoon} ⚠️`
304+
} else {
305+
return `${Language.ttlCausesShutdownHelperText} ${Language.ttlCausesShutdownAt} ${newDeadline
306+
.tz(tz)
307+
.format("MMM D, YYYY h:mm A")}.`
308+
}
298309
}
299310
}
300311

0 commit comments

Comments
 (0)