mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(site): simplify bulk task delete confirmation UI (#20979)
Reduce from 3 confirmation stages to 2 by removing the redundant "resources" stage. The final button now shows "Delete N tasks and M workspaces" directly, so users still see what will be deleted. Also add a Cancel button to match the single task delete dialog UX. Refs #20905
This commit is contained in:
@@ -33,7 +33,7 @@ const meta: Meta<typeof BatchDeleteConfirmation> = {
|
||||
name: "task-docs-789",
|
||||
display_name: "Update Documentation",
|
||||
initial_prompt: "Update documentation for the new features",
|
||||
// Intentionally null to test that only 2 workspaces are shown in review resources stage
|
||||
// Intentionally null to test that only 2 workspaces are shown
|
||||
workspace_id: null,
|
||||
created_at: new Date(
|
||||
Date.now() - 3 * 24 * 60 * 60 * 1000,
|
||||
@@ -64,23 +64,3 @@ export const ReviewTasks: Story = {
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const ReviewResources: Story = {
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const body = within(canvasElement.ownerDocument.body);
|
||||
|
||||
await step("Advance to stage 2: Review tasks", async () => {
|
||||
const confirmButton = await body.findByRole("button", {
|
||||
name: /review selected tasks/i,
|
||||
});
|
||||
await userEvent.click(confirmButton);
|
||||
});
|
||||
|
||||
await step("Advance to stage 3: Review resources", async () => {
|
||||
const confirmButton = await body.findByRole("button", {
|
||||
name: /confirm.*tasks/i,
|
||||
});
|
||||
await userEvent.click(confirmButton);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Task } from "api/typesGenerated";
|
||||
import { ConfirmDialog } from "components/Dialogs/ConfirmDialog/ConfirmDialog";
|
||||
import dayjs from "dayjs";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import { ClockIcon, ServerIcon, UserIcon } from "lucide-react";
|
||||
import { ClockIcon, UserIcon } from "lucide-react";
|
||||
import { type FC, type ReactNode, useState } from "react";
|
||||
|
||||
dayjs.extend(relativeTime);
|
||||
@@ -24,17 +24,12 @@ export const BatchDeleteConfirmation: FC<BatchDeleteConfirmationProps> = ({
|
||||
onConfirm,
|
||||
isLoading,
|
||||
}) => {
|
||||
const [stage, setStage] = useState<"consequences" | "tasks" | "resources">(
|
||||
"consequences",
|
||||
);
|
||||
const [stage, setStage] = useState<"consequences" | "tasks">("consequences");
|
||||
|
||||
const onProceed = () => {
|
||||
switch (stage) {
|
||||
case "resources":
|
||||
onConfirm();
|
||||
break;
|
||||
case "tasks":
|
||||
setStage("resources");
|
||||
onConfirm();
|
||||
break;
|
||||
case "consequences":
|
||||
setStage("tasks");
|
||||
@@ -45,15 +40,12 @@ export const BatchDeleteConfirmation: FC<BatchDeleteConfirmationProps> = ({
|
||||
const taskCount = `${checkedTasks.length} ${
|
||||
checkedTasks.length === 1 ? "task" : "tasks"
|
||||
}`;
|
||||
const workspaceCountText = `${workspaceCount} ${
|
||||
workspaceCount === 1 ? "workspace" : "workspaces"
|
||||
}`;
|
||||
|
||||
let confirmText: ReactNode = <>Review selected tasks…</>;
|
||||
if (stage === "tasks") {
|
||||
confirmText = <>Confirm {taskCount}…</>;
|
||||
}
|
||||
if (stage === "resources") {
|
||||
const workspaceCountText = `${workspaceCount} ${
|
||||
workspaceCount === 1 ? "workspace" : "workspaces"
|
||||
}`;
|
||||
confirmText = (
|
||||
<>
|
||||
Delete {taskCount} and {workspaceCountText}
|
||||
@@ -70,7 +62,6 @@ export const BatchDeleteConfirmation: FC<BatchDeleteConfirmationProps> = ({
|
||||
onClose();
|
||||
}}
|
||||
title={`Delete ${taskCount}`}
|
||||
hideCancel
|
||||
confirmLoading={isLoading}
|
||||
confirmText={confirmText}
|
||||
onConfirm={onProceed}
|
||||
@@ -78,11 +69,6 @@ export const BatchDeleteConfirmation: FC<BatchDeleteConfirmationProps> = ({
|
||||
<>
|
||||
{stage === "consequences" && <Consequences />}
|
||||
{stage === "tasks" && <Tasks tasks={checkedTasks} />}
|
||||
{stage === "resources" && (
|
||||
<Resources tasks={checkedTasks} workspaceCount={workspaceCount} />
|
||||
)}
|
||||
{/* Preload ServerIcon to prevent flicker on stage 3 */}
|
||||
<ServerIcon className="sr-only" aria-hidden />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
@@ -93,11 +79,6 @@ interface TasksStageProps {
|
||||
tasks: readonly Task[];
|
||||
}
|
||||
|
||||
interface ResourcesStageProps {
|
||||
tasks: readonly Task[];
|
||||
workspaceCount: number;
|
||||
}
|
||||
|
||||
const Consequences: FC = () => {
|
||||
return (
|
||||
<>
|
||||
@@ -174,24 +155,3 @@ const Tasks: FC<TasksStageProps> = ({ tasks }) => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const Resources: FC<ResourcesStageProps> = ({ tasks, workspaceCount }) => {
|
||||
const taskCount = tasks.length;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4">
|
||||
<p>
|
||||
Deleting {taskCount === 1 ? "this task" : "these tasks"} will also
|
||||
permanently destroy…
|
||||
</p>
|
||||
<div className="flex flex-wrap justify-center gap-x-5 gap-y-1.5 text-sm">
|
||||
<div className="flex items-center gap-2">
|
||||
<ServerIcon className="size-icon-sm" />
|
||||
<span>
|
||||
{workspaceCount} {workspaceCount === 1 ? "workspace" : "workspaces"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user