10000 feat: update workspace deadline when workspace ttl updated by johnstcn · Pull Request #2165 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

feat: update workspace deadline when workspace ttl updated #2165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: WorkspaceScheduleForm: show shutdown time when editing workspac…
…e TTL
  • Loading branch information
johnstcn committed Jun 8, 2022
commit daa9a5febfdf1e0e61521a23c52231b2a1df267b
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
import { action } from "@storybook/addon-actions"
import { Story } from "@storybook/react"
import { WorkspaceScheduleForm, WorkspaceScheduleFormProps } from "./WorkspaceScheduleForm"
import dayjs from "dayjs"
import advancedFormat from "dayjs/plugin/advancedFormat"
import timezone from "dayjs/plugin/timezone"
import utc from "dayjs/plugin/utc"
import * as Mocks from "../../testHelpers/entities"
import {
WorkspaceScheduleForm,
WorkspaceScheduleFormInitialValues,
WorkspaceScheduleFormProps,
} from "./WorkspaceScheduleForm"

dayjs.extend(advancedFormat)
dayjs.extend(utc)
dayjs.extend(timezone)

export default {
title: "components/WorkspaceScheduleForm",
Expand All @@ -9,8 +22,96 @@ export default {

const Template: Story<WorkspaceScheduleFormProps> = (args) => <WorkspaceScheduleForm {...args} />

export const Example = Template.bind({})
Example.args = {
export const WorkspaceNotRunning = Template.bind({})
WorkspaceNotRunning.args = {
now: dayjs("2022-05-17T17:40:00Z"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Praise: Thank you for making this constant.

initialValues: {
...WorkspaceScheduleFormInitialValues,
timezone: "UTC",
},
workspace: {
...Mocks.MockWorkspace,
latest_build: {
...Mocks.MockWorkspaceBuild,
transition: "stop",
updated_at: "2022-05-17T17:39:00Z",
},
},
onCancel: () => action("onCancel"),
onSubmit: () => action("onSubmit"),
}

export const WorkspaceWillNotShutDown = Template.bind({})
WorkspaceWillNotShutDown.args = {
now: dayjs("2022-05-17T17:40:00Z"),
initialValues: {
...WorkspaceScheduleFormInitialValues,
timezone: "UTC",
ttl: 0,
},
workspace: {
...Mocks.MockWorkspace,
latest_build: {
...Mocks.MockWorkspaceBuild,
updated_at: "2022-05-17T17:39:00Z",
},
},
onCancel: () => action("onCancel"),
onSubmit: () => action("onSubmit"),
}

export const WorkspaceWillShutdown = Template.bind({})
WorkspaceWillShutdown.args = {
now: dayjs("2022-05-17T17:40:00Z"),
initialValues: {
...WorkspaceScheduleFormInitialValues,
timezone: "UTC",
},
workspace: {
...Mocks.MockWorkspace,
latest_build: {
...Mocks.MockWorkspaceBuild,
updated_at: "2022-05-17T17:39:00Z",
},
},
onCancel: () => action("onCancel"),
onSubmit: () => action("onSubmit"),
}

export const WorkspaceWillShutdownSoon = Template.bind({})
WorkspaceWillShutdownSoon.args = {
now: dayjs("2022-05-17T18:10:00Z"),
initialValues: {
...WorkspaceScheduleFormInitialValues,
timezone: "UTC",
ttl: 1,
},
workspace: {
...Mocks.MockWorkspace,
latest_build: {
...Mocks.MockWorkspaceBuild,
updated_at: "2022-05-17T17:39:00Z",
},
},
onCancel: () => action("onCancel"),
onSubmit: () => action("onSubmit"),
}

export const WorkspaceWillShutdownImmediately = Template.bind({})
WorkspaceWillShutdownImmediately.args = {
now: dayjs("2022-05-17T18:40:00Z"),
initialValues: {
...WorkspaceScheduleFormInitialValues,
timezone: "UTC",
ttl: 1,
},
workspace: {
...Mocks.MockWorkspace,
latest_build: {
...Mocks.MockWorkspaceBuild,
updated_at: "2022-05-17T17:39:00Z",
},
},
onCancel: () => action("onCancel"),
onSubmit: () => action("onSubmit"),
}
57 changes: 45 additions & 12 deletions site/src/components/WorkspaceScheduleForm/WorkspaceScheduleForm.tsx
8000
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import MenuItem from "@material-ui/core/MenuItem"
import makeStyles from "@material-ui/core/styles/makeStyles"
import TextField from "@material-ui/core/TextField"
import dayjs from "dayjs"
import advancedFormat from "dayjs/plugin/advancedFormat"
import timezone from "dayjs/plugin/timezone"
import utc from "dayjs/plugin/utc"
import { useFormik } from "formik"
import { FC } from "react"
import * as Yup from "yup"
import { FieldErrors } from "../../api/errors"
import { Workspace, WorkspaceBuild } from "../../api/typesGenerated"
import { getFormHelpers } from "../../util/formUtils"
import { FormFooter } from "../FormFooter/FormFooter"
import { FullPageForm } from "../FullPageForm/FullPageForm"
Expand All @@ -23,6 +25,7 @@ import { zones } from "./zones"
// REMARK: timezone plugin depends on UTC
//
// SEE: https://day.js.org/docs/en/timezone/timezone
dayjs.extend(advancedFormat)
dayjs.extend(utc)
dayjs.extend(timezone)

Expand All @@ -44,14 +47,21 @@ export const Language = {
timezoneLabel: "Timezone",
ttlLabel: "Time until shutdown (hours)",
ttlHelperText: "Your workspace will automatically shut down after this amount of time has elapsed.",
ttlCausesShutdownHelperText: "Your workspace will shut down ",
ttlCausesShutdownAt: "at ",
ttlCausesShutdownImmediately: "immediately!",
ttlCausesShutdownSoon: "within 30 minutes.",
ttlCausesNoShutdownHelperText: "Your workspace will not automatically shut down.",
}

export interface WorkspaceScheduleFormProps {
fieldErrors?: FieldErrors
initialValues?: WorkspaceScheduleFormValues
isLoading: boolean
now: dayjs.Dayjs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review: I'm not sure if there's a better way to do it, but I figured it's easiest to just pass in the current time as a prop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment(approving): I'm OK with this, it seems like we either don't do this and wrestle with mocks or spies in tests and storybook...or we just do this and live with it being a little weird.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion(nit): Just let's make it optional:

Suggested change
now: dayjs.Dayjs
now?: dayjs.Dayjs

onCancel: () => void
onSubmit: (values: WorkspaceScheduleFormValues) => void
workspace: Workspace
}

export interface WorkspaceScheduleFormValues {
Expand All @@ -68,6 +78,20 @@ export interface WorkspaceScheduleFormValues {
ttl: number
}

export const WorkspaceScheduleFormInitialValues = {
sunday: false,
monday: true,
tuesday: true,
wednesday: true,
thursday: true,
friday: true,
saturday: false,

startTime: "09:30",
timezone: "",
ttl: 5,
}

export const validationSchema = Yup.object({
sunday: Yup.boolean(),
monday: Yup.boolean().test("at-least-one-day", Language.errorNoDayOfWeek, function (value) {
Expand Down Expand Up @@ -154,21 +178,13 @@ export const validationSchema = Yup.object({
export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
fieldErrors,
initialValues = {
sunday: false,
monday: true,
tuesday: true,
wednesday: true,
thursday: true,
friday: true,
saturday: false,

startTime: "09:30",
timezone: "",
ttl: 5,
...WorkspaceScheduleFormInitialValues,
},
isLoading,
now: now,
onCancel,
onSubmit,
workspace,
}) => {
const styles = useStyles()

Expand Down Expand Up @@ -248,7 +264,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
</FormControl>

<TextField
{...formHelpers("ttl", Language.ttlHelperText)}
{...formHelpers("ttl", ttlShutdownAt(now, workspace, form.values.timezone, form.values.ttl))}
disabled={isLoading}
inputProps={{ min: 0, step: 1 }}
label={Language.ttlLabel}
Expand All @@ -262,6 +278,23 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
)
}

const ttlShutdownAt = (now: dayjs.Dayjs, workspace: Workspace, tz: string, newTTL: number): string => {
if (workspace.latest_build.transition !== "start") {
return Language.ttlHelperText
}
if (newTTL === 0) {
return Language.ttlCausesNoShutdownHelperText
}
const newDeadline = dayjs(workspace.latest_build.updated_at).add(newTTL, "hour")
if (newDeadline.isBefore(now)) {
return Language.ttlCausesShutdownHelperText + Language.ttlCausesShutdownImmediately
}
if (newDeadline.isBefore(now.add(30, "minute"))) {
return Language.ttlCausesShutdownHelperText + Language.ttlCausesShutdownSoon
}
return Language.ttlCausesShutdownHelperText + Language.ttlCausesShutdownAt + newDeadline.tz(tz).format("hh:mm A z")
}

const useStyles = makeStyles({
form: {
"& input": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ export const WorkspaceSchedulePage: React.FC = () => {
} else if (scheduleState.matches("presentForm") || scheduleState.matches("submittingSchedule")) {
return (
<WorkspaceScheduleForm
workspace={workspace}
now={dayjs()}
fieldErrors={formErrors}
initialValues={workspaceToInitialValues(workspace, dayjs.tz.guess())}
isLoading={scheduleState.tags.has("loading")}
Expand Down
0