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:
Mathias Fredriksson
2025-12-04 10:46:02 +02:00
committed by GitHub
parent 6acfcd5736
commit 2f829286f2
2 changed files with 7 additions and 67 deletions
@@ -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&hellip;</>;
if (stage === "tasks") {
confirmText = <>Confirm {taskCount}&hellip;</>;
}
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&hellip;
</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>
);
};