mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
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:
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -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(" ")
|
||||
}
|
||||
Reference in New Issue
Block a user