From 3691b492a213c51a0298b5516c9510db1707a0e3 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 17 May 2023 19:36:55 +0000 Subject: [PATCH 1/8] created WorkspaceDeletion directory --- .../WorkspaceDeletion/DeletionBadge.tsx | 31 ++++++++ .../WorkspaceDeletion/DeletionBanner.tsx | 43 +++++++++++ .../WorkspaceDeletion/DeletionStat.tsx | 59 +++++++++++++++ .../WorkspaceDeletion/DeletionText.tsx | 34 +++++++++ .../src/components/WorkspaceDeletion/index.ts | 4 + .../WorkspaceDeletion/utils.test.ts | 58 ++++++++++++++ .../src/components/WorkspaceDeletion/utils.ts | 33 ++++++++ .../WorkspaceStats/WorkspaceStats.tsx | 2 + .../WorkspaceStatusBadge.tsx | 75 ++++++++----------- .../TemplateSchedulePage.tsx | 4 + .../WorkspacePage/WorkspacePage.test.tsx | 9 +++ .../pages/WorkspacesPage/WorkspacesPage.tsx | 9 --- .../WorkspacesPage/WorkspacesPageView.tsx | 39 ++++------ site/src/testHelpers/entities.ts | 2 +- site/src/utils/workspace.test.ts | 18 ----- site/src/utils/workspace.ts | 24 ------ 16 files changed, 324 insertions(+), 120 deletions(-) create mode 100644 site/src/components/WorkspaceDeletion/DeletionBadge.tsx create mode 100644 site/src/components/WorkspaceDeletion/DeletionBanner.tsx create mode 100644 site/src/components/WorkspaceDeletion/DeletionStat.tsx create mode 100644 site/src/components/WorkspaceDeletion/DeletionText.tsx create mode 100644 site/src/components/WorkspaceDeletion/index.ts create mode 100644 site/src/components/WorkspaceDeletion/utils.test.ts create mode 100644 site/src/components/WorkspaceDeletion/utils.ts diff --git a/site/src/components/WorkspaceDeletion/DeletionBadge.tsx b/site/src/components/WorkspaceDeletion/DeletionBadge.tsx new file mode 100644 index 0000000000000..e58765f983b0e --- /dev/null +++ b/site/src/components/WorkspaceDeletion/DeletionBadge.tsx @@ -0,0 +1,31 @@ +import { Workspace } from "api/typesGenerated" +import { displayImpendingDeletion } from "./utils" +import { useDashboard } from "components/Dashboard/DashboardProvider" +import { Pill } from "components/Pill/Pill" +import ErrorIcon from "@mui/icons-material/ErrorOutline" + +export const DeletionBadge = ({ + workspace, +}: { + workspace: Workspace +}): JSX.Element | null => { + const { entitlements, experiments } = useDashboard() + const allowAdvancedScheduling = + entitlements.features["advanced_template_scheduling"].enabled + // This check can be removed when https://github.com/coder/coder/milestone/19 + // is merged up + const allowWorkspaceActions = experiments.includes("workspace_actions") + // return null + + if ( + !displayImpendingDeletion( + workspace, + allowAdvancedScheduling, + allowWorkspaceActions, + ) + ) { + return null + } + + return } text="Impending deletion" type="error" /> +} diff --git a/site/src/components/WorkspaceDeletion/DeletionBanner.tsx b/site/src/components/WorkspaceDeletion/DeletionBanner.tsx new file mode 100644 index 0000000000000..b5153e716246a --- /dev/null +++ b/site/src/components/WorkspaceDeletion/DeletionBanner.tsx @@ -0,0 +1,43 @@ +import { Workspace } from "api/typesGenerated" +import { displayImpendingDeletion } from "./utils" +import { useDashboard } from "components/Dashboard/DashboardProvider" +import { Maybe } from "components/Conditionals/Maybe" +import { AlertBanner } from "components/AlertBanner/AlertBanner" + +export const DeletionBanner = ({ + workspace, + onDismiss, + displayImpendingDeletionBanner, +}: { + workspace?: Workspace + onDismiss: () => void + displayImpendingDeletionBanner: boolean +}): JSX.Element | null => { + const { entitlements, experiments } = useDashboard() + const allowAdvancedScheduling = + entitlements.features["advanced_template_scheduling"].enabled + // This check can be removed when https://github.com/coder/coder/milestone/19 + // is merged up + const allowWorkspaceActions = experiments.includes("workspace_actions") + + return ( + + + + ) +} diff --git a/site/src/components/WorkspaceDeletion/DeletionStat.tsx b/site/src/components/WorkspaceDeletion/DeletionStat.tsx new file mode 100644 index 0000000000000..16153bb210ff7 --- /dev/null +++ b/site/src/components/WorkspaceDeletion/DeletionStat.tsx @@ -0,0 +1,59 @@ +import { Maybe } from "components/Conditionals/Maybe" +import { StatsItem } from "components/Stats/Stats" +import Link from "@mui/material/Link" +import { Link as RouterLink } from "react-router-dom" +import styled from "@emotion/styled" +import { Workspace } from "api/typesGenerated" +import { displayImpendingDeletion } from "./utils" +import { useDashboard } from "components/Dashboard/DashboardProvider" + +export const DeletionStat = ({ + workspace, +}: { + workspace: Workspace +}): JSX.Element => { + const { entitlements, experiments } = useDashboard() + const allowAdvancedScheduling = + entitlements.features["advanced_template_scheduling"].enabled + // This check can be removed when https://github.com/coder/coder/milestone/19 + // is merged up + const allowWorkspaceActions = experiments.includes("workspace_actions") + + return ( + + + {/* We check for string existence in the conditional */} + {new Date(workspace.deleting_at as string).toLocaleString()} + + } + /> + + ) +} + +const StyledStatsItem = styled(StatsItem)(() => ({ + "&.containerClass": { + flexDirection: "column", + gap: 0, + padding: 0, + + "& > span:first-of-type": { + fontSize: 12, + fontWeight: 500, + }, + }, +})) diff --git a/site/src/components/WorkspaceDeletion/DeletionText.tsx b/site/src/components/WorkspaceDeletion/DeletionText.tsx new file mode 100644 index 0000000000000..576ac15fa114c --- /dev/null +++ b/site/src/components/WorkspaceDeletion/DeletionText.tsx @@ -0,0 +1,34 @@ +import { Workspace } from "api/typesGenerated" +import { displayImpendingDeletion } from "./utils" +import { useDashboard } from "components/Dashboard/DashboardProvider" +import styled from "@emotion/styled" +import { Theme as MaterialUITheme } from "@mui/material/styles" + +export const DeletionText = ({ + workspace, +}: { + workspace: Workspace +}): JSX.Element | null => { + const { entitlements, experiments } = useDashboard() + const allowAdvancedScheduling = + entitlements.features["advanced_template_scheduling"].enabled + // This check can be removed when https://github.com/coder/coder/milestone/19 + // is merged up + const allowWorkspaceActions = experiments.includes("workspace_actions") + + if ( + !displayImpendingDeletion( + workspace, + allowAdvancedScheduling, + allowWorkspaceActions, + ) + ) { + return null + } + return Impending deletion +} + +const StyledSpan = styled.span<{ theme?: MaterialUITheme }>` + color: ${(props) => props.theme.palette.warning.light}; + font-weight: 600; +` diff --git a/site/src/components/WorkspaceDeletion/index.ts b/site/src/components/WorkspaceDeletion/index.ts new file mode 100644 index 0000000000000..c0a77f1b4524e --- /dev/null +++ b/site/src/components/WorkspaceDeletion/index.ts @@ -0,0 +1,4 @@ +export * from "./DeletionStat" +export * from "./DeletionBadge" +export * from "./DeletionText" +export * from "./DeletionBanner" diff --git a/site/src/components/WorkspaceDeletion/utils.test.ts b/site/src/components/WorkspaceDeletion/utils.test.ts new file mode 100644 index 0000000000000..7bc807f9ccaa1 --- /dev/null +++ b/site/src/components/WorkspaceDeletion/utils.test.ts @@ -0,0 +1,58 @@ +import * as TypesGen from "api/typesGenerated" +import * as Mocks from "testHelpers/entities" +import { displayImpendingDeletion } from "./utils" + +describe("util > workspace deletion", () => { + describe("displayImpendingDeletion", () => { + const today = new Date() + it.each<[string, boolean, boolean, boolean]>([ + [ + new Date(new Date().setDate(today.getDate() + 15)).toISOString(), + true, + true, + false, + ], // today + 15 days out + [ + new Date(new Date().setDate(today.getDate() + 14)).toISOString(), + true, + true, + true, + ], // today + 14 + [ + new Date(new Date().setDate(today.getDate() + 13)).toISOString(), + true, + true, + true, + ], // today + 13 + [ + new Date(new Date().setDate(today.getDate() + 1)).toISOString(), + true, + true, + true, + ], // today + 1 + [new Date().toISOString(), true, true, true], // today + 0 + [new Date().toISOString(), false, true, false], // Advanced Scheduling off + [new Date().toISOString(), true, false, false], // Workspace Actions off + ])( + `deleting_at=%p, allowAdvancedScheduling=%p, AllowWorkspaceActions=%p, shouldDisplay=%p`, + ( + deleting_at, + allowAdvancedScheduling, + allowWorkspaceActions, + shouldDisplay, + ) => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, + deleting_at, + } + expect( + displayImpendingDeletion( + workspace, + allowAdvancedScheduling, + allowWorkspaceActions, + ), + ).toBe(shouldDisplay) + }, + ) + }) +}) diff --git a/site/src/components/WorkspaceDeletion/utils.ts b/site/src/components/WorkspaceDeletion/utils.ts new file mode 100644 index 0000000000000..745bd48ad8941 --- /dev/null +++ b/site/src/components/WorkspaceDeletion/utils.ts @@ -0,0 +1,33 @@ +import { Workspace } from "api/typesGenerated" + +// This const dictates how far out we alert the user that a workspace +// has an impending deletion (due to template.InactivityTTL being set) +const IMPENDING_DELETION_DISPLAY_THRESHOLD = 14 // 14 days + +/** + * Returns a boolean indicating if an impending deletion indicator should be + * displayed in the UI. Impending deletions are configured by setting the + * Template.InactivityTTL + * @param {TypesGen.Workspace} workspace + * @returns {boolean} + */ +export const displayImpendingDeletion = ( + workspace: Workspace, + allowAdvancedScheduling: boolean, + allowWorkspaceActions: boolean, +) => { + const today = new Date() + if ( + !workspace.deleting_at || + !allowAdvancedScheduling || + !allowWorkspaceActions + ) { + return false + } + return ( + new Date(workspace.deleting_at) <= + new Date( + today.setDate(today.getDate() + IMPENDING_DELETION_DISPLAY_THRESHOLD), + ) + ) +} diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 26eb80d7ba364..212a53f6aa885 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -20,6 +20,7 @@ import Popover from "@mui/material/Popover" import TextField from "@mui/material/TextField" import Button from "@mui/material/Button" import { WorkspaceStatusText } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge" +import { DeletionStat } from "components/WorkspaceDeletion" const Language = { workspaceDetails: "Workspace Details", @@ -74,6 +75,7 @@ export const WorkspaceStats: FC = ({ label="Status" value={} /> + { return @@ -93,41 +93,21 @@ export type WorkspaceStatusBadgeProps = { className?: string } -const ImpendingDeletionBadge: FC> = ({ - className, -}) => { - const { entitlements, experiments } = useDashboard() - const allowAdvancedScheduling = - entitlements.features["advanced_template_scheduling"].enabled - // This check can be removed when https://github.com/coder/coder/milestone/19 - // is merged up - const allowWorkspaceActions = experiments.includes("workspace_actions") - - if (!allowAdvancedScheduling || !allowWorkspaceActions) { - return null - } - return ( - } - text="Impending deletion" - type="error" - /> - ) -} - export const WorkspaceStatusBadge: FC< PropsWithChildren > = ({ workspace, className }) => { - // The ImpendingDeletionBadge component itself checks to see if the - // Advanced Scheduling feature is turned on and if the - // Workspace Actions flag is turned on. - if (displayImpendingDeletion(workspace)) { - return - } - const { text, icon, type } = getStatus(workspace.latest_build.status) - return + return ( + + {/* determines its own visibility */} + + + + + + + + ) } export const WorkspaceStatusText: FC< @@ -135,17 +115,26 @@ export const WorkspaceStatusText: FC< > = ({ workspace, className }) => { const styles = useStyles() const { text, type } = getStatus(workspace.latest_build.status) + return ( - - {text} - + + {/* determines its own visibility */} + + + + + + {text} + + + ) } diff --git a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx index af5424ab8cbf4..8bc0d9256fb18 100644 --- a/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx +++ b/site/src/pages/TemplateSettingsPage/TemplateSchedulePage/TemplateSchedulePage.tsx @@ -9,6 +9,7 @@ import { useNavigate, useParams } from "react-router-dom" import { pageTitle } from "utils/page" import { useTemplateSettingsContext } from "../TemplateSettingsLayout" import { TemplateSchedulePageView } from "./TemplateSchedulePageView" +import { useLocalStorage } from "hooks" const TemplateSchedulePage: FC = () => { const { template: templateName } = useParams() as { template: string } @@ -20,6 +21,7 @@ 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 { clearLocal } = useLocalStorage() const { mutate: updateTemplate, @@ -30,6 +32,8 @@ const TemplateSchedulePage: FC = () => { { onSuccess: () => { displaySuccess("Template updated successfully") + // clear browser-stored list of workspaces impending deletion + clearLocal("dismissedWorkspaceList") }, }, ) diff --git a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx index 315bd7ec898ad..ad818cb501944 100644 --- a/site/src/pages/WorkspacePage/WorkspacePage.test.tsx +++ b/site/src/pages/WorkspacePage/WorkspacePage.test.tsx @@ -18,9 +18,11 @@ import { MockCanceledWorkspace, MockDeletingWorkspace, MockDeletedWorkspace, + MockWorkspaceWithDeletion, MockBuilds, MockTemplateVersion3, MockUser, + MockEntitlementsWithScheduling, } from "testHelpers/entities" import * as api from "../../api/api" import { Workspace } from "../../api/typesGenerated" @@ -373,6 +375,13 @@ describe("WorkspacePage", () => { ) }) + it("shows the Impending deletion status when the workspace is impending deletion", async () => { + jest + .spyOn(api, "getEntitlements") + .mockResolvedValue(MockEntitlementsWithScheduling) + await testStatus(MockWorkspaceWithDeletion, "Impending deletion") + }) + it("shows the timeline build", async () => { await renderWorkspacePage() const table = await screen.findByTestId("builds-table") diff --git a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx index f69baa7d8fc20..cdd0753f26a32 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPage.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPage.tsx @@ -6,17 +6,10 @@ import { workspaceFilterQuery } from "utils/filters" import { pageTitle } from "utils/page" import { useWorkspacesData, useWorkspaceUpdate } from "./data" import { WorkspacesPageView } from "./WorkspacesPageView" -import { useDashboard } from "components/Dashboard/DashboardProvider" const WorkspacesPage: FC = () => { const filter = useFilter(workspaceFilterQuery.me) const pagination = usePagination() - const { entitlements, experiments } = useDashboard() - const allowAdvancedScheduling = - entitlements.features["advanced_template_scheduling"].enabled - // This check can be removed when https://github.com/coder/coder/milestone/19 - // is merged up - const allowWorkspaceActions = experiments.includes("workspace_actions") const { data, error, queryKey } = useWorkspacesData({ ...pagination, @@ -42,8 +35,6 @@ const WorkspacesPage: FC = () => { onUpdateWorkspace={(workspace) => { updateWorkspace.mutate(workspace) }} - allowAdvancedScheduling={allowAdvancedScheduling} - allowWorkspaceActions={allowWorkspaceActions} /> ) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index 330457119e670..daccbe85cce46 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -18,6 +18,7 @@ import { WorkspacesTable } from "components/WorkspacesTable/WorkspacesTable" import { workspaceFilterQuery } from "utils/filters" import { useLocalStorage } from "hooks" import difference from "lodash/difference" +import { DeletionBanner } from "components/WorkspaceDeletion" export const Language = { pageTitle: "Workspaces", @@ -51,8 +52,8 @@ export interface WorkspacesPageViewProps { onPageChange: (page: number) => void onFilter: (query: string) => void onUpdateWorkspace: (workspace: Workspace) => void - allowAdvancedScheduling: boolean - allowWorkspaceActions: boolean + // allowAdvancedScheduling: boolean + // allowWorkspaceActions: boolean } export const WorkspacesPageView: FC< @@ -67,8 +68,6 @@ export const WorkspacesPageView: FC< onFilter, onPageChange, onUpdateWorkspace, - allowAdvancedScheduling, - allowWorkspaceActions, }) => { const { saveLocal, getLocal } = useLocalStorage() @@ -97,14 +96,6 @@ export const WorkspacesPageView: FC< return diff && diff.length > 0 } - const displayImpendingDeletionBanner = - (allowAdvancedScheduling && - allowWorkspaceActions && - workspaceIdsWithImpendingDeletions && - workspaceIdsWithImpendingDeletions.length > 0 && - isNewWorkspacesImpendingDeletion()) ?? - false - return ( @@ -135,19 +126,17 @@ export const WorkspacesPageView: FC< } /> - - - saveLocal( - "dismissedWorkspaceList", - JSON.stringify(workspaceIdsWithImpendingDeletions), - ) - } - dismissible - text="You have workspaces that will be deleted soon." - /> - + {/* determines its own visibility */} + workspace.deleting_at)} + displayImpendingDeletionBanner={isNewWorkspacesImpendingDeletion()} + onDismiss={() => + saveLocal( + "dismissedWorkspaceList", + JSON.stringify(workspaceIdsWithImpendingDeletions), + ) + } + /> workspace", () => { expect(displayed).toEqual(workspace.template_display_name) }) }) - - describe("displayImpendingDeletion", () => { - const today = new Date() - it.each<[string, boolean]>([ - [new Date(new Date().setDate(today.getDate() + 15)).toISOString(), false], // today + 15 days out - [new Date(new Date().setDate(today.getDate() + 14)).toISOString(), true], // today + 14 - [new Date(new Date().setDate(today.getDate() + 13)).toISOString(), true], // today + 13 - [new Date(new Date().setDate(today.getDate() + 1)).toISOString(), true], // today + 1 - [new Date().toISOString(), true], // today + 0 - ])(`deleting_at=%p, isWorkspaceOn=%p`, (deleting_at, shouldDisplay) => { - const workspace: TypesGen.Workspace = { - ...Mocks.MockWorkspace, - deleting_at, - } - expect(displayImpendingDeletion(workspace)).toBe(shouldDisplay) - }) - }) }) diff --git a/site/src/utils/workspace.ts b/site/src/utils/workspace.ts index 44bd1e6c9c7c3..d180222e0a83d 100644 --- a/site/src/utils/workspace.ts +++ b/site/src/utils/workspace.ts @@ -185,27 +185,3 @@ export const getDisplayWorkspaceTemplateName = ( ? workspace.template_display_name : workspace.template_name } - -// This const dictates how far out we alert the user that a workspace -// has an impending deletion (due to template.InactivityTTL being set) -const IMPENDING_DELETION_DISPLAY_THRESHOLD = 14 // 14 days - -/** - * Returns a boolean indicating if an impending deletion indicator should be - * displayed in the UI. Impending deletions are configured by setting the - * Template.InactivityTTL - * @param {TypesGen.Workspace} workspace - * @returns {boolean} - */ -export const displayImpendingDeletion = (workspace: TypesGen.Workspace) => { - const today = new Date() - if (!workspace.deleting_at) { - return false - } - return ( - new Date(workspace.deleting_at) <= - new Date( - today.setDate(today.getDate() + IMPENDING_DELETION_DISPLAY_THRESHOLD), - ) - ) -} From 92d036573e333d539f27258fe0cbb5ae32e1e4be Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 17 May 2023 19:44:56 +0000 Subject: [PATCH 2/8] remove commented code --- site/src/pages/WorkspacesPage/WorkspacesPageView.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index daccbe85cce46..0232900e6d2d6 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -52,8 +52,6 @@ export interface WorkspacesPageViewProps { onPageChange: (page: number) => void onFilter: (query: string) => void onUpdateWorkspace: (workspace: Workspace) => void - // allowAdvancedScheduling: boolean - // allowWorkspaceActions: boolean } export const WorkspacesPageView: FC< @@ -126,7 +124,6 @@ export const WorkspacesPageView: FC< } /> - {/* determines its own visibility */} workspace.deleting_at)} displayImpendingDeletionBanner={isNewWorkspacesImpendingDeletion()} From 819983c282105fd5f8a4ea7486fff708ff0537e2 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 17 May 2023 21:00:23 +0000 Subject: [PATCH 3/8] attempting to fix workspace stories --- .../Workspace/Workspace.stories.tsx | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/site/src/components/Workspace/Workspace.stories.tsx b/site/src/components/Workspace/Workspace.stories.tsx index fd36e6997e4da..3fc82e25a921c 100644 --- a/site/src/components/Workspace/Workspace.stories.tsx +++ b/site/src/components/Workspace/Workspace.stories.tsx @@ -2,12 +2,12 @@ import { action } from "@storybook/addon-actions" import { Story } from "@storybook/react" import { WatchAgentMetadataContext } from "components/Resources/AgentMetadata" import { ProvisionerJobLog } from "api/typesGenerated" -import * as Mocks from "../../testHelpers/entities" +import * as Mocks from "testHelpers/entities" import { Workspace, WorkspaceErrors, WorkspaceProps } from "./Workspace" import { withReactContext } from "storybook-react-context" import EventSource from "eventsourcemock" import { ProxyContext, getPreferredProxy } from "contexts/ProxyContext" -import { MockProxyLatencies } from "../../testHelpers/entities" +import { DashboardProviderContext } from "components/Dashboard/DashboardProvider" export default { title: "components/Workspace", @@ -24,21 +24,37 @@ export default { ], } +const MockedAppearance = { + config: Mocks.MockAppearance, + preview: false, + setPreview: () => {}, + save: () => {}, +} + const Template: Story = (args) => ( - { - return - }, + buildInfo: Mocks.MockBuildInfo, + entitlements: Mocks.MockEntitlementsWithScheduling, + experiments: Mocks.MockExperiments, + appearance: MockedAppearance, }} > - - + { + return + }, + }} + > + + + ) export const Running = Template.bind({}) From 8f728bb737f80e9226e877bd87eb57e33b97f3d8 Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 17 May 2023 21:07:21 +0000 Subject: [PATCH 4/8] fix lint --- site/src/components/Workspace/Workspace.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/src/components/Workspace/Workspace.stories.tsx b/site/src/components/Workspace/Workspace.stories.tsx index 3fc82e25a921c..8ea8504a9e18d 100644 --- a/site/src/components/Workspace/Workspace.stories.tsx +++ b/site/src/components/Workspace/Workspace.stories.tsx @@ -27,8 +27,8 @@ export default { const MockedAppearance = { config: Mocks.MockAppearance, preview: false, - setPreview: () => {}, - save: () => {}, + setPreview: () => null, + save: () => null, } const Template: Story = (args) => ( From e987c70928a022ed7003c8ac7f22f38c1005836d Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 17 May 2023 21:34:56 +0000 Subject: [PATCH 5/8] fix the rest of the stories --- .../WorkspaceStats/WorkspaceStats.stories.tsx | 27 +++++++++++++++++-- .../WorkspaceStatusBadge.stories.tsx | 23 +++++++++++++++- .../CreateWorkspacePageView.stories.tsx | 25 +++++++++++++++-- 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.stories.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.stories.tsx index 2dc0f331d48ec..96fe4d636fee8 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.stories.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.stories.tsx @@ -1,17 +1,40 @@ import { Story } from "@storybook/react" -import { MockWorkspace } from "testHelpers/entities" +import { + MockWorkspace, + MockAppearance, + MockBuildInfo, + MockEntitlementsWithScheduling, + MockExperiments, +} from "testHelpers/entities" import { WorkspaceStats, WorkspaceStatsProps, } from "../WorkspaceStats/WorkspaceStats" +import { DashboardProviderContext } from "components/Dashboard/DashboardProvider" export default { title: "components/WorkspaceStats", component: WorkspaceStats, } +const MockedAppearance = { + config: MockAppearance, + preview: false, + setPreview: () => null, + save: () => null, +} + const Template: Story = (args) => ( - + + + ) export const Example = Template.bind({}) diff --git a/site/src/components/WorkspaceStatusBadge/WorkspaceStatusBadge.stories.tsx b/site/src/components/WorkspaceStatusBadge/WorkspaceStatusBadge.stories.tsx index b98b10f437ffb..3e7eefc942326 100644 --- a/site/src/components/WorkspaceStatusBadge/WorkspaceStatusBadge.stories.tsx +++ b/site/src/components/WorkspaceStatusBadge/WorkspaceStatusBadge.stories.tsx @@ -10,19 +10,40 @@ import { MockStoppedWorkspace, MockStoppingWorkspace, MockWorkspace, + MockBuildInfo, + MockEntitlementsWithScheduling, + MockExperiments, + MockAppearance, } from "testHelpers/entities" import { WorkspaceStatusBadge, WorkspaceStatusBadgeProps, } from "./WorkspaceStatusBadge" +import { DashboardProviderContext } from "components/Dashboard/DashboardProvider" export default { title: "components/WorkspaceStatusBadge", component: WorkspaceStatusBadge, } +const MockedAppearance = { + config: MockAppearance, + preview: false, + setPreview: () => null, + save: () => null, +} + const Template: Story = (args) => ( - + + + ) export const Running = Template.bind({}) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index c548580f35797..d2d2130e1c8e7 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -7,20 +7,41 @@ import { MockTemplateVersionParameter1, MockTemplateVersionParameter2, MockTemplateVersionParameter3, -} from "../../testHelpers/entities" + MockBuildInfo, + MockEntitlementsWithScheduling, + MockExperiments, + MockAppearance, +} from "testHelpers/entities" import { CreateWorkspaceErrors, CreateWorkspacePageView, CreateWorkspacePageViewProps, } from "./CreateWorkspacePageView" +import { DashboardProviderContext } from "components/Dashboard/DashboardProvider" export default { title: "pages/CreateWorkspacePageView", component: CreateWorkspacePageView, } as ComponentMeta +const MockedAppearance = { + config: MockAppearance, + preview: false, + setPreview: () => null, + save: () => null, +} + const Template: Story = (args) => ( - + + + ) export const NoParameters = Template.bind({}) From 8322b633ee07b7e98038102d9323e575f4e9cdcb Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Wed, 17 May 2023 21:53:11 +0000 Subject: [PATCH 6/8] fix right stories --- .../CreateWorkspacePageView.stories.tsx | 25 ++------------- .../WorkspacesPageView.stories.tsx | 31 ++++++++++++++++--- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx index d2d2130e1c8e7..c548580f35797 100644 --- a/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx +++ b/site/src/pages/CreateWorkspacePage/CreateWorkspacePageView.stories.tsx @@ -7,41 +7,20 @@ import { MockTemplateVersionParameter1, MockTemplateVersionParameter2, MockTemplateVersionParameter3, - MockBuildInfo, - MockEntitlementsWithScheduling, - MockExperiments, - MockAppearance, -} from "testHelpers/entities" +} from "../../testHelpers/entities" import { CreateWorkspaceErrors, CreateWorkspacePageView, CreateWorkspacePageViewProps, } from "./CreateWorkspacePageView" -import { DashboardProviderContext } from "components/Dashboard/DashboardProvider" export default { title: "pages/CreateWorkspacePageView", component: CreateWorkspacePageView, } as ComponentMeta -const MockedAppearance = { - config: MockAppearance, - preview: false, - setPreview: () => null, - save: () => null, -} - const Template: Story = (args) => ( - - - + ) export const NoParameters = Template.bind({}) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx index 3282bc8eb067c..8308f5343031c 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.stories.tsx @@ -6,13 +6,20 @@ import { Workspace, WorkspaceStatus, WorkspaceStatuses, -} from "../../api/typesGenerated" -import { MockWorkspace } from "../../testHelpers/entities" -import { workspaceFilterQuery } from "../../utils/filters" +} from "api/typesGenerated" +import { + MockWorkspace, + MockAppearance, + MockBuildInfo, + MockEntitlementsWithScheduling, + MockExperiments, +} from "testHelpers/entities" +import { workspaceFilterQuery } from "utils/filters" import { WorkspacesPageView, WorkspacesPageViewProps, } from "./WorkspacesPageView" +import { DashboardProviderContext } from "components/Dashboard/DashboardProvider" const createWorkspace = ( status: WorkspaceStatus, @@ -55,6 +62,13 @@ const allWorkspaces = [ ...Object.values(additionalWorkspaces), ] +const MockedAppearance = { + config: MockAppearance, + preview: false, + setPreview: () => null, + save: () => null, +} + export default { title: "pages/WorkspacesPageView", component: WorkspacesPageView, @@ -64,7 +78,16 @@ export default { } as ComponentMeta const Template: Story = (args) => ( - + + + ) export const AllStates = Template.bind({}) From 5aec820ae5b86ac09370cf59bb507416011a61fd Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Thu, 18 May 2023 17:35:50 +0000 Subject: [PATCH 7/8] PR comments --- ...onBadge.tsx => ImpendingDeletionBadge.tsx} | 2 +- ...Banner.tsx => ImpendingDeletionBanner.tsx} | 2 +- ...tionStat.tsx => ImpendingDeletionStat.tsx} | 2 +- ...tionText.tsx => ImpendingDeletionText.tsx} | 2 +- .../src/components/WorkspaceDeletion/index.ts | 8 +- .../WorkspaceDeletion/utils.test.ts | 102 +++++++++--------- .../WorkspaceStats/WorkspaceStats.tsx | 4 +- .../WorkspaceStatusBadge.tsx | 17 +-- .../WorkspacesPage/WorkspacesPageView.tsx | 4 +- 9 files changed, 72 insertions(+), 71 deletions(-) rename site/src/components/WorkspaceDeletion/{DeletionBadge.tsx => ImpendingDeletionBadge.tsx} (95%) rename site/src/components/WorkspaceDeletion/{DeletionBanner.tsx => ImpendingDeletionBanner.tsx} (96%) rename site/src/components/WorkspaceDeletion/{DeletionStat.tsx => ImpendingDeletionStat.tsx} (97%) rename site/src/components/WorkspaceDeletion/{DeletionText.tsx => ImpendingDeletionText.tsx} (96%) diff --git a/site/src/components/WorkspaceDeletion/DeletionBadge.tsx b/site/src/components/WorkspaceDeletion/ImpendingDeletionBadge.tsx similarity index 95% rename from site/src/components/WorkspaceDeletion/DeletionBadge.tsx rename to site/src/components/WorkspaceDeletion/ImpendingDeletionBadge.tsx index e58765f983b0e..eb27db82a3e2e 100644 --- a/site/src/components/WorkspaceDeletion/DeletionBadge.tsx +++ b/site/src/components/WorkspaceDeletion/ImpendingDeletionBadge.tsx @@ -4,7 +4,7 @@ import { useDashboard } from "components/Dashboard/DashboardProvider" import { Pill } from "components/Pill/Pill" import ErrorIcon from "@mui/icons-material/ErrorOutline" -export const DeletionBadge = ({ +export const ImpendingDeletionBadge = ({ workspace, }: { workspace: Workspace diff --git a/site/src/components/WorkspaceDeletion/DeletionBanner.tsx b/site/src/components/WorkspaceDeletion/ImpendingDeletionBanner.tsx similarity index 96% rename from site/src/components/WorkspaceDeletion/DeletionBanner.tsx rename to site/src/components/WorkspaceDeletion/ImpendingDeletionBanner.tsx index b5153e716246a..58abb42a38608 100644 --- a/site/src/components/WorkspaceDeletion/DeletionBanner.tsx +++ b/site/src/components/WorkspaceDeletion/ImpendingDeletionBanner.tsx @@ -4,7 +4,7 @@ import { useDashboard } from "components/Dashboard/DashboardProvider" import { Maybe } from "components/Conditionals/Maybe" import { AlertBanner } from "components/AlertBanner/AlertBanner" -export const DeletionBanner = ({ +export const ImpendingDeletionBanner = ({ workspace, onDismiss, displayImpendingDeletionBanner, diff --git a/site/src/components/WorkspaceDeletion/DeletionStat.tsx b/site/src/components/WorkspaceDeletion/ImpendingDeletionStat.tsx similarity index 97% rename from site/src/components/WorkspaceDeletion/DeletionStat.tsx rename to site/src/components/WorkspaceDeletion/ImpendingDeletionStat.tsx index 16153bb210ff7..aca1e21b22a97 100644 --- a/site/src/components/WorkspaceDeletion/DeletionStat.tsx +++ b/site/src/components/WorkspaceDeletion/ImpendingDeletionStat.tsx @@ -7,7 +7,7 @@ import { Workspace } from "api/typesGenerated" import { displayImpendingDeletion } from "./utils" import { useDashboard } from "components/Dashboard/DashboardProvider" -export const DeletionStat = ({ +export const ImpendingDeletionStat = ({ workspace, }: { workspace: Workspace diff --git a/site/src/components/WorkspaceDeletion/DeletionText.tsx b/site/src/components/WorkspaceDeletion/ImpendingDeletionText.tsx similarity index 96% rename from site/src/components/WorkspaceDeletion/DeletionText.tsx rename to site/src/components/WorkspaceDeletion/ImpendingDeletionText.tsx index 576ac15fa114c..6191ed927cc69 100644 --- a/site/src/components/WorkspaceDeletion/DeletionText.tsx +++ b/site/src/components/WorkspaceDeletion/ImpendingDeletionText.tsx @@ -4,7 +4,7 @@ import { useDashboard } from "components/Dashboard/DashboardProvider" import styled from "@emotion/styled" import { Theme as MaterialUITheme } from "@mui/material/styles" -export const DeletionText = ({ +export const ImpendingDeletionText = ({ workspace, }: { workspace: Workspace diff --git a/site/src/components/WorkspaceDeletion/index.ts b/site/src/components/WorkspaceDeletion/index.ts index c0a77f1b4524e..d58af8e83ac57 100644 --- a/site/src/components/WorkspaceDeletion/index.ts +++ b/site/src/components/WorkspaceDeletion/index.ts @@ -1,4 +1,4 @@ -export * from "./DeletionStat" -export * from "./DeletionBadge" -export * from "./DeletionText" -export * from "./DeletionBanner" +export * from "./ImpendingDeletionStat" +export * from "./ImpendingDeletionBadge" +export * from "./ImpendingDeletionText" +export * from "./ImpendingDeletionBanner" diff --git a/site/src/components/WorkspaceDeletion/utils.test.ts b/site/src/components/WorkspaceDeletion/utils.test.ts index 7bc807f9ccaa1..9436926ec7108 100644 --- a/site/src/components/WorkspaceDeletion/utils.test.ts +++ b/site/src/components/WorkspaceDeletion/utils.test.ts @@ -2,57 +2,55 @@ import * as TypesGen from "api/typesGenerated" import * as Mocks from "testHelpers/entities" import { displayImpendingDeletion } from "./utils" -describe("util > workspace deletion", () => { - describe("displayImpendingDeletion", () => { - const today = new Date() - it.each<[string, boolean, boolean, boolean]>([ - [ - new Date(new Date().setDate(today.getDate() + 15)).toISOString(), - true, - true, - false, - ], // today + 15 days out - [ - new Date(new Date().setDate(today.getDate() + 14)).toISOString(), - true, - true, - true, - ], // today + 14 - [ - new Date(new Date().setDate(today.getDate() + 13)).toISOString(), - true, - true, - true, - ], // today + 13 - [ - new Date(new Date().setDate(today.getDate() + 1)).toISOString(), - true, - true, - true, - ], // today + 1 - [new Date().toISOString(), true, true, true], // today + 0 - [new Date().toISOString(), false, true, false], // Advanced Scheduling off - [new Date().toISOString(), true, false, false], // Workspace Actions off - ])( - `deleting_at=%p, allowAdvancedScheduling=%p, AllowWorkspaceActions=%p, shouldDisplay=%p`, - ( +describe("displayImpendingDeletion", () => { + const today = new Date() + it.each<[string, boolean, boolean, boolean]>([ + [ + new Date(new Date().setDate(today.getDate() + 15)).toISOString(), + true, + true, + false, + ], // today + 15 days out + [ + new Date(new Date().setDate(today.getDate() + 14)).toISOString(), + true, + true, + true, + ], // today + 14 + [ + new Date(new Date().setDate(today.getDate() + 13)).toISOString(), + true, + true, + true, + ], // today + 13 + [ + new Date(new Date().setDate(today.getDate() + 1)).toISOString(), + true, + true, + true, + ], // today + 1 + [new Date().toISOString(), true, true, true], // today + 0 + [new Date().toISOString(), false, true, false], // Advanced Scheduling off + [new Date().toISOString(), true, false, false], // Workspace Actions off + ])( + `deleting_at=%p, allowAdvancedScheduling=%p, AllowWorkspaceActions=%p, shouldDisplay=%p`, + ( + deleting_at, + allowAdvancedScheduling, + allowWorkspaceActions, + shouldDisplay, + ) => { + const workspace: TypesGen.Workspace = { + ...Mocks.MockWorkspace, deleting_at, - allowAdvancedScheduling, - allowWorkspaceActions, - shouldDisplay, - ) => { - const workspace: TypesGen.Workspace = { - ...Mocks.MockWorkspace, - deleting_at, - } - expect( - displayImpendingDeletion( - workspace, - allowAdvancedScheduling, - allowWorkspaceActions, - ), - ).toBe(shouldDisplay) - }, - ) - }) + } + expect( + displayImpendingDeletion( + workspace, + allowAdvancedScheduling, + allowWorkspaceActions, + ), + ).toBe(shouldDisplay) + }, + ) }) diff --git a/site/src/components/WorkspaceStats/WorkspaceStats.tsx b/site/src/components/WorkspaceStats/WorkspaceStats.tsx index 212a53f6aa885..c7d2f1a941de9 100644 --- a/site/src/components/WorkspaceStats/WorkspaceStats.tsx +++ b/site/src/components/WorkspaceStats/WorkspaceStats.tsx @@ -20,7 +20,7 @@ import Popover from "@mui/material/Popover" import TextField from "@mui/material/TextField" import Button from "@mui/material/Button" import { WorkspaceStatusText } from "components/WorkspaceStatusBadge/WorkspaceStatusBadge" -import { DeletionStat } from "components/WorkspaceDeletion" +import { ImpendingDeletionStat } from "components/WorkspaceDeletion" const Language = { workspaceDetails: "Workspace Details", @@ -75,7 +75,7 @@ export const WorkspaceStats: FC = ({ label="Status" value={} /> - + { return @@ -99,9 +102,9 @@ export const WorkspaceStatusBadge: FC< const { text, icon, type } = getStatus(workspace.latest_build.status) return ( - {/* determines its own visibility */} - - + {/* determines its own visibility */} + + @@ -118,9 +121,9 @@ export const WorkspaceStatusText: FC< return ( - {/* determines its own visibility */} - - + {/* determines its own visibility */} + + - workspace.deleting_at)} displayImpendingDeletionBanner={isNewWorkspacesImpendingDeletion()} onDismiss={() => From 20ba9061fddb789b004bd94f3267e7fdac5524ee Mon Sep 17 00:00:00 2001 From: Kira Pilot Date: Thu, 18 May 2023 17:41:05 +0000 Subject: [PATCH 8/8] fix lint --- site/src/pages/WorkspacesPage/WorkspacesPageView.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx index f3f710b8d5884..8d9e2dbfaffcd 100644 --- a/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx +++ b/site/src/pages/WorkspacesPage/WorkspacesPageView.tsx @@ -1,6 +1,5 @@ import Link from "@mui/material/Link" import { Workspace } from "api/typesGenerated" -import { Alert } from "components/Alert/Alert" import { Maybe } from "components/Conditionals/Maybe" import { PaginationWidgetBase } from "components/PaginationWidget/PaginationWidgetBase" import { FC } from "react"