Skip to content

Commit

Permalink
DEVPROD-7517: Add beta toggle for host uptime scheduling (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
sophstad authored Jun 28, 2024
1 parent e982220 commit 37dff21
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe("edit spawn host modal", () => {
sleepSchedule: {
dailyStartTime: "09:00",
dailyStopTime: "17:00",
isBetaTester: false,
permanentlyExempt: false,
shouldKeepOff: false,
timeZone: "America/New_York",
Expand Down Expand Up @@ -57,6 +58,7 @@ const formState = {
expiration: "Wed Oct 19 2022 08:56:42 GMT-0400 (Eastern Daylight Time)",
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: false,
sleepSchedule: {
enabledWeekdays: [false, true, true, true, true, false, false],
timeSelection: {
Expand Down
32 changes: 29 additions & 3 deletions apps/spruce/src/components/Spawn/getFormSchema.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import Badge from "@leafygreen-ui/badge";
import { Body } from "@leafygreen-ui/typography";
import { add } from "date-fns";
import widgets from "components/SpruceForm/Widgets";
import { StyledLink } from "components/styles";
import { hostUptimeDocumentationUrl } from "constants/externalResources";
import { prettifyTimeZone } from "constants/fieldMaps";
import { size } from "constants/tokens";
import { MyPublicKeysQuery } from "gql/generated/types";
import { isProduction } from "utils/environmentVariables";
import {
defaultStartDate,
defaultStopDate,
Expand Down Expand Up @@ -98,6 +99,10 @@ const getHostUptimeSchema = ({
details: {
type: "null" as "null",
},
isBetaTester: {
type: "boolean" as "boolean",
title: "",
},
...(isEditModal && {
temporarilyExemptUntil: {
type: "string" as "string",
Expand Down Expand Up @@ -175,6 +180,28 @@ const getHostUptimeSchema = ({
"ui:showLabel": false,
"ui:warnings": hostUptimeWarnings?.warnings,
},
isBetaTester: {
"ui:widget": widgets.ToggleWidget,
"ui:customLabel": (
<>
<Badge variant="blue">Beta</Badge> Enable host uptime scheduling
</>
),
"ui:descriptionNode": (
<>
Pausing hosts overnight reduces idle time outside of user-set hours.
Any schedule configured above will not take effect unless you opt in
to the beta.{" "}
<StyledLink
href={hostUptimeDocumentationUrl}
hideExternalIcon={false}
>
Learn more about host sleep schedules
</StyledLink>
.
</>
),
},
temporarilyExemptUntil: {
"ui:disableAfter": exemptionRange.disableAfter,
"ui:disableBefore": exemptionRange.disableBefore,
Expand Down Expand Up @@ -268,8 +295,7 @@ export const getExpirationDetailsSchema = ({
noExpiration: {
enum: [true],
},
...(!isProduction() &&
!permanentlyExempt && { hostUptime: hostUptime.schema }),
...(!permanentlyExempt && { hostUptime: hostUptime.schema }),
},
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ const data: Array<{ formData: FormState; mutationInput: SpawnHostInput }> = [
noExpiration: true,
hostUptime: {
useDefaultUptimeSchedule: true,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [false, false, true, true, true, true],
timeSelection: {
Expand Down Expand Up @@ -145,6 +146,7 @@ const data: Array<{ formData: FormState; mutationInput: SpawnHostInput }> = [
sleepSchedule: {
dailyStartTime: "08:00",
dailyStopTime: "20:00",
isBetaTester: true,
permanentlyExempt: false,
timeZone: "America/New_York",
shouldKeepOff: false,
Expand Down
45 changes: 45 additions & 0 deletions apps/spruce/src/components/Spawn/utils/hostUptime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ describe("validator", () => {
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [],
timeSelection: {
Expand All @@ -87,13 +88,40 @@ describe("validator", () => {
expect(f).toHaveBeenCalledTimes(0);
});

it("returns error even if beta testing is disabled in form", () => {
const f = vi.fn();
validator(false)(
{
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: false,
sleepSchedule: {
enabledWeekdays: [true, true, true, true, true, true, true],
timeSelection: {
startTime: "",
stopTime: "",
runContinuously: true,
},
},
},
noExpiration: true,
},
},
// @ts-expect-error
{ expirationDetails: { hostUptime: { details: { addError: f } } } },
);
expect(f).toHaveBeenCalledTimes(1);
});

it("returns error when the host has too many uptime hours", () => {
const f = vi.fn();
validator(false)(
{
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [true, true, true, true, true, true, true],
timeSelection: {
Expand All @@ -119,6 +147,7 @@ describe("validator", () => {
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [false, true, true, true, true, true, false],
timeSelection: {
Expand All @@ -144,6 +173,7 @@ describe("validator", () => {
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [],
timeSelection: {
Expand Down Expand Up @@ -187,6 +217,7 @@ describe("validator", () => {
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: true,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [],
timeSelection: {
Expand Down Expand Up @@ -217,6 +248,7 @@ describe("validator", () => {
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [],
timeSelection: {
Expand Down Expand Up @@ -247,6 +279,7 @@ describe("validator", () => {
expirationDetails: {
hostUptime: {
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [],
timeSelection: {
Expand Down Expand Up @@ -277,6 +310,7 @@ describe("getHostUptimeFromGql", () => {
const sched = {
dailyStartTime: "08:00",
dailyStopTime: "20:00",
isBetaTester: true,
permanentlyExempt: true,
shouldKeepOff: true,
temporarilyExemptUntil: null,
Expand All @@ -296,13 +330,15 @@ describe("getHostUptimeFromGql", () => {
},
},
temporarilyExemptUntil: "",
isBetaTester: true,
});
});

it("matches alternate schedule", () => {
const sched = {
dailyStartTime: "09:00",
dailyStopTime: "21:00",
isBetaTester: true,
permanentlyExempt: true,
shouldKeepOff: true,
temporarilyExemptUntil: new Date("2024-07-01"),
Expand All @@ -323,13 +359,15 @@ describe("getHostUptimeFromGql", () => {
},
temporarilyExemptUntil:
"Mon Jul 01 2024 00:00:00 GMT+0000 (Coordinated Universal Time)",
isBetaTester: true,
});
});

it("assigns continuous days", () => {
const sched = {
dailyStartTime: "",
dailyStopTime: "",
isBetaTester: true,
permanentlyExempt: true,
shouldKeepOff: true,
temporarilyExemptUntil: null,
Expand All @@ -349,6 +387,7 @@ describe("getHostUptimeFromGql", () => {
},
},
temporarilyExemptUntil: "",
isBetaTester: true,
});
});
});
Expand All @@ -359,6 +398,7 @@ describe("getSleepSchedule", () => {
getSleepSchedule(
{
useDefaultUptimeSchedule: true,
isBetaTester: false,
sleepSchedule: {
enabledWeekdays: [false, false, true, true, true, true, false],
timeSelection: {
Expand All @@ -375,6 +415,7 @@ describe("getSleepSchedule", () => {
).toStrictEqual({
dailyStartTime: "08:00",
dailyStopTime: "20:00",
isBetaTester: false,
permanentlyExempt: false,
shouldKeepOff: false,
timeZone: "America/New_York",
Expand All @@ -387,6 +428,7 @@ describe("getSleepSchedule", () => {
getSleepSchedule(
{
useDefaultUptimeSchedule: false,
isBetaTester: false,
sleepSchedule: {
enabledWeekdays: [false, false, true, true, true, true, false],
timeSelection: {
Expand All @@ -403,6 +445,7 @@ describe("getSleepSchedule", () => {
).toStrictEqual({
dailyStartTime: "",
dailyStopTime: "",
isBetaTester: false,
permanentlyExempt: false,
shouldKeepOff: false,
timeZone: "America/New_York",
Expand All @@ -415,6 +458,7 @@ describe("getSleepSchedule", () => {
getSleepSchedule(
{
useDefaultUptimeSchedule: false,
isBetaTester: true,
sleepSchedule: {
enabledWeekdays: [false, false, true, true, true, true, false],
timeSelection: {
Expand All @@ -431,6 +475,7 @@ describe("getSleepSchedule", () => {
).toStrictEqual({
dailyStartTime: "08:00",
dailyStopTime: "20:00",
isBetaTester: true,
permanentlyExempt: false,
shouldKeepOff: false,
timeZone: "America/New_York",
Expand Down
19 changes: 12 additions & 7 deletions apps/spruce/src/components/Spawn/utils/hostUptime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ValidateProps } from "components/SpruceForm";
import { days } from "constants/fieldMaps";
import { SleepScheduleInput } from "gql/generated/types";
import { Optional } from "types/utils";
import { isProduction } from "utils/environmentVariables";
import { FormState as EditFormState } from "../editHostModal";
import { FormState as SpawnFormState } from "../spawnHostModal";

Expand Down Expand Up @@ -39,6 +38,7 @@ export type HostUptime = {
};
};
details?: null;
isBetaTester: boolean;
temporarilyExemptUntil?: string;
};

Expand Down Expand Up @@ -110,6 +110,7 @@ export const getEnabledHoursCount = (

export const getSleepSchedule = (
{
isBetaTester,
sleepSchedule,
temporarilyExemptUntil,
useDefaultUptimeSchedule,
Expand All @@ -122,6 +123,7 @@ export const getSleepSchedule = (
...(temporarilyExemptUntil
? { temporarilyExemptUntil: new Date(temporarilyExemptUntil) }
: {}),
isBetaTester,
timeZone,
};
}
Expand All @@ -134,6 +136,7 @@ export const getSleepSchedule = (
return {
dailyStartTime: runContinuously ? "" : toTimeString(new Date(startTime)),
dailyStopTime: runContinuously ? "" : toTimeString(new Date(stopTime)),
isBetaTester,
permanentlyExempt: false,
timeZone,
shouldKeepOff: false,
Expand Down Expand Up @@ -167,10 +170,7 @@ const toTimeString = (date: Date): string =>
minute: "2-digit",
});

type RequiredSleepSchedule = Optional<
SleepScheduleInput,
"isBetaTester" | "timeZone"
>;
type RequiredSleepSchedule = Optional<SleepScheduleInput, "timeZone">;

export const defaultSleepSchedule: RequiredSleepSchedule = {
dailyStartTime: toTimeString(defaultStartDate),
Expand All @@ -186,13 +186,15 @@ export const getHostUptimeFromGql = (
const {
dailyStartTime,
dailyStopTime,
isBetaTester,
temporarilyExemptUntil,
wholeWeekdaysOff,
} = sleepSchedule;

return {
useDefaultUptimeSchedule: matchesDefaultUptimeSchedule(sleepSchedule),
temporarilyExemptUntil: temporarilyExemptUntil?.toString() ?? "",
isBetaTester: !!isBetaTester,
sleepSchedule: {
enabledWeekdays: new Array(7)
.fill(false)
Expand Down Expand Up @@ -265,6 +267,8 @@ export const validator = (permanentlyExempt: boolean) =>

if (
!isSleepScheduleActive({
// Set true because we to validate sleep schedule regardless of whether user is enabling it
isBetaTester: true,
isTemporarilyExempt: !!temporarilyExemptUntil,
noExpiration: !!noExpiration,
permanentlyExempt,
Expand Down Expand Up @@ -322,16 +326,17 @@ export const isNullSleepSchedule = (sleepSchedule: RequiredSleepSchedule) => {
};

export const isSleepScheduleActive = ({
isBetaTester,
isTemporarilyExempt,
noExpiration,
permanentlyExempt,
}: {
isBetaTester: boolean;
isTemporarilyExempt: boolean;
noExpiration: boolean;
permanentlyExempt: boolean;
}) => {
// TODO DEVPROD-7517: replace prod check with beta tester check when beta period begins
if (isProduction()) return false;
if (!isBetaTester) return false;
if (!noExpiration) return false;
if (isTemporarilyExempt) return false;
if (permanentlyExempt) return false;
Expand Down
Loading

0 comments on commit 37dff21

Please sign in to comment.