mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
refactor: Remove workspace schedule banner (#4932)
This commit is contained in:
@ -15,10 +15,6 @@ const Template: Story<WorkspaceProps> = (args) => <Workspace {...args} />
|
|||||||
|
|
||||||
export const Running = Template.bind({})
|
export const Running = Template.bind({})
|
||||||
Running.args = {
|
Running.args = {
|
||||||
bannerProps: {
|
|
||||||
isLoading: false,
|
|
||||||
onExtend: action("extend"),
|
|
||||||
},
|
|
||||||
scheduleProps: {
|
scheduleProps: {
|
||||||
onDeadlineMinus: () => {
|
onDeadlineMinus: () => {
|
||||||
// do nothing, this is just for storybook
|
// do nothing, this is just for storybook
|
||||||
@ -36,6 +32,8 @@ Running.args = {
|
|||||||
Mocks.MockTemplate,
|
Mocks.MockTemplate,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
maxDeadlineDecrease: 1000,
|
||||||
|
maxDeadlineIncrease: 1000,
|
||||||
},
|
},
|
||||||
workspace: Mocks.MockWorkspace,
|
workspace: Mocks.MockWorkspace,
|
||||||
handleStart: action("start"),
|
handleStart: action("start"),
|
||||||
|
@ -14,7 +14,6 @@ import { Resources } from "../Resources/Resources"
|
|||||||
import { Stack } from "../Stack/Stack"
|
import { Stack } from "../Stack/Stack"
|
||||||
import { WorkspaceActions } from "../WorkspaceActions/WorkspaceActions"
|
import { WorkspaceActions } from "../WorkspaceActions/WorkspaceActions"
|
||||||
import { WorkspaceDeletedBanner } from "../WorkspaceDeletedBanner/WorkspaceDeletedBanner"
|
import { WorkspaceDeletedBanner } from "../WorkspaceDeletedBanner/WorkspaceDeletedBanner"
|
||||||
import { WorkspaceScheduleBanner } from "../WorkspaceScheduleBanner/WorkspaceScheduleBanner"
|
|
||||||
import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceScheduleButton"
|
import { WorkspaceScheduleButton } from "../WorkspaceScheduleButton/WorkspaceScheduleButton"
|
||||||
import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats"
|
import { WorkspaceStats } from "../WorkspaceStats/WorkspaceStats"
|
||||||
import { AlertBanner } from "../AlertBanner/AlertBanner"
|
import { AlertBanner } from "../AlertBanner/AlertBanner"
|
||||||
@ -33,10 +32,6 @@ export enum WorkspaceErrors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface WorkspaceProps {
|
export interface WorkspaceProps {
|
||||||
bannerProps: {
|
|
||||||
isLoading?: boolean
|
|
||||||
onExtend: () => void
|
|
||||||
}
|
|
||||||
scheduleProps: {
|
scheduleProps: {
|
||||||
onDeadlinePlus: (hours: number) => void
|
onDeadlinePlus: (hours: number) => void
|
||||||
onDeadlineMinus: (hours: number) => void
|
onDeadlineMinus: (hours: number) => void
|
||||||
@ -66,7 +61,6 @@ export interface WorkspaceProps {
|
|||||||
* Workspace is the top-level component for viewing an individual workspace
|
* Workspace is the top-level component for viewing an individual workspace
|
||||||
*/
|
*/
|
||||||
export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
||||||
bannerProps,
|
|
||||||
scheduleProps,
|
scheduleProps,
|
||||||
handleStart,
|
handleStart,
|
||||||
handleStop,
|
handleStop,
|
||||||
@ -188,12 +182,6 @@ export const Workspace: FC<React.PropsWithChildren<WorkspaceProps>> = ({
|
|||||||
{cancellationError}
|
{cancellationError}
|
||||||
{workspaceRefreshWarning}
|
{workspaceRefreshWarning}
|
||||||
|
|
||||||
<WorkspaceScheduleBanner
|
|
||||||
isLoading={bannerProps.isLoading}
|
|
||||||
onExtend={bannerProps.onExtend}
|
|
||||||
workspace={workspace}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<WorkspaceDeletedBanner
|
<WorkspaceDeletedBanner
|
||||||
workspace={workspace}
|
workspace={workspace}
|
||||||
handleClick={() => navigate(`/templates`)}
|
handleClick={() => navigate(`/templates`)}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
import { action } from "@storybook/addon-actions"
|
|
||||||
import { Story } from "@storybook/react"
|
|
||||||
import dayjs from "dayjs"
|
|
||||||
import utc from "dayjs/plugin/utc"
|
|
||||||
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 = {
|
|
||||||
isLoading: false,
|
|
||||||
onExtend: action("extend"),
|
|
||||||
workspace: {
|
|
||||||
...Mocks.MockWorkspace,
|
|
||||||
|
|
||||||
latest_build: {
|
|
||||||
...Mocks.MockWorkspaceBuild,
|
|
||||||
deadline: dayjs().utc().format(),
|
|
||||||
job: {
|
|
||||||
...Mocks.MockProvisionerJob,
|
|
||||||
status: "succeeded",
|
|
||||||
},
|
|
||||||
transition: "start",
|
|
||||||
},
|
|
||||||
|
|
||||||
ttl_ms: 2 * 60 * 60 * 1000, // 2 hours
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Loading = Template.bind({})
|
|
||||||
Loading.args = {
|
|
||||||
...Example.args,
|
|
||||||
isLoading: true,
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
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 undefined.
|
|
||||||
const workspace: TypesGen.Workspace = {
|
|
||||||
...Mocks.MockWorkspace,
|
|
||||||
latest_build: {
|
|
||||||
...Mocks.MockWorkspaceBuild,
|
|
||||||
deadline: undefined,
|
|
||||||
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(),
|
|
||||||
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()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,56 +0,0 @@
|
|||||||
import Button from "@material-ui/core/Button"
|
|
||||||
import dayjs from "dayjs"
|
|
||||||
import isSameOrBefore from "dayjs/plugin/isSameOrBefore"
|
|
||||||
import utc from "dayjs/plugin/utc"
|
|
||||||
import { FC } from "react"
|
|
||||||
import * as TypesGen from "api/typesGenerated"
|
|
||||||
import { isWorkspaceOn } from "util/workspace"
|
|
||||||
import { AlertBanner } from "components/AlertBanner/AlertBanner"
|
|
||||||
import { useTranslation } from "react-i18next"
|
|
||||||
|
|
||||||
dayjs.extend(utc)
|
|
||||||
dayjs.extend(isSameOrBefore)
|
|
||||||
|
|
||||||
export interface WorkspaceScheduleBannerProps {
|
|
||||||
isLoading?: boolean
|
|
||||||
onExtend: () => void
|
|
||||||
workspace: TypesGen.Workspace
|
|
||||||
}
|
|
||||||
|
|
||||||
export const shouldDisplay = (workspace: TypesGen.Workspace): boolean => {
|
|
||||||
if (!isWorkspaceOn(workspace) || !workspace.latest_build.deadline) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const deadline = dayjs(workspace.latest_build.deadline).utc()
|
|
||||||
const thirtyMinutesFromNow = dayjs().add(30, "minutes").utc()
|
|
||||||
return deadline.isSameOrBefore(thirtyMinutesFromNow)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WorkspaceScheduleBanner: FC<
|
|
||||||
React.PropsWithChildren<WorkspaceScheduleBannerProps>
|
|
||||||
> = ({ isLoading, onExtend, workspace }) => {
|
|
||||||
const { t } = useTranslation("workspacePage")
|
|
||||||
|
|
||||||
if (!shouldDisplay(workspace)) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const ScheduleButton = (
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
disabled={isLoading}
|
|
||||||
onClick={onExtend}
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
{t("ctas.extendScheduleCta")}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AlertBanner
|
|
||||||
text={t("warningsAndErrors.workspaceShutdownWarning")}
|
|
||||||
actions={[ScheduleButton]}
|
|
||||||
severity="warning"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
@ -78,15 +78,6 @@ export const WorkspaceReadyPage = ({
|
|||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<Workspace
|
<Workspace
|
||||||
bannerProps={{
|
|
||||||
isLoading: bannerState.hasTag("loading"),
|
|
||||||
onExtend: () => {
|
|
||||||
bannerSend({
|
|
||||||
type: "INCREASE_DEADLINE",
|
|
||||||
hours: 4,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
scheduleProps={{
|
scheduleProps={{
|
||||||
onDeadlineMinus: (hours: number) => {
|
onDeadlineMinus: (hours: number) => {
|
||||||
bannerSend({
|
bannerSend({
|
||||||
|
Reference in New Issue
Block a user