feat: add UI for autostart workspace days (#10263)

* feat: add ui for selecting auto start days
This commit is contained in:
Steven Masley 2023-10-16 09:29:42 -05:00 committed by GitHub
parent 5a90228c60
commit 6ebe9b0402
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 231 additions and 4 deletions

View File

@ -610,6 +610,7 @@ func (api *API) patchTemplateMeta(rw http.ResponseWriter, r *http.Request) {
req.DefaultTTLMillis == time.Duration(template.DefaultTTL).Milliseconds() &&
req.MaxTTLMillis == time.Duration(template.MaxTTL).Milliseconds() &&
autostopRequirementDaysOfWeekParsed == scheduleOpts.AutostopRequirement.DaysOfWeek &&
autostartRequirementDaysOfWeekParsed == scheduleOpts.AutostartRequirement.DaysOfWeek &&
req.AutostopRequirement.Weeks == scheduleOpts.AutostopRequirement.Weeks &&
req.FailureTTLMillis == time.Duration(template.FailureTTL).Milliseconds() &&
req.TimeTilDormantMillis == time.Duration(template.TimeTilDormant).Milliseconds() &&

View File

@ -0,0 +1,137 @@
import { FC } from "react";
import { TemplateAutostartRequirementDaysValue } from "utils/schedule";
import Button from "@mui/material/Button";
import { Stack } from "components/Stack/Stack";
import FormHelperText from "@mui/material/FormHelperText";
export interface TemplateScheduleAutostartProps {
allow_user_autostart?: boolean;
autostart_requirement_days_of_week: TemplateAutostartRequirementDaysValue[];
isSubmitting: boolean;
onChange: (newDaysOfWeek: TemplateAutostartRequirementDaysValue[]) => void;
}
export const TemplateScheduleAutostart: FC<
React.PropsWithChildren<TemplateScheduleAutostartProps>
> = ({
autostart_requirement_days_of_week,
isSubmitting,
allow_user_autostart,
onChange,
}) => {
return (
<Stack
direction="column"
width="100%"
alignItems="center"
css={{
marginBottom: "20px",
}}
>
<Stack
direction="row"
css={{
width: "100%",
}}
spacing={0}
alignItems="baseline"
justifyContent="center"
>
{(
[
{ value: "monday", key: "Mon" },
{ value: "tuesday", key: "Tue" },
{ value: "wednesday", key: "Wed" },
{ value: "thursday", key: "Thu" },
{ value: "friday", key: "Fri" },
{ value: "saturday", key: "Sat" },
{ value: "sunday", key: "Sun" },
] as {
value: TemplateAutostartRequirementDaysValue;
key: string;
}[]
).map((day) => (
<Button
key={day.key}
css={{
borderRadius: "0px",
}}
// TODO: Adding a background color would also help
color={
autostart_requirement_days_of_week.includes(day.value)
? "primary"
: "secondary"
}
disabled={isSubmitting || !allow_user_autostart}
onClick={() => {
if (!autostart_requirement_days_of_week.includes(day.value)) {
onChange(autostart_requirement_days_of_week.concat(day.value));
} else {
onChange(
autostart_requirement_days_of_week.filter(
(obj) => obj !== day.value,
),
);
}
}}
>
{day.key}
</Button>
))}
</Stack>
<FormHelperText>
<AutostartRequirementDaysHelperText
allowed={allow_user_autostart}
days={autostart_requirement_days_of_week}
/>
</FormHelperText>
</Stack>
);
};
export const sortedDays = [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday",
] as TemplateAutostartRequirementDaysValue[];
const AutostartRequirementDaysHelperText: FC<{
allowed?: boolean;
days: TemplateAutostartRequirementDaysValue[];
}> = ({ allowed, days: unsortedDays }) => {
if (!allowed) {
return <span>Workspaces are not allowed to auto start.</span>;
}
// Sort the days
const days = unsortedDays.sort(
(a, b) => sortedDays.indexOf(a) - sortedDays.indexOf(b),
);
let daymsg = `Workspaces can autostart on ${days.join(", ")}.`;
if (days.length === 7) {
// If every day is allowed, no more explaining is needed.
return <span>Workspaces are allowed to auto start on any day.</span>;
}
if (days.length === 0) {
return (
<span>
Workspaces will never auto start. This is effectively the same as
disabling autostart.
</span>
);
}
if (
days.length === 5 &&
!days.includes("saturday") &&
!days.includes("sunday")
) {
daymsg = "Workspaces will never auto start on the weekends.";
}
return (
<span>{daymsg} These days are relative to the user&apos;s timezone.</span>
);
};

View File

@ -42,7 +42,14 @@ import {
AutostopRequirementWeeksHelperText,
} from "pages/TemplateSettingsPage/TemplateSchedulePage/AutostopRequirementHelperText";
import MenuItem from "@mui/material/MenuItem";
import { TemplateAutostopRequirementDaysValue } from "utils/schedule";
import {
TemplateAutostartRequirementDaysValue,
TemplateAutostopRequirementDaysValue,
} from "utils/schedule";
import {
TemplateScheduleAutostart,
sortedDays,
} from "components/TemplateScheduleAutostart/TemplateScheduleAutostart";
const MAX_DESCRIPTION_CHAR_LIMIT = 128;
const MAX_TTL_DAYS = 30;
@ -54,6 +61,7 @@ export interface CreateTemplateData {
icon: string;
default_ttl_hours: number;
max_ttl_hours: number;
autostart_requirement_days_of_week: TemplateAutostartRequirementDaysValue[];
autostop_requirement_days_of_week: TemplateAutostopRequirementDaysValue;
autostop_requirement_weeks: number;
allow_user_autostart: boolean;
@ -88,6 +96,7 @@ const validationSchema = Yup.object({
),
autostop_requirement_days_of_week: Yup.string().required(),
autostop_requirement_weeks: Yup.number().required().min(1).max(16),
autostart_requirement_days_of_week: Yup.array().of(Yup.string()).required(),
});
const defaultInitialValues: CreateTemplateData = {
@ -110,6 +119,7 @@ const defaultInitialValues: CreateTemplateData = {
// user's timezone.
autostop_requirement_days_of_week: "sunday",
autostop_requirement_weeks: 1,
autostart_requirement_days_of_week: sortedDays,
allow_user_cancel_workspace_jobs: false,
allow_user_autostart: false,
allow_user_autostop: false,
@ -434,6 +444,25 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
</strong>
</Stack>
</Stack>
{allowAdvancedScheduling && (
<TemplateScheduleAutostart
allow_user_autostart={form.values.allow_user_autostart}
autostart_requirement_days_of_week={
form.values.autostart_requirement_days_of_week
}
isSubmitting={isSubmitting}
onChange={async (
newDaysOfWeek: TemplateAutostartRequirementDaysValue[],
) => {
await form.setFieldValue(
"autostart_requirement_days_of_week",
newDaysOfWeek,
);
}}
/>
)}
<Stack direction="row" alignItems="center">
<Checkbox
id="allow-user-autostop"

View File

@ -17,6 +17,7 @@ export const newTemplate = (formData: CreateTemplateData) => {
max_ttl_hours,
parameter_values_by_name,
allow_everyone_group_access,
autostart_requirement_days_of_week,
autostop_requirement_days_of_week,
autostop_requirement_weeks,
...safeTemplateData
@ -33,6 +34,9 @@ export const newTemplate = (formData: CreateTemplateData) => {
),
weeks: formData.autostop_requirement_weeks,
},
autostart_requirement: {
days_of_week: autostart_requirement_days_of_week,
},
};
};

View File

@ -9,7 +9,10 @@ import { FC, ChangeEvent, useState, useEffect } from "react";
import { Template, UpdateTemplateMeta } from "api/typesGenerated";
import { getFormHelpers } from "utils/formUtils";
import { docs } from "utils/docs";
import { calculateAutostopRequirementDaysValue } from "utils/schedule";
import {
TemplateAutostartRequirementDaysValue,
calculateAutostopRequirementDaysValue,
} from "utils/schedule";
import {
FormSection,
HorizontalForm,
@ -36,6 +39,7 @@ import {
convertAutostopRequirementDaysValue,
} from "./AutostopRequirementHelperText";
import { useTheme } from "@emotion/react";
import { TemplateScheduleAutostart } from "components/TemplateScheduleAutostart/TemplateScheduleAutostart";
const MS_HOUR_CONVERSION = 3600000;
const MS_DAY_CONVERSION = 86400000;
@ -95,6 +99,8 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
? template.autostop_requirement.weeks
: 1
: 1,
autostart_requirement_days_of_week: template.autostart_requirement
.days_of_week as TemplateAutostartRequirementDaysValue[],
allow_user_autostart: template.allow_user_autostart,
allow_user_autostop: template.allow_user_autostop,
@ -215,6 +221,9 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
),
weeks: autostop_requirement_weeks,
},
autostart_requirement: {
days_of_week: form.values.autostart_requirement_days_of_week,
},
allow_user_autostart: form.values.allow_user_autostart,
allow_user_autostop: form.values.allow_user_autostop,
@ -430,6 +439,24 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
</strong>
</Stack>
</Stack>
{allowAdvancedScheduling && (
<TemplateScheduleAutostart
allow_user_autostart={form.values.allow_user_autostart}
autostart_requirement_days_of_week={
form.values.autostart_requirement_days_of_week
}
isSubmitting={isSubmitting}
onChange={async (
newDaysOfWeek: TemplateAutostartRequirementDaysValue[],
) => {
await form.setFieldValue(
"autostart_requirement_days_of_week",
newDaysOfWeek,
);
}}
/>
)}
<Stack direction="row" alignItems="center">
<Checkbox
id="allow-user-autostop"
@ -623,4 +650,7 @@ const styles = {
ttlFields: {
width: "100%",
},
dayButtons: {
borderRadius: "0px",
},
};

View File

@ -26,6 +26,15 @@ const validFormValues: TemplateScheduleFormValues = {
failure_cleanup_enabled: false,
inactivity_cleanup_enabled: false,
dormant_autodeletion_cleanup_enabled: false,
autostart_requirement_days_of_week: [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday",
],
};
const renderTemplateSchedulePage = async () => {

View File

@ -1,9 +1,16 @@
import { UpdateTemplateMeta } from "api/typesGenerated";
import { TemplateAutostopRequirementDaysValue } from "utils/schedule";
import {
TemplateAutostartRequirementDaysValue,
TemplateAutostopRequirementDaysValue,
} from "utils/schedule";
import * as Yup from "yup";
export interface TemplateScheduleFormValues
extends Omit<UpdateTemplateMeta, "autostop_requirement"> {
extends Omit<
UpdateTemplateMeta,
"autostop_requirement" | "autostart_requirement"
> {
autostart_requirement_days_of_week: TemplateAutostartRequirementDaysValue[];
autostop_requirement_days_of_week: TemplateAutostopRequirementDaysValue;
autostop_requirement_weeks: number;
failure_cleanup_enabled: boolean;
@ -75,5 +82,6 @@ export const getValidationSchema = (): Yup.AnyObjectSchema =>
allow_user_autostop: Yup.boolean(),
autostop_requirement_days_of_week: Yup.string().required(),
autostart_requirement_days_of_week: Yup.array().of(Yup.string()).required(),
autostop_requirement_weeks: Yup.number().required().min(1).max(16),
});

View File

@ -211,6 +211,15 @@ export const quietHoursDisplay = (
return display;
};
export type TemplateAutostartRequirementDaysValue =
| "monday"
| "tuesday"
| "wednesday"
| "thursday"
| "friday"
| "saturday"
| "sunday";
export type TemplateAutostopRequirementDaysValue =
| "off"
| "daily"