chore(site): refactor dormant badge and add stories (#12555)

This commit is contained in:
Bruno Quaresma
2024-03-12 14:17:55 -03:00
committed by GitHub
parent 321546474b
commit e947e0e829
5 changed files with 102 additions and 142 deletions
@@ -0,0 +1,41 @@
import type { Meta, StoryObj } from "@storybook/react";
import { userEvent, within } from "@storybook/test";
import { MockDormantWorkspace } from "testHelpers/entities";
import { WorkspaceDormantBadge } from "./WorkspaceDormantBadge";
const meta: Meta<typeof WorkspaceDormantBadge> = {
title: "modules/workspaces/WorkspaceDormantBadge",
component: WorkspaceDormantBadge,
args: {
workspace: MockDormantWorkspace,
},
};
export default meta;
type Story = StoryObj<typeof WorkspaceDormantBadge>;
export const Default: Story = {
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await step("Open tooltip", async () => {
await userEvent.hover(canvas.getByRole("status"));
});
},
};
export const DeletingAt: Story = {
args: {
workspace: {
...MockDormantWorkspace,
deleting_at: "2024-03-12T14:17:12.196Z",
},
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await step("Open tooltip", async () => {
await userEvent.hover(canvas.getByRole("status"));
});
},
};
@@ -0,0 +1,58 @@
import AutoDeleteIcon from "@mui/icons-material/AutoDelete";
import RecyclingIcon from "@mui/icons-material/Recycling";
import Tooltip from "@mui/material/Tooltip";
import { formatDistanceToNow } from "date-fns";
import type { FC } from "react";
import type { Workspace } from "api/typesGenerated";
import { Pill } from "components/Pill/Pill";
export type WorkspaceDormantBadgeProps = {
workspace: Workspace;
};
export const WorkspaceDormantBadge: FC<WorkspaceDormantBadgeProps> = ({
workspace,
}) => {
const formatDate = (dateStr: string): string => {
const date = new Date(dateStr);
return date.toLocaleDateString(undefined, {
month: "long",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
});
};
return workspace.deleting_at ? (
<Tooltip
title={
<>
This workspace has not been used for{" "}
{formatDistanceToNow(Date.parse(workspace.last_used_at))} and has been
marked dormant. It is scheduled to be deleted on{" "}
{formatDate(workspace.deleting_at)}.
</>
}
>
<Pill role="status" icon={<AutoDeleteIcon />} type="error">
Deletion Pending
</Pill>
</Tooltip>
) : (
<Tooltip
title={
<>
This workspace has not been used for{" "}
{formatDistanceToNow(Date.parse(workspace.last_used_at))} and has been
marked dormant. It is not scheduled for auto-deletion but will become
a candidate if auto-deletion is enabled on this template.
</>
}
>
<Pill role="status" icon={<RecyclingIcon />} type="warning">
Dormant
</Pill>
</Tooltip>
);
};
@@ -1,34 +0,0 @@
import type { FC } from "react";
import type { Workspace } from "api/typesGenerated";
import { useDashboard } from "modules/dashboard/useDashboard";
import { displayDormantDeletion } from "utils/dormant";
interface DormantDeletionTextProps {
workspace: Workspace;
}
export const DormantDeletionText: FC<DormantDeletionTextProps> = ({
workspace,
}) => {
const { entitlements } = 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
if (!displayDormantDeletion(workspace, allowAdvancedScheduling)) {
return null;
}
return (
<span
role="status"
css={(theme) => ({
color: theme.palette.warning.light,
fontWeight: 600,
})}
>
Impending deletion
</span>
);
};
@@ -1,18 +1,14 @@
import AutoDeleteIcon from "@mui/icons-material/AutoDelete";
import ErrorOutline from "@mui/icons-material/ErrorOutline";
import RecyclingIcon from "@mui/icons-material/Recycling";
import Tooltip, {
type TooltipProps,
tooltipClasses,
} from "@mui/material/Tooltip";
import { formatDistanceToNow } from "date-fns";
import type { FC, ReactNode } from "react";
import type { Workspace } from "api/typesGenerated";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { Pill } from "components/Pill/Pill";
import { useClassName } from "hooks/useClassName";
import { getDisplayWorkspaceStatus } from "utils/workspace";
import { DormantDeletionText } from "./DormantDeletionText";
export type WorkspaceStatusBadgeProps = {
workspace: Workspace;
@@ -73,105 +69,6 @@ export const WorkspaceStatusBadge: FC<WorkspaceStatusBadgeProps> = ({
);
};
export type DormantStatusBadgeProps = {
workspace: Workspace;
className?: string;
};
export const DormantStatusBadge: FC<DormantStatusBadgeProps> = ({
workspace,
className,
}) => {
if (!workspace.dormant_at) {
return null;
}
const formatDate = (dateStr: string): string => {
const date = new Date(dateStr);
return date.toLocaleDateString(undefined, {
month: "long",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
});
};
return workspace.deleting_at ? (
<Tooltip
title={
<>
This workspace has not been used for{" "}
{formatDistanceToNow(Date.parse(workspace.last_used_at))} and has been
marked dormant. It is scheduled to be deleted on{" "}
{formatDate(workspace.deleting_at)}.
</>
}
>
<Pill
role="status"
className={className}
icon={<AutoDeleteIcon />}
type="error"
>
Deletion Pending
</Pill>
</Tooltip>
) : (
<Tooltip
title={
<>
This workspace has not been used for{" "}
{formatDistanceToNow(Date.parse(workspace.last_used_at))} and has been
marked dormant. It is not scheduled for auto-deletion but will become
a candidate if auto-deletion is enabled on this template.
</>
}
>
<Pill
role="status"
className={className}
icon={<RecyclingIcon />}
type="warning"
>
Dormant
</Pill>
</Tooltip>
);
};
export const WorkspaceStatusText: FC<WorkspaceStatusBadgeProps> = ({
workspace,
className,
}) => {
const { text, type } = getDisplayWorkspaceStatus(
workspace.latest_build.status,
);
return (
<ChooseOne>
<Cond condition={Boolean(DormantDeletionText({ workspace }))}>
<DormantDeletionText workspace={workspace} />
</Cond>
<Cond>
<span
role="status"
data-testid="build-status"
className={className}
css={(theme) => ({
fontWeight: 600,
color: type
? theme.roles[type].fill.solid
: theme.experimental.l1.text,
})}
>
{text}
</span>
</Cond>
</ChooseOne>
);
};
const FailureTooltip: FC<TooltipProps> = ({ children, ...tooltipProps }) => {
const popper = useClassName(
(css, theme) => css`
@@ -22,11 +22,9 @@ import {
TableRowSkeleton,
} from "components/TableLoader/TableLoader";
import { useClickableTableRow } from "hooks/useClickableTableRow";
import { WorkspaceDormantBadge } from "modules/workspaces/WorkspaceDormantBadge/WorkspaceDormantBadge";
import { WorkspaceOutdatedTooltip } from "modules/workspaces/WorkspaceOutdatedTooltip/WorkspaceOutdatedTooltip";
import {
DormantStatusBadge,
WorkspaceStatusBadge,
} from "modules/workspaces/WorkspaceStatusBadge/WorkspaceStatusBadge";
import { WorkspaceStatusBadge } from "modules/workspaces/WorkspaceStatusBadge/WorkspaceStatusBadge";
import { LastUsed } from "pages/WorkspacesPage/LastUsed";
import { getDisplayWorkspaceTemplateName } from "utils/workspace";
import { WorkspacesEmpty } from "./WorkspacesEmpty";
@@ -214,7 +212,7 @@ export const WorkspacesTable: FC<WorkspacesTableProps> = ({
/>
)}
{workspace.dormant_at && (
<DormantStatusBadge workspace={workspace} />
<WorkspaceDormantBadge workspace={workspace} />
)}
</div>
</TableCell>