Skip to content

Commit 928958c

Browse files
authored
fix: workspace schedule time displays (#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

Lines changed: 4 additions & 2 deletions
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

Lines changed: 11 additions & 9 deletions
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

Lines changed: 78 additions & 10 deletions
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

Lines changed: 25 additions & 14 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy