feat: allow templates to specify max_ttl or autostop_requirement (#10920)

This commit is contained in:
Dean Sheather
2023-12-15 18:27:56 +10:00
committed by GitHub
parent 30f032d282
commit b36071c6bb
46 changed files with 699 additions and 495 deletions
+1 -4
View File
@@ -958,6 +958,7 @@ export interface Template {
readonly deprecation_message: string;
readonly icon: string;
readonly default_ttl_ms: number;
readonly use_max_ttl: boolean;
readonly max_ttl_ms: number;
readonly autostop_requirement: TemplateAutostopRequirement;
readonly autostart_requirement: TemplateAutostartRequirement;
@@ -1776,7 +1777,6 @@ export type Experiment =
| "moons"
| "single_tailnet"
| "tailnet_pg_coordinator"
| "template_autostop_requirement"
| "template_update_policies"
| "workspace_actions";
export const Experiments: Experiment[] = [
@@ -1784,7 +1784,6 @@ export const Experiments: Experiment[] = [
"moons",
"single_tailnet",
"tailnet_pg_coordinator",
"template_autostop_requirement",
"template_update_policies",
"workspace_actions",
];
@@ -1801,7 +1800,6 @@ export type FeatureName =
| "high_availability"
| "multiple_external_auth"
| "scim"
| "template_autostop_requirement"
| "template_rbac"
| "user_limit"
| "user_role_management"
@@ -1818,7 +1816,6 @@ export const FeatureNames: FeatureName[] = [
"high_availability",
"multiple_external_auth",
"scim",
"template_autostop_requirement",
"template_rbac",
"user_limit",
"user_role_management",
+17
View File
@@ -122,6 +122,23 @@ export const AlphaBadge: FC = () => {
);
};
export const DeprecatedBadge: FC = () => {
return (
<span
css={[
styles.badge,
{
border: `1px solid ${colors.orange[600]}`,
backgroundColor: colors.orange[950],
color: colors.orange[50],
},
]}
>
Deprecated
</span>
);
};
export const Badges: FC<PropsWithChildren> = ({ children }) => {
return (
<Stack
+11 -2
View File
@@ -6,7 +6,7 @@ import {
type PropsWithChildren,
useContext,
} from "react";
import { AlphaBadge } from "components/Badges/Badges";
import { AlphaBadge, DeprecatedBadge } from "components/Badges/Badges";
import { Stack } from "components/Stack/Stack";
import {
FormFooter as BaseFormFooter,
@@ -77,8 +77,16 @@ export const FormSection: FC<
infoTitle?: string;
};
alpha?: boolean;
deprecated?: boolean;
}
> = ({ children, title, description, classes = {}, alpha = false }) => {
> = ({
children,
title,
description,
classes = {},
alpha = false,
deprecated = false,
}) => {
const { direction } = useContext(FormContext);
const theme = useTheme();
@@ -121,6 +129,7 @@ export const FormSection: FC<
>
{title}
{alpha && <AlphaBadge />}
{deprecated && <DeprecatedBadge />}
</h2>
<div css={styles.formSectionInfoDescription}>{description}</div>
</div>
@@ -60,6 +60,7 @@ export interface CreateTemplateData {
description: string;
icon: string;
default_ttl_hours: number;
use_max_ttl: boolean;
max_ttl_hours: number;
autostart_requirement_days_of_week: TemplateAutostartRequirementDaysValue[];
autostop_requirement_days_of_week: TemplateAutostopRequirementDaysValue;
@@ -110,6 +111,7 @@ const defaultInitialValues: CreateTemplateData = {
//
// The maximum value is 30 days but we default to 7 days as it's a much more
// sensible value for most teams.
use_max_ttl: false, // autostop_requirement is default
max_ttl_hours: 24 * 7,
// autostop_requirement is an enterprise-only feature, and the server ignores
// the value if you are not licensed. We hide the form value based on
@@ -145,6 +147,8 @@ const getInitialValues = ({
initialValues = {
...initialValues,
max_ttl_hours: 0,
autostop_requirement_days_of_week: "off",
autostop_requirement_weeks: 1,
};
}
@@ -202,7 +206,6 @@ export type CreateTemplateFormProps = (
logs?: ProvisionerJobLog[];
allowAdvancedScheduling: boolean;
allowDisableEveryoneAccess: boolean;
allowAutostopRequirement: boolean;
};
export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
@@ -216,7 +219,6 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
logs,
allowAdvancedScheduling,
allowDisableEveryoneAccess,
allowAutostopRequirement,
} = props;
const form = useFormik<CreateTemplateData>({
initialValues: getInitialValues({
@@ -262,6 +264,27 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
}
}, [autostop_requirement_days_of_week, setFieldValue]);
const handleToggleUseMaxTTL = async () => {
const val = !form.values.use_max_ttl;
if (val) {
// set max_ttl to 1, set autostop_requirement to empty
await form.setValues({
...form.values,
use_max_ttl: val,
max_ttl_hours: 1,
autostop_requirement_days_of_week: "off",
autostop_requirement_weeks: 1,
});
} else {
// set max_ttl to 0
await form.setValues({
...form.values,
use_max_ttl: val,
max_ttl_hours: 0,
});
}
};
return (
<HorizontalForm onSubmit={form.handleSubmit}>
{/* General info */}
@@ -349,78 +372,107 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
label="Default autostop (hours)"
type="number"
/>
{!allowAutostopRequirement && (
<TextField
{...getFieldHelpers(
"max_ttl_hours",
allowAdvancedScheduling ? (
<MaxTTLHelperText ttl={form.values.max_ttl_hours} />
) : (
<>
You need an enterprise license to use it.{" "}
<Link href={docs("/enterprise")}>Learn more</Link>.
</>
),
)}
disabled={isSubmitting || !allowAdvancedScheduling}
fullWidth
label="Max lifetime (hours)"
type="number"
/>
)}
</Stack>
{allowAutostopRequirement && (
<Stack direction="row" css={styles.ttlFields}>
<TextField
{...getFieldHelpers(
"autostop_requirement_days_of_week",
<AutostopRequirementDaysHelperText
days={form.values.autostop_requirement_days_of_week}
/>,
)}
disabled={isSubmitting}
fullWidth
select
value={form.values.autostop_requirement_days_of_week}
label="Days with required stop"
>
<MenuItem key="off" value="off">
Off
</MenuItem>
<MenuItem key="daily" value="daily">
Daily
</MenuItem>
<MenuItem key="saturday" value="saturday">
Saturday
</MenuItem>
<MenuItem key="sunday" value="sunday">
Sunday
</MenuItem>
</TextField>
<Stack direction="row" css={styles.ttlFields}>
<TextField
{...getFieldHelpers(
"autostop_requirement_days_of_week",
<AutostopRequirementDaysHelperText
days={form.values.autostop_requirement_days_of_week}
/>,
)}
disabled={
isSubmitting ||
form.values.use_max_ttl ||
!allowAdvancedScheduling
}
fullWidth
select
value={form.values.autostop_requirement_days_of_week}
label="Days with required stop"
>
<MenuItem key="off" value="off">
Off
</MenuItem>
<MenuItem key="daily" value="daily">
Daily
</MenuItem>
<MenuItem key="saturday" value="saturday">
Saturday
</MenuItem>
<MenuItem key="sunday" value="sunday">
Sunday
</MenuItem>
</TextField>
<TextField
{...getFieldHelpers(
"autostop_requirement_weeks",
<AutostopRequirementWeeksHelperText
days={form.values.autostop_requirement_days_of_week}
weeks={form.values.autostop_requirement_weeks}
/>,
)}
disabled={
isSubmitting ||
!["saturday", "sunday"].includes(
form.values.autostop_requirement_days_of_week || "",
)
}
fullWidth
inputProps={{ min: 1, max: 16, step: 1 }}
label="Weeks between required stops"
type="number"
<TextField
{...getFieldHelpers(
"autostop_requirement_weeks",
<AutostopRequirementWeeksHelperText
days={form.values.autostop_requirement_days_of_week}
weeks={form.values.autostop_requirement_weeks}
/>,
)}
disabled={
isSubmitting ||
form.values.use_max_ttl ||
!allowAdvancedScheduling ||
!["saturday", "sunday"].includes(
form.values.autostop_requirement_days_of_week || "",
)
}
fullWidth
inputProps={{ min: 1, max: 16, step: 1 }}
label="Weeks between required stops"
type="number"
/>
</Stack>
<Stack direction="column">
<Stack direction="row" alignItems="center">
<Checkbox
id="use_max_ttl"
size="small"
disabled={isSubmitting || !allowAdvancedScheduling}
onChange={handleToggleUseMaxTTL}
name="use_max_ttl"
checked={form.values.use_max_ttl}
/>
<Stack spacing={0.5}>
<strong>
Use a max lifetime instead of a required autostop schedule.
</strong>
<span css={styles.optionHelperText}>
Use a maximum lifetime for workspaces created from this
template instead of an autostop requirement as configured
above.
</span>
</Stack>
</Stack>
)}
<TextField
{...getFieldHelpers(
"max_ttl_hours",
allowAdvancedScheduling ? (
<MaxTTLHelperText ttl={form.values.max_ttl_hours} />
) : (
<>
You need an enterprise license to use it.{" "}
<Link href={docs("/enterprise")}>Learn more</Link>.
</>
),
)}
disabled={
isSubmitting ||
!form.values.use_max_ttl ||
!allowAdvancedScheduling
}
fullWidth
label="Max lifetime (hours)"
type="number"
/>
</Stack>
<Stack direction="column">
<Stack direction="row" alignItems="center">
@@ -482,8 +534,8 @@ export const CreateTemplateForm: FC<CreateTemplateFormProps> = (props) => {
</strong>
<span css={styles.optionHelperText}>
Workspaces will always use the default TTL if this is set.
Regardless of this setting, workspaces can only stay on for
the max TTL.
Regardless of this setting, workspaces will still stop due to
the autostop requirement policy.
</span>
</Stack>
</Stack>
+25 -13
View File
@@ -12,30 +12,45 @@ const provisioner: ProvisionerType =
typeof (window as any).playwright !== "undefined" ? "echo" : "terraform";
export const newTemplate = (formData: CreateTemplateData) => {
const {
default_ttl_hours,
let {
max_ttl_hours,
parameter_values_by_name,
allow_everyone_group_access,
autostart_requirement_days_of_week,
autostop_requirement_days_of_week,
autostop_requirement_weeks,
...safeTemplateData
} = formData;
const safeTemplateData = {
name: formData.name,
display_name: formData.display_name,
description: formData.description,
icon: formData.icon,
use_max_ttl: formData.use_max_ttl,
allow_user_autostart: formData.allow_user_autostart,
allow_user_autostop: formData.allow_user_autostop,
allow_user_cancel_workspace_jobs: formData.allow_user_cancel_workspace_jobs,
user_variable_values: formData.user_variable_values,
allow_everyone_group_access: formData.allow_everyone_group_access,
};
if (formData.use_max_ttl) {
autostop_requirement_days_of_week = "off";
autostop_requirement_weeks = 1;
} else {
max_ttl_hours = 0;
}
return {
...safeTemplateData,
disable_everyone_group_access: !formData.allow_everyone_group_access,
default_ttl_ms: formData.default_ttl_hours * 60 * 60 * 1000, // Convert hours to ms
max_ttl_ms: formData.max_ttl_hours * 60 * 60 * 1000, // Convert hours to ms
max_ttl_ms: max_ttl_hours * 60 * 60 * 1000, // Convert hours to ms
autostop_requirement: {
days_of_week: calculateAutostopRequirementDaysValue(
formData.autostop_requirement_days_of_week,
autostop_requirement_days_of_week,
),
weeks: formData.autostop_requirement_weeks,
weeks: autostop_requirement_weeks,
},
autostart_requirement: {
days_of_week: autostart_requirement_days_of_week,
days_of_week: formData.autostart_requirement_days_of_week,
},
require_active_version: false,
};
@@ -48,13 +63,10 @@ export const getFormPermissions = (entitlements: Entitlements) => {
// means no one can access.
const allowDisableEveryoneAccess =
entitlements.features["template_rbac"].enabled;
const allowAutostopRequirement =
entitlements.features["template_autostop_requirement"].enabled;
return {
allowAdvancedScheduling,
allowDisableEveryoneAccess,
allowAutostopRequirement,
};
};
@@ -55,7 +55,6 @@ export interface TemplateScheduleForm {
error?: unknown;
allowAdvancedScheduling: boolean;
allowWorkspaceActions: boolean;
allowAutostopRequirement: boolean;
// Helpful to show field errors on Storybook
initialTouched?: FormikTouched<UpdateTemplateMeta>;
}
@@ -67,7 +66,6 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
error,
allowAdvancedScheduling,
allowWorkspaceActions,
allowAutostopRequirement,
isSubmitting,
initialTouched,
}) => {
@@ -78,6 +76,10 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
default_ttl_ms: template.default_ttl_ms / MS_HOUR_CONVERSION,
// the API ignores these values, but to avoid tripping up validation set
// it to zero if the user can't set the field.
use_max_ttl:
template.use_max_ttl === undefined
? template.max_ttl_ms > 0
: template.use_max_ttl,
max_ttl_ms: allowAdvancedScheduling
? template.max_ttl_ms / MS_HOUR_CONVERSION
: 0,
@@ -91,12 +93,12 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
? template.time_til_dormant_autodelete_ms / MS_DAY_CONVERSION
: 0,
autostop_requirement_days_of_week: allowAutostopRequirement
autostop_requirement_days_of_week: allowAdvancedScheduling
? convertAutostopRequirementDaysValue(
template.autostop_requirement.days_of_week,
)
: "off",
autostop_requirement_weeks: allowAutostopRequirement
autostop_requirement_weeks: allowAdvancedScheduling
? template.autostop_requirement.weeks > 0
? template.autostop_requirement.weeks
: 1
@@ -205,9 +207,10 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
default_ttl_ms: form.values.default_ttl_ms
? form.values.default_ttl_ms * MS_HOUR_CONVERSION
: undefined,
max_ttl_ms: form.values.max_ttl_ms
? form.values.max_ttl_ms * MS_HOUR_CONVERSION
: undefined,
max_ttl_ms:
form.values.max_ttl_ms && form.values.use_max_ttl
? form.values.max_ttl_ms * MS_HOUR_CONVERSION
: undefined,
failure_ttl_ms: form.values.failure_ttl_ms
? form.values.failure_ttl_ms * MS_DAY_CONVERSION
: undefined,
@@ -218,12 +221,14 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
? form.values.time_til_dormant_autodelete_ms * MS_DAY_CONVERSION
: undefined,
autostop_requirement: {
days_of_week: calculateAutostopRequirementDaysValue(
form.values.autostop_requirement_days_of_week,
),
weeks: autostop_requirement_weeks,
},
autostop_requirement: form.values.use_max_ttl
? undefined
: {
days_of_week: calculateAutostopRequirementDaysValue(
form.values.autostop_requirement_days_of_week,
),
weeks: autostop_requirement_weeks,
},
autostart_requirement: {
days_of_week: form.values.autostart_requirement_days_of_week,
},
@@ -317,6 +322,27 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
}
};
const handleToggleUseMaxTTL = async () => {
const val = !form.values.use_max_ttl;
if (val) {
// set max_ttl to 1, set autostop_requirement to empty
await form.setValues({
...form.values,
use_max_ttl: val,
max_ttl_ms: 1,
autostop_requirement_days_of_week: "off",
autostop_requirement_weeks: 1,
});
} else {
// set max_ttl to 0
await form.setValues({
...form.values,
use_max_ttl: val,
max_ttl_ms: 0,
});
}
};
return (
<HorizontalForm
onSubmit={form.handleSubmit}
@@ -338,85 +364,126 @@ export const TemplateScheduleForm: FC<TemplateScheduleForm> = ({
label="Default autostop (hours)"
type="number"
/>
{!allowAutostopRequirement && (
<TextField
{...getFieldHelpers(
"max_ttl_ms",
allowAdvancedScheduling ? (
<MaxTTLHelperText ttl={form.values.max_ttl_ms} />
) : (
<>
You need an enterprise license to use it{" "}
<Link href={docs("/enterprise")}>Learn more</Link>.
</>
),
)}
disabled={isSubmitting || !allowAdvancedScheduling}
fullWidth
inputProps={{ min: 0, step: 1 }}
label="Max lifetime (hours)"
type="number"
/>
)}
</Stack>
</FormSection>
{allowAutostopRequirement && (
<FormSection
title="Autostop Requirement"
description="Define when workspaces created from this template are stopped periodically to enforce template updates and ensure idle workspaces are stopped."
>
<Stack direction="row" css={styles.ttlFields}>
<TextField
{...getFieldHelpers(
"autostop_requirement_days_of_week",
<AutostopRequirementDaysHelperText
days={form.values.autostop_requirement_days_of_week}
/>,
)}
disabled={isSubmitting}
fullWidth
select
value={form.values.autostop_requirement_days_of_week}
label="Days with required stop"
>
<MenuItem key="off" value="off">
Off
</MenuItem>
<MenuItem key="daily" value="daily">
Daily
</MenuItem>
<MenuItem key="saturday" value="saturday">
Saturday
</MenuItem>
<MenuItem key="sunday" value="sunday">
Sunday
</MenuItem>
</TextField>
<FormSection
title="Autostop Requirement"
description="Define when workspaces created from this template are stopped periodically to enforce template updates and ensure idle workspaces are stopped."
>
<Stack direction="row" css={styles.ttlFields}>
<TextField
{...getFieldHelpers(
"autostop_requirement_days_of_week",
<AutostopRequirementDaysHelperText
days={form.values.autostop_requirement_days_of_week}
/>,
)}
disabled={isSubmitting || form.values.use_max_ttl}
fullWidth
select
value={form.values.autostop_requirement_days_of_week}
label="Days with required stop"
>
<MenuItem key="off" value="off">
Off
</MenuItem>
<MenuItem key="daily" value="daily">
Daily
</MenuItem>
<MenuItem key="saturday" value="saturday">
Saturday
</MenuItem>
<MenuItem key="sunday" value="sunday">
Sunday
</MenuItem>
</TextField>
<TextField
{...getFieldHelpers(
"autostop_requirement_weeks",
<AutostopRequirementWeeksHelperText
days={form.values.autostop_requirement_days_of_week}
weeks={form.values.autostop_requirement_weeks}
/>,
)}
disabled={
isSubmitting ||
!["saturday", "sunday"].includes(
form.values.autostop_requirement_days_of_week || "",
)
<TextField
{...getFieldHelpers(
"autostop_requirement_weeks",
<AutostopRequirementWeeksHelperText
days={form.values.autostop_requirement_days_of_week}
weeks={form.values.autostop_requirement_weeks}
/>,
)}
disabled={
isSubmitting ||
form.values.use_max_ttl ||
!["saturday", "sunday"].includes(
form.values.autostop_requirement_days_of_week || "",
)
}
fullWidth
inputProps={{ min: 1, max: 16, step: 1 }}
label="Weeks between required stops"
type="number"
/>
</Stack>
</FormSection>
<FormSection
title="Max Lifetime"
description="Define the maximum lifetime for workspaces created from this template."
deprecated
>
<Stack direction="column">
<Stack direction="row" alignItems="center">
<FormControlLabel
control={
<Checkbox
id="use_max_ttl"
size="small"
disabled={isSubmitting || !allowAdvancedScheduling}
onChange={handleToggleUseMaxTTL}
name="use_max_ttl"
checked={form.values.use_max_ttl}
/>
}
label={
<Stack spacing={0.5}>
<strong>
Use a max lifetime instead of a required autostop schedule.
</strong>
<span
css={{
fontSize: 12,
color: theme.palette.text.secondary,
}}
>
Use a maximum lifetime for workspaces created from this
template instead of an autostop requirement as configured
above.
</span>
</Stack>
}
fullWidth
inputProps={{ min: 1, max: 16, step: 1 }}
label="Weeks between required stops"
type="number"
/>
</Stack>
</FormSection>
)}
<TextField
{...getFieldHelpers(
"max_ttl_ms",
allowAdvancedScheduling ? (
<MaxTTLHelperText ttl={form.values.max_ttl_ms} />
) : (
<>
You need an enterprise license to use it{" "}
<Link href={docs("/enterprise")}>Learn more</Link>.
</>
),
)}
disabled={
isSubmitting ||
!form.values.use_max_ttl ||
!allowAdvancedScheduling
}
fullWidth
inputProps={{ min: 0, step: 1 }}
label="Max lifetime (hours)"
type="number"
/>
</Stack>
</FormSection>
<FormSection
title="Allow users scheduling"
@@ -15,6 +15,7 @@ import TemplateSchedulePage from "./TemplateSchedulePage";
const validFormValues: TemplateScheduleFormValues = {
default_ttl_ms: 1,
use_max_ttl: true,
max_ttl_ms: 2,
failure_ttl_ms: 7,
time_til_dormant_ms: 180,
@@ -73,8 +74,12 @@ const fillAndSubmitForm = async ({
}
if (max_ttl_ms) {
const useMaxTtlCheckbox = screen.getByRole("checkbox", {
name: /Use a max lifetime/i,
});
const maxTtlField = await screen.findByLabelText("Max lifetime (hours)");
await user.click(useMaxTtlCheckbox);
await user.clear(maxTtlField);
await user.type(maxTtlField, max_ttl_ms.toString());
}
@@ -24,8 +24,6 @@ const TemplateSchedulePage: FC = () => {
// This check can be removed when https://github.com/coder/coder/milestone/19
// is merged up
const allowWorkspaceActions = experiments.includes("workspace_actions");
const allowAutostopRequirement =
entitlements.features["template_autostop_requirement"].enabled;
const { clearLocal } = useLocalStorage();
const {
@@ -55,7 +53,6 @@ const TemplateSchedulePage: FC = () => {
<TemplateSchedulePageView
allowAdvancedScheduling={allowAdvancedScheduling}
allowWorkspaceActions={allowWorkspaceActions}
allowAutostopRequirement={allowAutostopRequirement}
isSubmitting={isSubmitting}
template={template}
submitError={submitError}
@@ -14,7 +14,6 @@ export interface TemplateSchedulePageViewProps {
>["initialTouched"];
allowAdvancedScheduling: boolean;
allowWorkspaceActions: boolean;
allowAutostopRequirement: boolean;
}
export const TemplateSchedulePageView: FC<TemplateSchedulePageViewProps> = ({
@@ -24,7 +23,6 @@ export const TemplateSchedulePageView: FC<TemplateSchedulePageViewProps> = ({
isSubmitting,
allowAdvancedScheduling,
allowWorkspaceActions,
allowAutostopRequirement,
submitError,
initialTouched,
}) => {
@@ -37,7 +35,6 @@ export const TemplateSchedulePageView: FC<TemplateSchedulePageViewProps> = ({
<TemplateScheduleForm
allowAdvancedScheduling={allowAdvancedScheduling}
allowWorkspaceActions={allowWorkspaceActions}
allowAutostopRequirement={allowAutostopRequirement}
initialTouched={initialTouched}
isSubmitting={isSubmitting}
template={template}
@@ -10,6 +10,7 @@ export interface TemplateScheduleFormValues
UpdateTemplateMeta,
"autostop_requirement" | "autostart_requirement"
> {
use_max_ttl: boolean;
autostart_requirement_days_of_week: TemplateAutostartRequirementDaysValue[];
autostop_requirement_days_of_week: TemplateAutostopRequirementDaysValue;
autostop_requirement_weeks: number;
+4 -4
View File
@@ -7,13 +7,13 @@ import ScheduleIcon from "@mui/icons-material/EditCalendarOutlined";
import SecurityIcon from "@mui/icons-material/LockOutlined";
import type { User } from "api/typesGenerated";
import { UserAvatar } from "components/UserAvatar/UserAvatar";
import { useDashboard } from "components/Dashboard/DashboardProvider";
import {
Sidebar as BaseSidebar,
SidebarHeader,
SidebarNavItem,
} from "components/Sidebar/Sidebar";
import { GitIcon } from "components/Icons/GitIcon";
import { useDashboard } from "components/Dashboard/DashboardProvider";
interface SidebarProps {
user: User;
@@ -21,8 +21,8 @@ interface SidebarProps {
export const Sidebar: FC<SidebarProps> = ({ user }) => {
const { entitlements } = useDashboard();
const allowAutostopRequirement =
entitlements.features.template_autostop_requirement.enabled;
const showSchedulePage =
entitlements.features.advanced_template_scheduling.enabled;
return (
<BaseSidebar>
@@ -39,7 +39,7 @@ export const Sidebar: FC<SidebarProps> = ({ user }) => {
<SidebarNavItem href="appearance" icon={AppearanceIcon}>
Appearance
</SidebarNavItem>
{allowAutostopRequirement && (
{showSchedulePage && (
<SidebarNavItem href="schedule" icon={ScheduleIcon}>
Schedule
</SidebarNavItem>
+3 -2
View File
@@ -445,9 +445,10 @@ export const MockTemplate: TypesGen.Template = {
},
description: "This is a test description.",
default_ttl_ms: 24 * 60 * 60 * 1000,
max_ttl_ms: 2 * 24 * 60 * 60 * 1000,
use_max_ttl: false,
max_ttl_ms: 0,
autostop_requirement: {
days_of_week: [],
days_of_week: ["sunday"],
weeks: 1,
},
autostart_requirement: {