From 956a5780e8517b3d20d4830ef1983df084e5fce6 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Mon, 10 Apr 2023 12:59:26 +0000 Subject: [PATCH 1/4] feat: add advanced schedule settings --- .../CreateTemplatePage/CreateTemplateForm.tsx | 51 ++++++++ .../TemplateScheduleForm.tsx | 115 ++++++++++++++---- .../createTemplate/createTemplateXService.ts | 2 + 3 files changed, 143 insertions(+), 25 deletions(-) diff --git a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx index 4d2122b2cb2a5..0a8d567fd466f 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx @@ -105,6 +105,8 @@ const defaultInitialValues: CreateTemplateData = { // you are not licensed. We hide the form value based on entitlements. max_ttl_hours: 24 * 7, allow_user_cancel_workspace_jobs: false, + allow_user_autostart: false, + allow_user_autostop: false, } type GetInitialValuesParams = { @@ -341,6 +343,55 @@ export const CreateTemplateForm: FC = ({ type="number" /> + + + { + await form.setFieldValue( + "allow_user_autostart", + !form.values.allow_user_autostart, + ) + }} + name="allow_user_autostart" + checked={form.values.allow_user_autostart} + /> + + + Allow users to auto-start workspaces on a schedule. + + + + + { + await form.setFieldValue( + "allow_user_autostop", + !form.values.allow_user_autostop, + ) + }} + name="allow-user-autostop" + checked={form.values.allow_user_autostop} + /> + + + Allow users to customize auto-stop duration for workspaces. + + + Workspaces will always use the default TTL if this is set. + Regardless of this setting, workspaces can only stay on for + the max lifetime. + + + + diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx index a8a44f5aa91e8..a89a9601238df 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateScheduleForm.tsx @@ -1,6 +1,6 @@ import TextField from "@material-ui/core/TextField" import { Template, UpdateTemplateMeta } from "api/typesGenerated" -import { FormikContextType, FormikTouched, useFormik } from "formik" +import { FormikTouched, useFormik } from "formik" import { FC } from "react" import { getFormHelpers } from "util/formUtils" import * as Yup from "yup" @@ -11,6 +11,7 @@ import { FormSection, HorizontalForm, FormFooter } from "components/Form/Form" import { Stack } from "components/Stack/Stack" import { makeStyles } from "@material-ui/core/styles" import Link from "@material-ui/core/Link" +import Checkbox from "@material-ui/core/Checkbox" const TTLHelperText = ({ ttl, @@ -48,6 +49,8 @@ export const getValidationSchema = (): Yup.AnyObjectSchema => 24 * MAX_TTL_DAYS /* 7 days in hours */, i18next.t("maxTTLMaxError", { ns: "templateSettingsPage" }), ), + allow_user_autostart: Yup.boolean(), + allow_user_autostop: Yup.boolean(), }) export interface TemplateScheduleForm { @@ -72,29 +75,32 @@ export const TemplateScheduleForm: FC = ({ }) => { const { t: commonT } = useTranslation("common") const validationSchema = getValidationSchema() - const form: FormikContextType = - useFormik({ - initialValues: { - // on display, convert from ms => hours - default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION, - // the API ignores this value, but to avoid tripping up validation set - // it to zero if the user can't set the field. - max_ttl_ms: canSetMaxTTL ? template.max_ttl_ms / MS_HOUR_CONVERSION : 0, - }, - validationSchema, - onSubmit: (formData) => { - // on submit, convert from hours => ms - onSubmit({ - default_ttl_ms: formData.default_ttl_ms - ? formData.default_ttl_ms * MS_HOUR_CONVERSION - : undefined, - max_ttl_ms: formData.max_ttl_ms - ? formData.max_ttl_ms * MS_HOUR_CONVERSION - : undefined, - }) - }, - initialTouched, - }) + const form = useFormik({ + initialValues: { + // on display, convert from ms => hours + default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION, + // the API ignores this value, but to avoid tripping up validation set + // it to zero if the user can't set the field. + max_ttl_ms: canSetMaxTTL ? template.max_ttl_ms / MS_HOUR_CONVERSION : 0, + allow_user_autostart: template.allow_user_autostart, + allow_user_autostop: template.allow_user_autostop, + }, + validationSchema, + onSubmit: (formData) => { + // on submit, convert from hours => ms + onSubmit({ + default_ttl_ms: formData.default_ttl_ms + ? formData.default_ttl_ms * MS_HOUR_CONVERSION + : undefined, + max_ttl_ms: formData.max_ttl_ms + ? formData.max_ttl_ms * MS_HOUR_CONVERSION + : undefined, + allow_user_autostart: formData.allow_user_autostart, + allow_user_autostop: formData.allow_user_autostop, + }) + }, + initialTouched, + }) const getFieldHelpers = getFormHelpers(form, error) const { t } = useTranslation("templateSettingsPage") const styles = useStyles() @@ -153,13 +159,72 @@ export const TemplateScheduleForm: FC = ({ + + + + { + await form.setFieldValue( + "allow_user_autostart", + !form.values.allow_user_autostart, + ) + }} + name="allow_user_autostart" + checked={form.values.allow_user_autostart} + /> + + + Allow users to auto-start workspaces on a schedule. + + + + + { + await form.setFieldValue( + "allow_user_autostop", + !form.values.allow_user_autostop, + ) + }} + name="allow_user_autostop" + checked={form.values.allow_user_autostop} + /> + + + Allow users to customize auto-stop duration for workspaces. + + + Workspaces will always use the default TTL if this is set. + Regardless of this setting, workspaces can only stay on for the + max lifetime. + + + + + + ) } -const useStyles = makeStyles(() => ({ +const useStyles = makeStyles((theme) => ({ ttlFields: { width: "100%", }, + optionDescription: { + fontSize: 12, + color: theme.palette.text.secondary, + }, })) diff --git a/site/src/xServices/createTemplate/createTemplateXService.ts b/site/src/xServices/createTemplate/createTemplateXService.ts index 9548e483c8334..313e7f59a05e4 100644 --- a/site/src/xServices/createTemplate/createTemplateXService.ts +++ b/site/src/xServices/createTemplate/createTemplateXService.ts @@ -44,6 +44,8 @@ export interface CreateTemplateData { icon: string default_ttl_hours: number max_ttl_hours: number + allow_user_autostart: boolean + allow_user_autostop: boolean allow_user_cancel_workspace_jobs: boolean parameter_values_by_name?: Record user_variable_values?: VariableValue[] From 7093c21cba53f7217aeca7afecb2e8662b6444c0 Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 11 Apr 2023 17:02:54 -0300 Subject: [PATCH 2/4] Update site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx Co-authored-by: Dean Sheather --- site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx index 0a8d567fd466f..9f5b8c18cdc28 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx @@ -387,7 +387,7 @@ export const CreateTemplateForm: FC = ({ Workspaces will always use the default TTL if this is set. Regardless of this setting, workspaces can only stay on for - the max lifetime. + the max TTL. From f5916cf30794daa341d2c470c552dfa8979526ed Mon Sep 17 00:00:00 2001 From: Rodrigo Maia Date: Tue, 11 Apr 2023 20:14:24 +0000 Subject: [PATCH 3/4] rename variable --- .../CreateTemplatePage/CreateTemplateForm.tsx | 24 +++++++++---------- .../CreateTemplatePage/CreateTemplatePage.tsx | 4 ++-- .../TemplateScheduleForm.tsx | 22 +++++++++-------- .../TemplateSchedulePage.tsx | 4 ++-- .../TemplateSchedulePageView.stories.tsx | 4 ++-- .../TemplateSchedulePageView.tsx | 6 ++--- 6 files changed, 33 insertions(+), 31 deletions(-) diff --git a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx index 9f5b8c18cdc28..e0128520700ac 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx @@ -114,19 +114,19 @@ type GetInitialValuesParams = { fromCopy?: Template parameters?: ParameterSchema[] variables?: TemplateVersionVariable[] - canSetMaxTTL: boolean + allowAdvancedScheduling: boolean } const getInitialValues = ({ fromExample, fromCopy, - canSetMaxTTL, + allowAdvancedScheduling, variables, parameters, }: GetInitialValuesParams) => { let initialValues = defaultInitialValues - if (!canSetMaxTTL) { + if (!allowAdvancedScheduling) { initialValues = { ...initialValues, max_ttl_hours: 0, @@ -190,7 +190,7 @@ export interface CreateTemplateFormProps { error?: unknown jobError?: string logs?: ProvisionerJobLog[] - canSetMaxTTL: boolean + allowAdvancedScheduling: boolean copiedTemplate?: Template } @@ -206,12 +206,12 @@ export const CreateTemplateForm: FC = ({ error, jobError, logs, - canSetMaxTTL, + allowAdvancedScheduling, }) => { const styles = useStyles() const form = useFormik({ initialValues: getInitialValues({ - canSetMaxTTL, + allowAdvancedScheduling, fromExample: starterTemplate, fromCopy: copiedTemplate, variables, @@ -321,7 +321,7 @@ export const CreateTemplateForm: FC = ({ = ({ ), )} - disabled={isSubmitting || !canSetMaxTTL} + disabled={isSubmitting || !allowAdvancedScheduling} fullWidth label={t("form.fields.maxTTL")} variant="outlined" @@ -349,7 +349,7 @@ export const CreateTemplateForm: FC = ({ id="allow_user_autostart" size="small" color="primary" - disabled={isSubmitting || !canSetMaxTTL} + disabled={isSubmitting || !allowAdvancedScheduling} onChange={async () => { await form.setFieldValue( "allow_user_autostart", @@ -361,7 +361,7 @@ export const CreateTemplateForm: FC = ({ /> - Allow users to auto-start workspaces on a schedule. + Allow users to autostart workspaces on a schedule. @@ -370,7 +370,7 @@ export const CreateTemplateForm: FC = ({ id="allow-user-autostop" size="small" color="primary" - disabled={isSubmitting || !canSetMaxTTL} + disabled={isSubmitting || !allowAdvancedScheduling} onChange={async () => { await form.setFieldValue( "allow_user_autostop", @@ -382,7 +382,7 @@ export const CreateTemplateForm: FC = ({ /> - Allow users to customize auto-stop duration for workspaces. + Allow users to customize autostop duration for workspaces. Workspaces will always use the default TTL if this is set. diff --git a/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx b/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx index e6443f48f3bf2..8819cdb5d5a01 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplatePage.tsx @@ -44,7 +44,7 @@ const CreateTemplatePage: FC = () => { } = state.context const shouldDisplayForm = !state.hasTag("loading") const { entitlements } = useDashboard() - const canSetMaxTTL = + const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled const onCancel = () => { @@ -70,7 +70,7 @@ const CreateTemplatePage: FC = () => { {shouldDisplayForm && ( void isSubmitting: boolean error?: unknown - canSetMaxTTL: boolean + allowAdvancedScheduling: boolean // Helpful to show field errors on Storybook initialTouched?: FormikTouched } @@ -69,7 +69,7 @@ export const TemplateScheduleForm: FC = ({ onSubmit, onCancel, error, - canSetMaxTTL, + allowAdvancedScheduling, isSubmitting, initialTouched, }) => { @@ -81,7 +81,9 @@ export const TemplateScheduleForm: FC = ({ default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION, // the API ignores this value, but to avoid tripping up validation set // it to zero if the user can't set the field. - max_ttl_ms: canSetMaxTTL ? template.max_ttl_ms / MS_HOUR_CONVERSION : 0, + max_ttl_ms: allowAdvancedScheduling + ? template.max_ttl_ms / MS_HOUR_CONVERSION + : 0, allow_user_autostart: template.allow_user_autostart, allow_user_autostop: template.allow_user_autostop, }, @@ -134,7 +136,7 @@ export const TemplateScheduleForm: FC = ({ = ({ ), )} - disabled={isSubmitting || !canSetMaxTTL} + disabled={isSubmitting || !allowAdvancedScheduling} fullWidth inputProps={{ min: 0, step: 1 }} label={t("maxTtlLabel")} @@ -161,7 +163,7 @@ export const TemplateScheduleForm: FC = ({ @@ -169,7 +171,7 @@ export const TemplateScheduleForm: FC = ({ id="allow_user_autostart" size="small" color="primary" - disabled={isSubmitting || !canSetMaxTTL} + disabled={isSubmitting || !allowAdvancedScheduling} onChange={async () => { await form.setFieldValue( "allow_user_autostart", @@ -181,7 +183,7 @@ export const TemplateScheduleForm: FC = ({ /> - Allow users to auto-start workspaces on a schedule. + Allow users to autostart workspaces on a schedule. @@ -190,7 +192,7 @@ export const TemplateScheduleForm: FC = ({ id="allow-user-autostop" size="small" color="primary" - disabled={isSubmitting || !canSetMaxTTL} + disabled={isSubmitting || !allowAdvancedScheduling} onChange={async () => { await form.setFieldValue( "allow_user_autostop", @@ -202,7 +204,7 @@ export const TemplateScheduleForm: FC = ({ /> - Allow users to customize auto-stop duration for workspaces. + Allow users to customize autostop duration for workspaces. Workspaces will always use the default TTL if this is set. diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx index c9e1e33c5b3b5..18075e0cd1795 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx @@ -15,7 +15,7 @@ const TemplateSchedulePage: FC = () => { const navigate = useNavigate() const { template } = useTemplateSettingsContext() const { entitlements } = useDashboard() - const canSetMaxTTL = + const allowAdvancedScheduling = entitlements.features["advanced_template_scheduling"].enabled const { mutate: updateTemplate, @@ -36,7 +36,7 @@ const TemplateSchedulePage: FC = () => { {pageTitle([template.name, "Schedule"])} ["initialTouched"] - canSetMaxTTL: boolean + allowAdvancedScheduling: boolean } export const TemplateSchedulePageView: FC = ({ @@ -19,7 +19,7 @@ export const TemplateSchedulePageView: FC = ({ onCancel, onSubmit, isSubmitting, - canSetMaxTTL, + allowAdvancedScheduling, submitError, initialTouched, }) => { @@ -32,7 +32,7 @@ export const TemplateSchedulePageView: FC = ({ Date: Wed, 12 Apr 2023 17:33:48 +0000 Subject: [PATCH 4/4] fix optionText css --- site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx index e0128520700ac..b3ff3b60e955e 100644 --- a/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx +++ b/site/src/pages/CreateTemplatePage/CreateTemplateForm.tsx @@ -384,7 +384,7 @@ export const CreateTemplateForm: FC = ({ Allow users to customize autostop duration for workspaces. - + Workspaces will always use the default TTL if this is set. Regardless of this setting, workspaces can only stay on for the max TTL.