Skip to content

Commit b92e7d4

Browse files
refactor(site): Refactor workspace schedule page (#7069)
1 parent 4dd5d79 commit b92e7d4

20 files changed

+582
-362
lines changed

site/src/AppRouter.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { RequireAuth } from "./components/RequireAuth/RequireAuth"
1717
import { SettingsLayout } from "./components/SettingsLayout/SettingsLayout"
1818
import { DeploySettingsLayout } from "components/DeploySettingsLayout/DeploySettingsLayout"
1919
import { TemplateSettingsLayout } from "pages/TemplateSettingsPage/TemplateSettingsLayout"
20+
import { WorkspaceSettingsLayout } from "pages/WorkspaceSettingsPage/WorkspaceSettingsLayout"
2021

2122
// Lazy load pages
2223
// - Pages that are secondary, not in the main navigation or not usually accessed
@@ -45,7 +46,10 @@ const WorkspaceBuildPage = lazy(
4546
)
4647
const WorkspacePage = lazy(() => import("./pages/WorkspacePage/WorkspacePage"))
4748
const WorkspaceSchedulePage = lazy(
48-
() => import("./pages/WorkspaceSchedulePage/WorkspaceSchedulePage"),
49+
() =>
50+
import(
51+
"./pages/WorkspaceSettingsPage/WorkspaceSchedulePage/WorkspaceSchedulePage"
52+
),
4953
)
5054
const TerminalPage = lazy(() => import("./pages/TerminalPage/TerminalPage"))
5155
const TemplatePermissionsPage = lazy(
@@ -260,12 +264,17 @@ export const AppRouter: FC = () => {
260264
<Route path="/@:username">
261265
<Route path=":workspace">
262266
<Route index element={<WorkspacePage />} />
263-
<Route path="schedule" element={<WorkspaceSchedulePage />} />
264267
<Route
265268
path="builds/:buildNumber"
266269
element={<WorkspaceBuildPage />}
267270
/>
268-
<Route path="settings" element={<WorkspaceSettingsPage />} />
271+
<Route path="settings" element={<WorkspaceSettingsLayout />}>
272+
<Route index element={<WorkspaceSettingsPage />} />
273+
<Route
274+
path="schedule"
275+
element={<WorkspaceSchedulePage />}
276+
/>
277+
</Route>
269278
</Route>
270279
</Route>
271280
</Route>

site/src/components/WorkspaceSchedule/WorkspaceSchedule.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export const WorkspaceSchedule: FC<
7474
<Link
7575
className={styles.scheduleAction}
7676
component={RouterLink}
77-
to={`/@${workspace.owner_name}/${workspace.name}/schedule`}
77+
to={`/@${workspace.owner_name}/${workspace.name}/settings/schedule`}
7878
>
7979
{Language.editScheduleLink}
8080
</Link>

site/src/components/WorkspaceScheduleForm/WorkspaceScheduleForm.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import utc from "dayjs/plugin/utc"
66
import {
77
defaultSchedule,
88
emptySchedule,
9-
} from "pages/WorkspaceSchedulePage/schedule"
10-
import { emptyTTL } from "pages/WorkspaceSchedulePage/ttl"
9+
} from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule"
10+
import { emptyTTL } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/ttl"
1111
import { makeMockApiError } from "testHelpers/entities"
1212
import {
1313
WorkspaceScheduleForm,

site/src/components/WorkspaceScheduleForm/WorkspaceScheduleForm.tsx

Lines changed: 103 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ import MenuItem from "@material-ui/core/MenuItem"
88
import makeStyles from "@material-ui/core/styles/makeStyles"
99
import Switch from "@material-ui/core/Switch"
1010
import TextField from "@material-ui/core/TextField"
11-
import { AlertBanner } from "components/AlertBanner/AlertBanner"
12-
import { Section } from "components/Section/Section"
11+
import {
12+
HorizontalForm,
13+
FormFooter,
14+
FormSection,
15+
FormFields,
16+
} from "components/Form/Form"
17+
import { Stack } from "components/Stack/Stack"
1318
import dayjs from "dayjs"
1419
import advancedFormat from "dayjs/plugin/advancedFormat"
1520
import duration from "dayjs/plugin/duration"
@@ -20,13 +25,10 @@ import { FormikTouched, useFormik } from "formik"
2025
import {
2126
defaultSchedule,
2227
emptySchedule,
23-
} from "pages/WorkspaceSchedulePage/schedule"
28+
} from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule"
2429
import { ChangeEvent, FC } from "react"
2530
import * as Yup from "yup"
2631
import { getFormHelpers } from "../../util/formUtils"
27-
import { FormFooter } from "../FormFooter/FormFooter"
28-
import { FullPageForm } from "../FullPageForm/FullPageForm"
29-
import { Stack } from "../Stack/Stack"
3032
import { zones } from "./zones"
3133

3234
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
@@ -48,16 +50,14 @@ export const Language = {
4850
errorTtlMax:
4951
"Please enter a limit that is less than or equal to 168 hours (7 days).",
5052
daysOfWeekLabel: "Days of Week",
51-
daySundayLabel: "Sunday",
52-
dayMondayLabel: "Monday",
53-
dayTuesdayLabel: "Tuesday",
54-
dayWednesdayLabel: "Wednesday",
55-
dayThursdayLabel: "Thursday",
56-
dayFridayLabel: "Friday",
57-
daySaturdayLabel: "Saturday",
53+
daySundayLabel: "Sun",
54+
dayMondayLabel: "Mon",
55+
dayTuesdayLabel: "Tue",
56+
dayWednesdayLabel: "Wed",
57+
dayThursdayLabel: "Thu",
58+
dayFridayLabel: "Fri",
59+
daySaturdayLabel: "Sat",
5860
startTimeLabel: "Start time",
59-
startTimeHelperText: "Your workspace will automatically start at this time.",
60-
noStartTimeHelperText: "Your workspace will not automatically start.",
6161
timezoneLabel: "Timezone",
6262
ttlLabel: "Time until shutdown (hours)",
6363
ttlCausesShutdownHelperText: "Your workspace will shut down",
@@ -67,13 +67,13 @@ export const Language = {
6767
"Your workspace will not automatically shut down.",
6868
formTitle: "Workspace schedule",
6969
startSection: "Start",
70-
startSwitch: "Autostart",
70+
startSwitch: "Enable Autostart",
7171
stopSection: "Stop",
72-
stopSwitch: "Autostop",
72+
stopSwitch: "Enable Autostop",
7373
}
7474

7575
export interface WorkspaceScheduleFormProps {
76-
submitScheduleError?: Error | unknown
76+
submitScheduleError?: unknown
7777
initialValues: WorkspaceScheduleFormValues
7878
isLoading: boolean
7979
onCancel: () => void
@@ -280,31 +280,26 @@ export const WorkspaceScheduleForm: FC<
280280
}
281281

282282
return (
283-
<FullPageForm title={Language.formTitle}>
284-
<form onSubmit={form.handleSubmit} className={styles.form}>
285-
<Stack>
286-
{Boolean(submitScheduleError) && (
287-
<AlertBanner severity="error" error={submitScheduleError} />
288-
)}
289-
<Section title={Language.startSection}>
290-
<FormControlLabel
291-
control={
292-
<Switch
293-
name="autostartEnabled"
294-
checked={form.values.autostartEnabled}
295-
onChange={handleToggleAutostart}
296-
color="primary"
297-
/>
298-
}
299-
label={Language.startSwitch}
300-
/>
283+
<HorizontalForm onSubmit={form.handleSubmit}>
284+
<FormSection
285+
title="Autostart"
286+
description="Select the time and days of week on which you want the workspace starting automatically."
287+
>
288+
<FormFields>
289+
<FormControlLabel
290+
control={
291+
<Switch
292+
name="autostartEnabled"
293+
checked={form.values.autostartEnabled}
294+
onChange={handleToggleAutostart}
295+
color="primary"
296+
/>
297+
}
298+
label={Language.startSwitch}
299+
/>
300+
<Stack direction="row">
301301
<TextField
302-
{...formHelpers(
303-
"startTime",
304-
form.values.autostartEnabled
305-
? Language.startTimeHelperText
306-
: Language.noStartTimeHelperText,
307-
)}
302+
{...formHelpers("startTime")}
308303
disabled={isLoading || !form.values.autostartEnabled}
309304
InputLabelProps={{
310305
shrink: true,
@@ -313,7 +308,6 @@ export const WorkspaceScheduleForm: FC<
313308
type="time"
314309
fullWidth
315310
/>
316-
317311
<TextField
318312
{...formHelpers("timezone")}
319313
disabled={isLoading || !form.values.autostartEnabled}
@@ -330,67 +324,68 @@ export const WorkspaceScheduleForm: FC<
330324
</MenuItem>
331325
))}
332326
</TextField>
327+
</Stack>
333328

334-
<FormControl
335-
component="fieldset"
336-
error={Boolean(form.errors.monday)}
337-
>
338-
<FormLabel className={styles.daysOfWeekLabel} component="legend">
339-
{Language.daysOfWeekLabel}
340-
</FormLabel>
329+
<FormControl component="fieldset" error={Boolean(form.errors.monday)}>
330+
<FormLabel className={styles.daysOfWeekLabel} component="legend">
331+
{Language.daysOfWeekLabel}
332+
</FormLabel>
341333

342-
<FormGroup>
343-
{checkboxes.map((checkbox) => (
344-
<FormControlLabel
345-
control={
346-
<Checkbox
347-
checked={checkbox.value}
348-
disabled={isLoading || !form.values.autostartEnabled}
349-
onChange={form.handleChange}
350-
name={checkbox.name}
351-
color="primary"
352-
size="small"
353-
disableRipple
354-
/>
355-
}
356-
key={checkbox.name}
357-
label={checkbox.label}
358-
/>
359-
))}
360-
</FormGroup>
361-
362-
{form.errors.monday && (
363-
<FormHelperText>{Language.errorNoDayOfWeek}</FormHelperText>
364-
)}
365-
</FormControl>
366-
</Section>
367-
368-
<Section title={Language.stopSection}>
369-
<FormControlLabel
370-
control={
371-
<Switch
372-
name="autostopEnabled"
373-
checked={form.values.autostopEnabled}
374-
onChange={handleToggleAutostop}
375-
color="primary"
334+
<FormGroup className={styles.daysOfWeekOptions}>
335+
{checkboxes.map((checkbox) => (
336+
<FormControlLabel
337+
control={
338+
<Checkbox
339+
checked={checkbox.value}
340+
disabled={isLoading || !form.values.autostartEnabled}
341+
onChange={form.handleChange}
342+
name={checkbox.name}
343+
color="primary"
344+
size="small"
345+
disableRipple
346+
/>
347+
}
348+
key={checkbox.name}
349+
label={checkbox.label}
376350
/>
377-
}
378-
label={Language.stopSwitch}
379-
/>
380-
<TextField
381-
{...formHelpers("ttl", ttlShutdownAt(form.values.ttl), "ttl_ms")}
382-
disabled={isLoading || !form.values.autostopEnabled}
383-
inputProps={{ min: 0, step: 1 }}
384-
label={Language.ttlLabel}
385-
type="number"
386-
fullWidth
387-
/>
388-
</Section>
351+
))}
352+
</FormGroup>
353+
354+
{form.errors.monday && (
355+
<FormHelperText>{Language.errorNoDayOfWeek}</FormHelperText>
356+
)}
357+
</FormControl>
358+
</FormFields>
359+
</FormSection>
389360

390-
<FormFooter onCancel={onCancel} isLoading={isLoading} />
391-
</Stack>
392-
</form>
393-
</FullPageForm>
361+
<FormSection
362+
title="Autostop"
363+
description="Set how many hours should elapse after a workspace is started before it automatically shuts down. If workspace connection activity is detected, the autostop timer will be bumped up one hour."
364+
>
365+
<FormFields>
366+
<FormControlLabel
367+
control={
368+
<Switch
369+
name="autostopEnabled"
370+
checked={form.values.autostopEnabled}
371+
onChange={handleToggleAutostop}
372+
color="primary"
373+
/>
374+
}
375+
label={Language.stopSwitch}
376+
/>
377+
<TextField
378+
{...formHelpers("ttl", ttlShutdownAt(form.values.ttl), "ttl_ms")}
379+
disabled={isLoading || !form.values.autostopEnabled}
380+
inputProps={{ min: 0, step: 1 }}
381+
label={Language.ttlLabel}
382+
type="number"
383+
fullWidth
384+
/>
385+
</FormFields>
386+
</FormSection>
387+
<FormFooter onCancel={onCancel} isLoading={isLoading} />
388+
</HorizontalForm>
394389
)
395390
}
396391

@@ -405,13 +400,14 @@ export const ttlShutdownAt = (formTTL: number): string => {
405400
}
406401
}
407402

408-
const useStyles = makeStyles({
409-
form: {
410-
"& input": {
411-
colorScheme: "dark",
412-
},
413-
},
403+
const useStyles = makeStyles((theme) => ({
414404
daysOfWeekLabel: {
415405
fontSize: 12,
416406
},
417-
})
407+
daysOfWeekOptions: {
408+
display: "flex",
409+
flexDirection: "row",
410+
flexWrap: "wrap",
411+
paddingTop: theme.spacing(0.5),
412+
},
413+
}))

0 commit comments

Comments
 (0)