mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(site): match activity bump text with template settings (#12170)
Close https://github.com/coder/coder/issues/12130
This commit is contained in:
+26
-13
@@ -8,20 +8,19 @@ import {
|
||||
emptySchedule,
|
||||
} from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/schedule";
|
||||
import { emptyTTL } from "pages/WorkspaceSettingsPage/WorkspaceSchedulePage/ttl";
|
||||
import { mockApiError } from "testHelpers/entities";
|
||||
import { MockTemplate, mockApiError } from "testHelpers/entities";
|
||||
import { WorkspaceScheduleForm } from "./WorkspaceScheduleForm";
|
||||
|
||||
dayjs.extend(advancedFormat);
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
const meta: Meta<typeof WorkspaceScheduleForm> = {
|
||||
title: "pages/WorkspaceSettingsPage/WorkspaceScheduleForm",
|
||||
component: WorkspaceScheduleForm,
|
||||
args: {
|
||||
allowTemplateAutoStart: true,
|
||||
allowTemplateAutoStop: true,
|
||||
allowedTemplateAutoStartDays: [
|
||||
const mockTemplate = {
|
||||
...MockTemplate,
|
||||
allow_user_autostart: true,
|
||||
allow_user_autostop: true,
|
||||
autostart_requirement: {
|
||||
days_of_week: [
|
||||
"sunday",
|
||||
"monday",
|
||||
"tuesday",
|
||||
@@ -33,12 +32,20 @@ const meta: Meta<typeof WorkspaceScheduleForm> = {
|
||||
},
|
||||
};
|
||||
|
||||
const meta: Meta<typeof WorkspaceScheduleForm> = {
|
||||
title: "pages/WorkspaceSettingsPage/WorkspaceScheduleForm",
|
||||
component: WorkspaceScheduleForm,
|
||||
args: {
|
||||
template: mockTemplate,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof WorkspaceScheduleForm>;
|
||||
|
||||
const defaultInitialValues = {
|
||||
autostartEnabled: true,
|
||||
...defaultSchedule(),
|
||||
autostartEnabled: true,
|
||||
autostopEnabled: true,
|
||||
ttl: 24,
|
||||
};
|
||||
@@ -51,8 +58,11 @@ export const AllDisabled: Story = {
|
||||
autostopEnabled: false,
|
||||
ttl: emptyTTL,
|
||||
},
|
||||
allowTemplateAutoStart: false,
|
||||
allowTemplateAutoStop: false,
|
||||
template: {
|
||||
...mockTemplate,
|
||||
allow_user_autostart: false,
|
||||
allow_user_autostop: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -64,7 +74,10 @@ export const Autostart: Story = {
|
||||
autostopEnabled: false,
|
||||
ttl: emptyTTL,
|
||||
},
|
||||
allowTemplateAutoStop: false,
|
||||
template: {
|
||||
...mockTemplate,
|
||||
allow_user_autostop: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -90,7 +103,7 @@ export const WithError: Story = {
|
||||
args: {
|
||||
initialValues: { ...defaultInitialValues, ttl: 100 },
|
||||
initialTouched: { ttl: true },
|
||||
submitScheduleError: mockApiError({
|
||||
error: mockApiError({
|
||||
message: "Something went wrong.",
|
||||
validations: [
|
||||
{ field: "ttl_ms", detail: "Invalid time until shutdown." },
|
||||
|
||||
+49
-33
@@ -4,6 +4,7 @@ import {
|
||||
validationSchema,
|
||||
WorkspaceScheduleFormValues,
|
||||
WorkspaceScheduleForm,
|
||||
WorkspaceScheduleFormProps,
|
||||
} from "./WorkspaceScheduleForm";
|
||||
import { timeZones } from "utils/timeZones";
|
||||
import * as API from "api/api";
|
||||
@@ -245,8 +246,8 @@ describe("ttlShutdownAt", () => {
|
||||
});
|
||||
|
||||
const autoStartDayLabels = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
const defaultFormProps = {
|
||||
submitScheduleError: "",
|
||||
const defaultFormProps: WorkspaceScheduleFormProps = {
|
||||
error: "",
|
||||
initialValues: {
|
||||
...defaultSchedule(),
|
||||
autostartEnabled: true,
|
||||
@@ -257,20 +258,28 @@ const defaultFormProps = {
|
||||
defaultTTL: 24,
|
||||
onCancel: () => null,
|
||||
onSubmit: () => null,
|
||||
allowedTemplateAutoStartDays: autoStartDayLabels,
|
||||
allowTemplateAutoStart: true,
|
||||
allowTemplateAutoStop: true,
|
||||
template: {
|
||||
...MockTemplate,
|
||||
allow_user_autostart: true,
|
||||
allow_user_autostop: true,
|
||||
autostart_requirement: {
|
||||
...MockTemplate.autostart_requirement,
|
||||
days_of_week: autoStartDayLabels,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("templateInheritance", () => {
|
||||
it("disables the entire autostart feature appropriately", async () => {
|
||||
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
|
||||
render(
|
||||
<WorkspaceScheduleForm
|
||||
{...defaultFormProps}
|
||||
allowTemplateAutoStart={false}
|
||||
/>,
|
||||
);
|
||||
const props = {
|
||||
...defaultFormProps,
|
||||
template: {
|
||||
...defaultFormProps.template,
|
||||
allow_user_autostart: false,
|
||||
},
|
||||
};
|
||||
render(<WorkspaceScheduleForm {...props} />);
|
||||
|
||||
const autoStartToggle = await screen.findByLabelText("Enable Autostart");
|
||||
expect(autoStartToggle).toBeDisabled();
|
||||
@@ -291,12 +300,18 @@ describe("templateInheritance", () => {
|
||||
const enabledDayLabels = ["Sat", "Sun"];
|
||||
|
||||
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
|
||||
render(
|
||||
<WorkspaceScheduleForm
|
||||
{...defaultFormProps}
|
||||
allowedTemplateAutoStartDays={["saturday", "sunday"]}
|
||||
/>,
|
||||
);
|
||||
const props = {
|
||||
...defaultFormProps,
|
||||
template: {
|
||||
...defaultFormProps.template,
|
||||
autostart_requirement: {
|
||||
...MockTemplate.autostart_requirement,
|
||||
days_of_week: ["saturday", "sunday"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
render(<WorkspaceScheduleForm {...props} />);
|
||||
|
||||
const autoStartToggle = await screen.findByLabelText("Enable Autostart");
|
||||
expect(autoStartToggle).toBeEnabled();
|
||||
@@ -321,13 +336,15 @@ describe("templateInheritance", () => {
|
||||
}
|
||||
});
|
||||
it("disables the entire autostop feature appropriately", async () => {
|
||||
const props = {
|
||||
...defaultFormProps,
|
||||
template: {
|
||||
...defaultFormProps.template,
|
||||
allow_user_autostop: false,
|
||||
},
|
||||
};
|
||||
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
|
||||
render(
|
||||
<WorkspaceScheduleForm
|
||||
{...defaultFormProps}
|
||||
allowTemplateAutoStop={false}
|
||||
/>,
|
||||
);
|
||||
render(<WorkspaceScheduleForm {...props} />);
|
||||
|
||||
const autoStopToggle = await screen.findByLabelText("Enable Autostop");
|
||||
expect(autoStopToggle).toBeDisabled();
|
||||
@@ -398,17 +415,16 @@ test("form should be enabled when both auto stop and auto start features are dis
|
||||
});
|
||||
|
||||
test("form should be disabled when both auto stop and auto start features are disabled at template level", async () => {
|
||||
const props = {
|
||||
...defaultFormProps,
|
||||
template: {
|
||||
...defaultFormProps.template,
|
||||
allow_user_autostart: false,
|
||||
allow_user_autostop: false,
|
||||
},
|
||||
};
|
||||
jest.spyOn(API, "getTemplateByName").mockResolvedValue(MockTemplate);
|
||||
render(
|
||||
<WorkspaceScheduleForm
|
||||
{...defaultFormProps}
|
||||
allowTemplateAutoStart={false}
|
||||
allowTemplateAutoStop={false}
|
||||
initialValues={{
|
||||
...defaultFormProps.initialValues,
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
render(<WorkspaceScheduleForm {...props} />);
|
||||
|
||||
const submitButton = await screen.findByRole("button", { name: "Submit" });
|
||||
expect(submitButton).toBeDisabled();
|
||||
|
||||
+25
-26
@@ -32,7 +32,7 @@ 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 { Template } from "api/typesGenerated";
|
||||
|
||||
// REMARK: some plugins depend on utc, so it's listed first. Otherwise they're
|
||||
// sorted alphabetically.
|
||||
@@ -71,12 +71,10 @@ export const Language = {
|
||||
};
|
||||
|
||||
export interface WorkspaceScheduleFormProps {
|
||||
submitScheduleError?: unknown;
|
||||
template: Template;
|
||||
error?: unknown;
|
||||
initialValues: WorkspaceScheduleFormValues;
|
||||
isLoading: boolean;
|
||||
allowedTemplateAutoStartDays: TemplateAutostartRequirement["days_of_week"];
|
||||
allowTemplateAutoStop: boolean;
|
||||
allowTemplateAutoStart: boolean;
|
||||
onCancel: () => void;
|
||||
onSubmit: (values: WorkspaceScheduleFormValues) => void;
|
||||
// for storybook
|
||||
@@ -95,7 +93,6 @@ export interface WorkspaceScheduleFormValues {
|
||||
saturday: boolean;
|
||||
startTime: string;
|
||||
timezone: string;
|
||||
|
||||
autostopEnabled: boolean;
|
||||
ttl: number;
|
||||
}
|
||||
@@ -184,16 +181,14 @@ export const validationSchema = Yup.object({
|
||||
});
|
||||
|
||||
export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
submitScheduleError,
|
||||
error,
|
||||
initialValues,
|
||||
isLoading,
|
||||
onCancel,
|
||||
onSubmit,
|
||||
initialTouched,
|
||||
defaultTTL,
|
||||
allowedTemplateAutoStartDays,
|
||||
allowTemplateAutoStop,
|
||||
allowTemplateAutoStart,
|
||||
template,
|
||||
}) => {
|
||||
const form = useFormik<WorkspaceScheduleFormValues>({
|
||||
initialValues,
|
||||
@@ -202,10 +197,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
initialTouched,
|
||||
enableReinitialize: true,
|
||||
});
|
||||
const formHelpers = getFormHelpers<WorkspaceScheduleFormValues>(
|
||||
form,
|
||||
submitScheduleError,
|
||||
);
|
||||
const formHelpers = getFormHelpers<WorkspaceScheduleFormValues>(form, error);
|
||||
|
||||
const checkboxes: Array<{ value: boolean; name: string; label: string }> = [
|
||||
{
|
||||
@@ -289,7 +281,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
Select the time and days of week on which you want the workspace
|
||||
starting automatically.
|
||||
</div>
|
||||
{!allowTemplateAutoStart && (
|
||||
{!template.allow_user_autostart && (
|
||||
<Tooltip title="This option can be enabled in the template settings">
|
||||
<DisabledBadge />
|
||||
</Tooltip>
|
||||
@@ -301,7 +293,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
disabled={!allowTemplateAutoStart}
|
||||
disabled={!template.allow_user_autostart}
|
||||
name="autostartEnabled"
|
||||
checked={form.values.autostartEnabled}
|
||||
onChange={handleToggleAutostart}
|
||||
@@ -316,7 +308,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
// or if primary feature is toggled off via the switch above
|
||||
disabled={
|
||||
isLoading ||
|
||||
!allowTemplateAutoStart ||
|
||||
!template.allow_user_autostart ||
|
||||
!form.values.autostartEnabled
|
||||
}
|
||||
label={Language.startTimeLabel}
|
||||
@@ -329,7 +321,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
// or if primary feature is toggled off via the switch above
|
||||
disabled={
|
||||
isLoading ||
|
||||
!allowTemplateAutoStart ||
|
||||
!template.allow_user_autostart ||
|
||||
!form.values.autostartEnabled
|
||||
}
|
||||
label={Language.timezoneLabel}
|
||||
@@ -367,8 +359,10 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
// also disabled if primary feature switch (above) is toggled off
|
||||
disabled={
|
||||
isLoading ||
|
||||
!allowTemplateAutoStart ||
|
||||
!allowedTemplateAutoStartDays.includes(checkbox.name) ||
|
||||
!template.allow_user_autostart ||
|
||||
!template.autostart_requirement.days_of_week.includes(
|
||||
checkbox.name,
|
||||
) ||
|
||||
!form.values.autostartEnabled
|
||||
}
|
||||
onChange={form.handleChange}
|
||||
@@ -396,10 +390,13 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
<div css={{ marginBottom: 16 }}>
|
||||
Set how many hours should elapse after the workspace started
|
||||
before the workspace automatically shuts down. This will be
|
||||
extended by 1 hour after last activity in the workspace was
|
||||
detected.
|
||||
extended by{" "}
|
||||
{dayjs
|
||||
.duration({ milliseconds: template.activity_bump_ms })
|
||||
.humanize()}{" "}
|
||||
after last activity in the workspace was detected.
|
||||
</div>
|
||||
{!allowTemplateAutoStop && (
|
||||
{!template.allow_user_autostop && (
|
||||
<Tooltip title="This option can be enabled in the template settings">
|
||||
<DisabledBadge />
|
||||
</Tooltip>
|
||||
@@ -414,7 +411,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
name="autostopEnabled"
|
||||
checked={form.values.autostopEnabled}
|
||||
onChange={handleToggleAutostop}
|
||||
disabled={!allowTemplateAutoStop}
|
||||
disabled={!template.allow_user_autostop}
|
||||
/>
|
||||
}
|
||||
label={Language.stopSwitch}
|
||||
@@ -428,7 +425,7 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
// if autostop feature is toggled off via the switch above
|
||||
disabled={
|
||||
isLoading ||
|
||||
!allowTemplateAutoStop ||
|
||||
!template.allow_user_autostop ||
|
||||
!form.values.autostopEnabled
|
||||
}
|
||||
inputProps={{ min: 0, step: "any" }}
|
||||
@@ -443,7 +440,9 @@ export const WorkspaceScheduleForm: FC<WorkspaceScheduleFormProps> = ({
|
||||
isLoading={isLoading}
|
||||
// If both options, autostart and autostop, are disabled at the template
|
||||
// level, the form is disabled.
|
||||
submitDisabled={!allowTemplateAutoStart && !allowTemplateAutoStop}
|
||||
submitDisabled={
|
||||
!template.allow_user_autostart && !template.allow_user_autostop
|
||||
}
|
||||
/>
|
||||
</HorizontalForm>
|
||||
);
|
||||
|
||||
+2
-6
@@ -101,12 +101,8 @@ export const WorkspaceSchedulePage: FC = () => {
|
||||
|
||||
{template && (
|
||||
<WorkspaceScheduleForm
|
||||
allowedTemplateAutoStartDays={
|
||||
template.autostart_requirement.days_of_week
|
||||
}
|
||||
allowTemplateAutoStart={template.allow_user_autostart}
|
||||
allowTemplateAutoStop={template.allow_user_autostop}
|
||||
submitScheduleError={submitScheduleMutation.error}
|
||||
template={template}
|
||||
error={submitScheduleMutation.error}
|
||||
initialValues={{
|
||||
...getAutostart(workspace),
|
||||
...getAutostop(workspace),
|
||||
|
||||
Reference in New Issue
Block a user