-
Notifications
You must be signed in to change notification settings - Fork 579
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: ui alert <= 30mins from deadline (#1825)
Summary: When a workspace build is <= 30 minutes from auto-scheduled shutdown, then an alert banner is displayed on the workspace page.
- Loading branch information
1 parent
ff542af
commit 8d7499f
Showing
5 changed files
with
204 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { Story } from "@storybook/react" | ||
import dayjs from "dayjs" | ||
import utc from "dayjs/plugin/utc" | ||
import React from "react" | ||
import * as Mocks from "../../testHelpers/entities" | ||
import { WorkspaceScheduleBanner, WorkspaceScheduleBannerProps } from "./WorkspaceScheduleBanner" | ||
|
||
dayjs.extend(utc) | ||
|
||
export default { | ||
title: "components/WorkspaceScheduleBanner", | ||
component: WorkspaceScheduleBanner, | ||
} | ||
|
||
const Template: Story<WorkspaceScheduleBannerProps> = (args) => <WorkspaceScheduleBanner {...args} /> | ||
|
||
export const Example = Template.bind({}) | ||
Example.args = { | ||
workspace: { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
deadline: dayjs().utc().format(), | ||
job: { | ||
...Mocks.MockProvisionerJob, | ||
status: "succeeded", | ||
}, | ||
transition: "start", | ||
}, | ||
ttl: 2 * 60 * 60 * 1000 * 1_000_000, // 2 hours | ||
}, | ||
} |
117 changes: 117 additions & 0 deletions
117
site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import dayjs from "dayjs" | ||
import utc from "dayjs/plugin/utc" | ||
import * as TypesGen from "../../api/typesGenerated" | ||
import * as Mocks from "../../testHelpers/entities" | ||
import { shouldDisplay } from "./WorkspaceScheduleBanner" | ||
|
||
dayjs.extend(utc) | ||
|
||
describe("WorkspaceScheduleBanner", () => { | ||
describe("shouldDisplay", () => { | ||
// Manual TTL case | ||
it("should not display if the build does not have a deadline", () => { | ||
// Given: a workspace with deadline of '"0001-01-01T00:00:00Z"' | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
deadline: "0001-01-01T00:00:00Z", | ||
transition: "start", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is false | ||
expect(shouldDisplay(workspace)).toBeFalsy() | ||
}) | ||
|
||
// Transition Checks | ||
it("should not display if the latest build is not transition=start", () => { | ||
// Given: a workspace with latest build as "stop" | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
transition: "stop", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is false | ||
expect(shouldDisplay(workspace)).toBeFalsy() | ||
}) | ||
|
||
// Provisioner Job Checks | ||
it("should not display if the latest build is canceling", () => { | ||
// Given: a workspace with latest build as "canceling" | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
job: Mocks.MockCancelingProvisionerJob, | ||
transition: "start", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is false | ||
expect(shouldDisplay(workspace)).toBeFalsy() | ||
}) | ||
it("should not display if the latest build is canceled", () => { | ||
// Given: a workspace with latest build as "canceled" | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
job: Mocks.MockCanceledProvisionerJob, | ||
transition: "start", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is false | ||
expect(shouldDisplay(workspace)).toBeFalsy() | ||
}) | ||
it("should not display if the latest build failed", () => { | ||
// Given: a workspace with latest build as "failed" | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
job: Mocks.MockFailedProvisionerJob, | ||
transition: "start", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is false | ||
expect(shouldDisplay(workspace)).toBeFalsy() | ||
}) | ||
|
||
// Deadline Checks | ||
it("should display if deadline is within 30 minutes", () => { | ||
// Given: a workspace with latest build as start and deadline in ~30 mins | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
deadline: dayjs().add(27, "minutes").utc().format(), | ||
job: Mocks.MockRunningProvisionerJob, | ||
transition: "start", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is true | ||
expect(shouldDisplay(workspace)).toBeTruthy() | ||
}) | ||
it("should not display if deadline is 45 minutes", () => { | ||
// Given: a workspace with latest build as start and deadline in 45 mins | ||
const workspace: TypesGen.Workspace = { | ||
...Mocks.MockWorkspace, | ||
latest_build: { | ||
...Mocks.MockWorkspaceBuild, | ||
deadline: dayjs().add(45, "minutes").utc().format(), | ||
transition: "start", | ||
}, | ||
} | ||
|
||
// Then: shouldDisplay is false | ||
expect(shouldDisplay(workspace)).toBeFalsy() | ||
}) | ||
}) | ||
}) |
48 changes: 48 additions & 0 deletions
48
site/src/components/WorkspaceScheduleBanner/WorkspaceScheduleBanner.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import Alert from "@material-ui/lab/Alert" | ||
import AlertTitle from "@material-ui/lab/AlertTitle" | ||
import dayjs from "dayjs" | ||
import isSameOrBefore from "dayjs/plugin/isSameOrBefore" | ||
import utc from "dayjs/plugin/utc" | ||
import React from "react" | ||
import * as TypesGen from "../../api/typesGenerated" | ||
|
||
dayjs.extend(utc) | ||
dayjs.extend(isSameOrBefore) | ||
|
||
export const Language = { | ||
bannerTitle: "Your workspace is scheduled to automatically shut down soon.", | ||
} | ||
|
||
export interface WorkspaceScheduleBannerProps { | ||
workspace: TypesGen.Workspace | ||
} | ||
|
||
export const shouldDisplay = (workspace: TypesGen.Workspace): boolean => { | ||
const transition = workspace.latest_build.transition | ||
const status = workspace.latest_build.job.status | ||
|
||
if (transition !== "start") { | ||
return false | ||
} else if (status === "canceled" || status === "canceling" || status === "failed") { | ||
return false | ||
} else { | ||
// a mannual shutdown has a deadline of '"0001-01-01T00:00:00Z"' | ||
// SEE: #1834 | ||
const deadline = dayjs(workspace.latest_build.deadline).utc() | ||
const hasDeadline = deadline.year() > 1 | ||
const thirtyMinutesFromNow = dayjs().add(30, "minutes").utc() | ||
return hasDeadline && deadline.isSameOrBefore(thirtyMinutesFromNow) | ||
} | ||
} | ||
|
||
export const WorkspaceScheduleBanner: React.FC<WorkspaceScheduleBannerProps> = ({ workspace }) => { | ||
if (!shouldDisplay(workspace)) { | ||
return null | ||
} else { | ||
return ( | ||
<Alert severity="warning"> | ||
<AlertTitle>{Language.bannerTitle}</AlertTitle> | ||
</Alert> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters