diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx index 314b1747f7..12574fa0f2 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.test.tsx @@ -289,8 +289,7 @@ describe("templateInheritance", () => { 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"); + expect(timezoneInput).toBeDisabled(); for (const label of autoStartDayLabels) { const checkbox = await screen.findByLabelText(label); @@ -323,8 +322,7 @@ describe("templateInheritance", () => { 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"); + expect(timezoneInput).toBeEnabled(); for (const label of enabledDayLabels) { const checkbox = await screen.findByLabelText(label); @@ -375,8 +373,7 @@ describe("templateInheritance", () => { 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"); + expect(timezoneInput).toBeDisabled(); for (const label of autoStartDayLabels) { const checkbox = await screen.findByLabelText(label); diff --git a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx index cdf1f5b0d9..0b0bcc9a86 100644 --- a/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx +++ b/site/src/pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceScheduleForm.tsx @@ -1,26 +1,23 @@ -import Checkbox from "@mui/material/Checkbox"; -import FormControl from "@mui/material/FormControl"; -import FormControlLabel from "@mui/material/FormControlLabel"; -import FormGroup from "@mui/material/FormGroup"; -import FormHelperText from "@mui/material/FormHelperText"; -import FormLabel from "@mui/material/FormLabel"; -import MenuItem from "@mui/material/MenuItem"; -import Switch from "@mui/material/Switch"; -import TextField from "@mui/material/TextField"; import type { Template } from "api/typesGenerated"; import { Button } from "components/Button/Button"; +import { Checkbox } from "components/Checkbox/Checkbox"; import { FormFields, FormFooter, FormSection, HorizontalForm, } from "components/Form/Form"; -import { Spinner } from "components/Spinner/Spinner"; -import { Stack } from "components/Stack/Stack"; +import { Input } from "components/Input/Input"; +import { Label } from "components/Label/Label"; import { - StackLabel, - StackLabelHelperText, -} from "components/StackLabel/StackLabel"; + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "components/Select/Select"; +import { Spinner } from "components/Spinner/Spinner"; +import { Switch } from "components/Switch/Switch"; import dayjs from "dayjs"; import timezone from "dayjs/plugin/timezone"; import { type FormikTouched, useFormik } from "formik"; @@ -28,7 +25,7 @@ import { defaultSchedule, emptySchedule, } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule"; -import type { ChangeEvent, FC } from "react"; +import type { FC } from "react"; import { getFormHelpers } from "utils/formUtils"; import { humanDuration } from "utils/time"; import { timeZones } from "utils/timeZones"; @@ -174,10 +171,6 @@ export const validationSchema = Yup.object({ }), }); -// This form utilizes complex, visually-intensive fields. Increasing the space -// between these fields enhances readability and cleanliness. -const FIELDS_SPACING = 4; - export const WorkspaceScheduleForm: FC = ({ error, initialValues, @@ -235,39 +228,20 @@ export const WorkspaceScheduleForm: FC = ({ }, ]; - const handleToggleAutostart = async (e: ChangeEvent) => { - form.handleChange(e); - if (form.values.autostartEnabled) { - // disable autostart, clear values - await form.setValues({ - ...form.values, - autostartEnabled: false, - ...emptySchedule, - }); - } else { - // enable autostart, fill with defaults - await form.setValues({ - ...form.values, - autostartEnabled: true, - ...defaultSchedule(), - }); - } - }; + const startTimeField = formHelpers("startTime"); + const timezoneField = formHelpers("timezone"); + const ttlField = formHelpers("ttl", { + helperText: ttlShutdownAt(form.values.ttl), + backendFieldName: "ttl_ms", + }); - const handleToggleAutostop = async (e: ChangeEvent) => { - form.handleChange(e); - if (form.values.autostopEnabled) { - // disable autostop, set TTL 0 - await form.setValues({ ...form.values, autostopEnabled: false, ttl: 0 }); - } else { - // enable autostop, fill with default TTL - await form.setValues({ - ...form.values, - autostopEnabled: true, - ttl: defaultTTL, - }); - } - }; + const autostartDisabled = + isLoading || + !template.allow_user_autostart || + !form.values.autostartEnabled; + + const autostopDisabled = + isLoading || !template.allow_user_autostop || !form.values.autostopEnabled; return ( @@ -275,108 +249,119 @@ export const WorkspaceScheduleForm: FC = ({ title="Autostart" description="Select the time and days of week on which you want the workspace starting automatically." > - - - } - label={ - - {Language.startSwitch} - {!template.allow_user_autostart && ( - - The template for this workspace does not allow modification - of autostart. - - )} - - } - /> - - - - {timeZones.map((zone) => ( - - {zone} - - ))} - - - - - - {Language.daysOfWeekLabel} - - - +
+ { + void form.setValues({ + ...form.values, + autostartEnabled: checked, + ...(checked ? defaultSchedule() : emptySchedule), + }); }} - > + /> +
+ + {!template.allow_user_autostart && ( + + The template for this workspace does not allow modification of + autostart. + + )} +
+
+ +
+
+ + + {startTimeField.error && ( + + {startTimeField.helperText} + + )} +
+
+ + + {timezoneField.error && ( + + {timezoneField.helperText} + + )} +
+
+ +
+ + {Language.daysOfWeekLabel} + + +
{checkboxes.map((checkbox) => ( - - } - key={checkbox.name} - label={checkbox.label} - /> +
+ { + void form.setFieldValue(checkbox.name, Boolean(checked)); + }} + /> + +
))} - +
{form.errors.monday && ( - {Language.errorNoDayOfWeek} + + {Language.errorNoDayOfWeek} + )} - +
@@ -391,46 +376,62 @@ export const WorkspaceScheduleForm: FC = ({ } > - - - } - label={ - + +
+ { + void form.setValues({ + ...form.values, + autostopEnabled: checked, + ttl: checked ? defaultTTL : 0, + }); + }} + disabled={!template.allow_user_autostop} + /> +
+ + {!template.allow_user_autostop && ( + + The template for this workspace does not allow modification of + autostop. + + )} +
+
+ +
+ + + {ttlField.helperText && ( + + {ttlField.helperText} + + )} +
diff --git a/site/src/theme/light/mui.ts b/site/src/theme/light/mui.ts index c5aa3327e6..de3f2c0a1a 100644 --- a/site/src/theme/light/mui.ts +++ b/site/src/theme/light/mui.ts @@ -166,18 +166,6 @@ const muiTheme = createTheme({ }, }, }, - MuiSwitch: { - ...components.MuiSwitch, - styleOverrides: { - root: { - ".Mui-focusVisible .MuiSwitch-thumb": { - // Had to thicken outline to make sure that the focus color didn't - // bleed into the thumb and was still easily-visible - boxShadow: `0 0 0 3px ${tw.blue[600]}`, - }, - }, - }, - }, MuiTooltip: { styleOverrides: { tooltip: ({ theme }) => ({ diff --git a/site/src/theme/mui.ts b/site/src/theme/mui.ts index 7fcef9bc1a..11e93bf9be 100644 --- a/site/src/theme/mui.ts +++ b/site/src/theme/mui.ts @@ -185,18 +185,6 @@ export const components = { }, }, }, - MuiSwitch: { - defaultProps: { color: "primary" }, - styleOverrides: { - root: { - ".Mui-focusVisible .MuiSwitch-thumb": { - // Had to thicken outline to make sure that the focus color didn't - // bleed into the thumb and was still easily-visible - boxShadow: `0 0 0 3px ${tw.blue[400]}`, - }, - }, - }, - }, MuiAutocomplete: { styleOverrides: { root: { diff --git a/site/vite.config.mts b/site/vite.config.mts index 5ce4ec10df..98cd000002 100644 --- a/site/vite.config.mts +++ b/site/vite.config.mts @@ -185,7 +185,6 @@ export default defineConfig({ "@mui/material/Snackbar", "@mui/material/Stack", "@mui/material/SvgIcon", - "@mui/material/Switch", "@mui/material/TableRow", "@mui/material/TextField", "@mui/material/ToggleButton",