From 0786256016786cf9a35a188188acea73ef74148c Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 24 Jan 2024 18:58:36 +0000 Subject: [PATCH 1/5] fix (site): disable autostart and autostop according to template settings --- .../WorkspaceScheduleForm.stories.tsx | 19 ++- ...test.ts => WorkspaceScheduleForm.test.tsx} | 109 ++++++++++++++++++ .../WorkspaceScheduleForm.tsx | 36 +++--- .../WorkspaceSchedulePage.tsx | 7 +- 4 files changed, 151 insertions(+), 20 deletions(-) rename site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/{WorkspaceScheduleForm.test.ts => WorkspaceScheduleForm.test.tsx} (68%) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.stories.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.stories.tsx index 6b643fd911bff..ec028498053b1 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.stories.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.stories.tsx @@ -19,8 +19,17 @@ const meta: Meta = { title: "pages/WorkspaceSettingsPage/WorkspaceScheduleForm", component: WorkspaceScheduleForm, args: { - enableAutoStart: true, - enableAutoStop: true, + allowTemplateAutoStart: true, + allowTemplateAutoStop: true, + allowedTemplateAutoStartDays: [ + "sunday", + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + ], }, }; @@ -42,8 +51,8 @@ export const AllDisabled: Story = { autostopEnabled: false, ttl: emptyTTL, }, - enableAutoStart: false, - enableAutoStop: false, + allowTemplateAutoStart: false, + allowTemplateAutoStop: false, }, }; @@ -55,7 +64,7 @@ export const Autostart: Story = { autostopEnabled: false, ttl: emptyTTL, }, - enableAutoStop: false, + allowTemplateAutoStop: false, }, }; diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.ts b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx similarity index 68% rename from site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.ts rename to site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx index 5fdd6616357f9..e81054a8b5682 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.ts +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx @@ -3,8 +3,14 @@ import { ttlShutdownAt, validationSchema, WorkspaceScheduleFormValues, + WorkspaceScheduleForm, } from "./WorkspaceScheduleForm"; import { timeZones } from "utils/timeZones"; +import * as API from "api/api"; +import { MockTemplate } from "testHelpers/entities"; +import { render } from "testHelpers/renderHelpers"; +import { defaultSchedule } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule"; +import { screen } from "@testing-library/react"; const valid: WorkspaceScheduleFormValues = { autostartEnabled: true, @@ -237,3 +243,106 @@ describe("ttlShutdownAt", () => { expect(ttlShutdownAt(ttlHours)).toEqual(expected); }); }); + +const autoStartDays = [ + "sunday", + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", +]; +const defaultFormProps = { + submitScheduleError: "", + initialValues: { + ...defaultSchedule(), + autostartEnabled: true, + autostopEnabled: true, + ttl: 24, + }, + isLoading: false, + defaultTTL: 24, + onCancel: () => null, + onSubmit: () => null, + allowedTemplateAutoStartDays: autoStartDays, + allowTemplateAutoStart: true, + allowTemplateAutoStop: true, +}; + +describe("templateInheritance", () => { + it("disables the entire autostart feature appropriately", async () => { + jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); + render( + , + ); + + const autoStartToggle = await screen.findByLabelText("Enable Autostart"); + expect(autoStartToggle).toBeDisabled(); + + const startTimeInput = await screen.findByLabelText("Start time"); + expect(startTimeInput).toBeDisabled(); + + const timezoneInput = await screen.findByLabelText("Timezone"); + // MUI's input is wrapped in a div so we look at the aria-attribute instead + expect(timezoneInput).toHaveAttribute("aria-disabled"); + + autoStartDays.forEach(async (label) => { + const checkbox = await screen.findByLabelText(label); + expect(checkbox).toBeDisabled(); + }); + }); + it("disables the autostart days of the week appropriately", async () => { + const enabledDays = ["saturday", "sunday"]; + + jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); + render( + , + ); + + const autoStartToggle = await screen.findByLabelText("Enable Autostart"); + expect(autoStartToggle).toBeEnabled(); + + const startTimeInput = await screen.findByLabelText("Start time"); + expect(startTimeInput).toBeEnabled(); + + const timezoneInput = await screen.findByLabelText("Timezone"); + // MUI's input is wrapped in a div so we look at the aria-attribute instead + expect(timezoneInput).not.toHaveAttribute("aria-disabled"); + + enabledDays.forEach(async (label) => { + const checkbox = await screen.findByLabelText(label); + expect(checkbox).toBeEnabled(); + }); + + autoStartDays + .filter((day) => !enabledDays.includes(day)) + .forEach(async (label) => { + const checkbox = await screen.findByLabelText(label); + expect(checkbox).toBeDisabled(); + }); + }); + it("disables the entire autostop feature appropriately", async () => { + jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); + render( + , + ); + + const autoStopToggle = await screen.findByLabelText("Enable Autostop"); + expect(autoStopToggle).toBeDisabled(); + + const ttlInput = await screen.findByLabelText( + "Time until shutdown (hours)", + ); + expect(ttlInput).toBeDisabled(); + }); +}); diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx index fc72ffb3089e1..1a807e8514fdb 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx @@ -32,6 +32,8 @@ import { timeZones } from "utils/timeZones"; import Tooltip from "@mui/material/Tooltip"; import { formatDuration, intervalToDuration } from "date-fns"; import { DisabledBadge } from "components/Badges/Badges"; +import { TemplateAutostartRequirement } from "api/typesGenerated"; +import { PropsWithChildren } from "react"; // REMARK: some plugins depend on utc, so it's listed first. Otherwise they're // sorted alphabetically. @@ -73,8 +75,9 @@ export interface WorkspaceScheduleFormProps { submitScheduleError?: unknown; initialValues: WorkspaceScheduleFormValues; isLoading: boolean; - enableAutoStop: boolean; - enableAutoStart: boolean; + allowedTemplateAutoStartDays: TemplateAutostartRequirement["days_of_week"]; + allowTemplateAutoStop: boolean; + allowTemplateAutoStart: boolean; onCancel: () => void; onSubmit: (values: WorkspaceScheduleFormValues) => void; // for storybook @@ -182,7 +185,7 @@ export const validationSchema = Yup.object({ }); export const WorkspaceScheduleForm: FC< - React.PropsWithChildren + PropsWithChildren > = ({ submitScheduleError, initialValues, @@ -191,8 +194,9 @@ export const WorkspaceScheduleForm: FC< onSubmit, initialTouched, defaultTTL, - enableAutoStop, - enableAutoStart, + allowedTemplateAutoStartDays, + allowTemplateAutoStop, + allowTemplateAutoStart, }) => { const form = useFormik({ initialValues, @@ -288,7 +292,7 @@ export const WorkspaceScheduleForm: FC< Select the time and days of week on which you want the workspace starting automatically. - {!enableAutoStart && ( + {!allowTemplateAutoStart && ( @@ -300,7 +304,7 @@ export const WorkspaceScheduleForm: FC< - {!enableAutoStop && ( + {!allowTemplateAutoStop && ( @@ -393,7 +403,7 @@ export const WorkspaceScheduleForm: FC< name="autostopEnabled" checked={form.values.autostopEnabled} onChange={handleToggleAutostop} - disabled={!enableAutoStop} + disabled={!allowTemplateAutoStop} /> } label={Language.stopSwitch} @@ -403,7 +413,7 @@ export const WorkspaceScheduleForm: FC< helperText: ttlShutdownAt(form.values.ttl), backendFieldName: "ttl_ms", })} - disabled={isLoading || !form.values.autostopEnabled} + disabled={isLoading || !allowTemplateAutoStop} inputProps={{ min: 0, step: "any" }} label={Language.ttlLabel} type="number" diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx index b54edcf437e61..712641d5e2cc7 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx @@ -98,8 +98,11 @@ export const WorkspaceSchedulePage: FC = () => { {template && ( Date: Thu, 25 Jan 2024 17:57:46 +0000 Subject: [PATCH 2/5] checking form values again; wrote tests --- .../WorkspaceScheduleForm.test.tsx | 41 +++++++++++++++++++ .../WorkspaceScheduleForm.tsx | 30 +++++++++++--- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx index e81054a8b5682..8adfd808efa03 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx @@ -340,6 +340,47 @@ describe("templateInheritance", () => { const autoStopToggle = await screen.findByLabelText("Enable Autostop"); expect(autoStopToggle).toBeDisabled(); + const ttlInput = await screen.findByLabelText( + "Time until shutdown (hours)", + ); + expect(ttlInput).toBeDisabled(); + }); + it("disables secondary autostart fields if main feature switch is toggled off", async () => { + jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); + render( + , + ); + + const startTimeInput = await screen.findByLabelText("Start time"); + expect(startTimeInput).toBeDisabled(); + + const timezoneInput = await screen.findByLabelText("Timezone"); + // MUI's input is wrapped in a div so we look at the aria-attribute instead + expect(timezoneInput).toHaveAttribute("aria-disabled"); + + autoStartDays.forEach(async (label) => { + const checkbox = await screen.findByLabelText(label); + expect(checkbox).toBeDisabled(); + }); + }); + it("disables secondary autostop fields if main feature switch is toggled off", async () => { + jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); + render( + , + ); + const ttlInput = await screen.findByLabelText( "Time until shutdown (hours)", ); diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx index 1a807e8514fdb..7ccdbef613618 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx @@ -315,14 +315,26 @@ export const WorkspaceScheduleForm: FC< Date: Fri, 26 Jan 2024 03:13:32 +0000 Subject: [PATCH 3/5] fixed closure and label bugs --- .../WorkspaceScheduleForm.test.tsx | 38 ++++++++----------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx index 8adfd808efa03..e43a8617d1dcc 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx @@ -244,15 +244,7 @@ describe("ttlShutdownAt", () => { }); }); -const autoStartDays = [ - "sunday", - "monday", - "tuesday", - "wednesday", - "thursday", - "friday", - "saturday", -]; +const autoStartDayLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const defaultFormProps = { submitScheduleError: "", initialValues: { @@ -265,7 +257,7 @@ const defaultFormProps = { defaultTTL: 24, onCancel: () => null, onSubmit: () => null, - allowedTemplateAutoStartDays: autoStartDays, + allowedTemplateAutoStartDays: autoStartDayLabels, allowTemplateAutoStart: true, allowTemplateAutoStop: true, }; @@ -290,19 +282,19 @@ describe("templateInheritance", () => { // MUI's input is wrapped in a div so we look at the aria-attribute instead expect(timezoneInput).toHaveAttribute("aria-disabled"); - autoStartDays.forEach(async (label) => { + for (const label of autoStartDayLabels) { const checkbox = await screen.findByLabelText(label); expect(checkbox).toBeDisabled(); - }); + } }); it("disables the autostart days of the week appropriately", async () => { - const enabledDays = ["saturday", "sunday"]; + const enabledDayLabels = ["Sat", "Sun"]; jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); render( , ); @@ -316,17 +308,17 @@ describe("templateInheritance", () => { // MUI's input is wrapped in a div so we look at the aria-attribute instead expect(timezoneInput).not.toHaveAttribute("aria-disabled"); - enabledDays.forEach(async (label) => { + for (const label of enabledDayLabels) { const checkbox = await screen.findByLabelText(label); expect(checkbox).toBeEnabled(); - }); + } - autoStartDays - .filter((day) => !enabledDays.includes(day)) - .forEach(async (label) => { - const checkbox = await screen.findByLabelText(label); - expect(checkbox).toBeDisabled(); - }); + for (const label of autoStartDayLabels.filter( + (day) => !enabledDayLabels.includes(day), + )) { + const checkbox = await screen.findByLabelText(label); + expect(checkbox).toBeDisabled(); + } }); it("disables the entire autostop feature appropriately", async () => { jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate); @@ -364,7 +356,7 @@ describe("templateInheritance", () => { // MUI's input is wrapped in a div so we look at the aria-attribute instead expect(timezoneInput).toHaveAttribute("aria-disabled"); - autoStartDays.forEach(async (label) => { + autoStartDayLabels.forEach(async (label) => { const checkbox = await screen.findByLabelText(label); expect(checkbox).toBeDisabled(); }); From becf9cae6adcb31bca01f041741addb3311c0d7b Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Fri, 26 Jan 2024 04:08:50 +0000 Subject: [PATCH 4/5] fix broken query key --- .../WorkspaceSchedulePage/WorkspaceSchedulePage.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx index 712641d5e2cc7..2c1eefc545aa0 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage.tsx @@ -59,7 +59,10 @@ export const WorkspaceSchedulePage: FC = () => { mutationFn: submitSchedule, onSuccess: async () => { await queryClient.invalidateQueries( - workspaceByOwnerAndNameKey(params.username, params.workspace), + workspaceByOwnerAndNameKey( + params.username.replace(/^@/, ""), + params.workspace, + ), ); }, }); From a9ef49902b26a608408e2a820480a204ace8af5b Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Fri, 26 Jan 2024 11:51:07 +0000 Subject: [PATCH 5/5] tweaks --- .../WorkspaceScheduleForm.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx index 7ccdbef613618..21120df0e62e9 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx @@ -211,11 +211,6 @@ export const WorkspaceScheduleForm: FC< ); const checkboxes: Array<{ value: boolean; name: string; label: string }> = [ - { - value: form.values.sunday, - name: "sunday", - label: Language.daySundayLabel, - }, { value: form.values.monday, name: "monday", @@ -246,6 +241,11 @@ export const WorkspaceScheduleForm: FC< name: "saturday", label: Language.daySaturdayLabel, }, + { + value: form.values.sunday, + name: "sunday", + label: Language.daySundayLabel, + }, ]; const handleToggleAutostart = async (e: ChangeEvent) => { @@ -441,7 +441,14 @@ export const WorkspaceScheduleForm: FC< /> - + ); }; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy