feat: workspace view for schedules (#991)

Summary:

This adds the client-side implementation to match the types introduced
in #879 and #844 as well as a card in the Workspaces page to present
workspace the data.

Details:

* Added a convenient line break in the example schedule.Weekly
* Added missing `json:""` annotations in codersdk/workspaces.go
* Installed cronstrue for displaying human-friendly cron strings
* Adjusted/Added client-side types to match codersdk/workspaces.go
* Added new component WorkspaceSchedule.tsx

Next Steps:

The WorkspaceSchedule.tsx card only presents data (on purpose). In order
to make it PUT/modify data, a few changes will be made:

- a form for updating workspace schedule will be created
- the form will wrapped in a dialog or modal
- the WorkspaceSchedule card will have a way of opening the modal which
will likely be generalized up to WorkspaceSection.tsx

Impact:

This is user-facing

This does not fully resolve either #274 or #275 (I may further decompose
that work to reflect reality and keep things in small deliverable
increments), but adds significant progress towards both.
This commit is contained in:
G r e y
2022-04-13 20:35:47 -04:00
committed by GitHub
parent 027d89dd9b
commit 42e9956779
13 changed files with 235 additions and 3 deletions
+33
View File
@@ -0,0 +1,33 @@
import { expandScheduleCronString, extractTimezone, stripTimezone } from "./schedule"
describe("util/schedule", () => {
describe("stripTimezone", () => {
it.each<[string, string]>([
["CRON_TZ=Canada/Eastern 30 9 1-5", "30 9 1-5"],
["CRON_TZ=America/Central 0 8 1,2,4,5", "0 8 1,2,4,5"],
["30 9 1-5", "30 9 1-5"],
])(`stripTimezone(%p) returns %p`, (input, expected) => {
expect(stripTimezone(input)).toBe(expected)
})
})
describe("extractTimezone", () => {
it.each<[string, string]>([
["CRON_TZ=Canada/Eastern 30 9 1-5", "Canada/Eastern"],
["CRON_TZ=America/Central 0 8 1,2,4,5", "America/Central"],
["30 9 1-5", "UTC"],
])(`extractTimezone(%p) returns %p`, (input, expected) => {
expect(extractTimezone(input)).toBe(expected)
})
})
describe("expandScheduleCronString", () => {
it.each<[string, string]>([
["CRON_TZ=Canada/Eastern 30 9 1-5", "30 9 * * 1-5"],
["CRON_TZ=America/Central 0 8 1,2,4,5", "0 8 * * 1,2,4,5"],
["30 9 1-5", "30 9 * * 1-5"],
])(`expandScheduleCronString(%p) returns %p`, (input, expected) => {
expect(expandScheduleCronString(input)).toBe(expected)
})
})
})
+54
View File
@@ -0,0 +1,54 @@
/**
* @fileoverview Client-side counterpart of the coderd/autostart/schedule Go
* package. This package is a variation on crontab that uses minute, hour and
* day of week.
*/
/**
* DEFAULT_TIMEZONE is the default timezone that crontab assumes unless one is
* specified.
*/
const DEFAULT_TIMEZONE = "UTC"
/**
* stripTimezone strips a leading timezone from a schedule string
*/
export const stripTimezone = (raw: string): string => {
return raw.replace(/CRON_TZ=\S*\s/, "")
}
/**
* extractTimezone returns a leading timezone from a schedule string if one is
* specified; otherwise DEFAULT_TIMEZONE
*/
export const extractTimezone = (raw: string): string => {
const matches = raw.match(/CRON_TZ=\S*\s/g)
if (matches && matches.length) {
return matches[0].replace(/CRON_TZ=/, "").trim()
} else {
return DEFAULT_TIMEZONE
}
}
/**
* expandScheduleCronString ensures a Schedule is expanded to a valid 5-value
* cron string by inserting '*' in month and day positions. If there is a
* leading timezone, it is removed.
*
* @example
* expandScheduleCronString("30 9 1-5") // -> "30 9 * * 1-5"
*/
export const expandScheduleCronString = (schedule: string): string => {
const prepared = stripTimezone(schedule).trim()
const parts = prepared.split(" ")
while (parts.length < 5) {
// insert '*' in the second to last position
// ie [a, b, c] --> [a, b, *, c]
parts.splice(parts.length - 1, 0, "*")
}
return parts.join(" ")
}