From 6a29a8bd9985cfec3e8871159539a306a1851306 Mon Sep 17 00:00:00 2001 From: EMSHVAC Date: Thu, 20 Feb 2025 18:56:05 -0600 Subject: [PATCH 1/4] Prevents accidental task deletions by requiring explicit user confirmation through a modal dialog. This improves the user experience by adding a safety check before performing irreversible actions. --- src/core/webview/ClineProvider.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 05faa138342..6e6ba17db54 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2309,6 +2309,17 @@ export class ClineProvider implements vscode.WebviewViewProvider { } async deleteTaskWithId(id: string) { + const answer = await vscode.window.showInformationMessage( + "Are you sure you want to delete this task? This action cannot be undone.", + { modal: true }, + "Delete", + "Cancel", + ) + + if (answer !== "Delete") { + return + } + if (id === this.cline?.taskId) { await this.clearTask() } From 2fd34316210fd1ecdc635e915ac07a6aef2c6f5e Mon Sep 17 00:00:00 2001 From: EMSHVAC Date: Thu, 20 Feb 2025 19:04:15 -0600 Subject: [PATCH 2/4] no duplicated cancel button --- src/core/webview/ClineProvider.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 6e6ba17db54..824d7a85ea8 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2313,7 +2313,6 @@ export class ClineProvider implements vscode.WebviewViewProvider { "Are you sure you want to delete this task? This action cannot be undone.", { modal: true }, "Delete", - "Cancel", ) if (answer !== "Delete") { From 5a43f867fbf53c14f68743937fde0e6a4f07b2fb Mon Sep 17 00:00:00 2001 From: EMSHVAC Date: Fri, 21 Feb 2025 08:46:56 -0600 Subject: [PATCH 3/4] This commit replaces the VSCode native dialog with a Radix AlertDialog component for task deletion confirmation. The change provides a more consistent user experience by using the same design system as the rest of the application. Changes: Add new DeleteTaskDialog component using Radix UIs AlertDialog Update HistoryView to manage dialog state and task deletion flow Remove VSCode native dialog from ClineProvider.ts --- src/core/webview/ClineProvider.ts | 10 ---- .../components/history/DeleteTaskDialog.tsx | 49 +++++++++++++++++++ .../src/components/history/HistoryView.tsx | 19 ++++++- 3 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 webview-ui/src/components/history/DeleteTaskDialog.tsx diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 824d7a85ea8..05faa138342 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -2309,16 +2309,6 @@ export class ClineProvider implements vscode.WebviewViewProvider { } async deleteTaskWithId(id: string) { - const answer = await vscode.window.showInformationMessage( - "Are you sure you want to delete this task? This action cannot be undone.", - { modal: true }, - "Delete", - ) - - if (answer !== "Delete") { - return - } - if (id === this.cline?.taskId) { await this.clearTask() } diff --git a/webview-ui/src/components/history/DeleteTaskDialog.tsx b/webview-ui/src/components/history/DeleteTaskDialog.tsx new file mode 100644 index 00000000000..b40adeae3de --- /dev/null +++ b/webview-ui/src/components/history/DeleteTaskDialog.tsx @@ -0,0 +1,49 @@ +import React from "react" +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" +import { Button } from "@/components/ui" +import { vscode } from "@/utils/vscode" + +interface DeleteTaskDialogProps { + taskId: string + open: boolean + onOpenChange: (open: boolean) => void +} + +export const DeleteTaskDialog = ({ taskId, open, onOpenChange }: DeleteTaskDialogProps) => { + const handleDelete = () => { + vscode.postMessage({ type: "deleteTaskWithId", text: taskId }) + onOpenChange(false) + } + + return ( + + + + Delete Task + + Are you sure you want to delete this task? This action cannot be undone. + + + + + + + + + + + + + ) +} diff --git a/webview-ui/src/components/history/HistoryView.tsx b/webview-ui/src/components/history/HistoryView.tsx index 38ca14df46c..ca60e1fcb89 100644 --- a/webview-ui/src/components/history/HistoryView.tsx +++ b/webview-ui/src/components/history/HistoryView.tsx @@ -1,4 +1,5 @@ import React, { memo, useMemo, useState, useEffect } from "react" +import { DeleteTaskDialog } from "./DeleteTaskDialog" import { Fzf } from "fzf" import prettyBytes from "pretty-bytes" import { Virtuoso } from "react-virtuoso" @@ -37,8 +38,12 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { vscode.postMessage({ type: "showTaskWithId", text: id }) } + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false) + const [taskToDelete, setTaskToDelete] = useState(null) + const handleDeleteHistoryItem = (id: string) => { - vscode.postMessage({ type: "deleteTaskWithId", text: id }) + setTaskToDelete(id) + setDeleteDialogOpen(true) } const formatDate = (timestamp: number) => { @@ -398,6 +403,18 @@ const HistoryView = ({ onDone }: HistoryViewProps) => { )} /> + {taskToDelete && ( + { + setDeleteDialogOpen(open) + if (!open) { + setTaskToDelete(null) + } + }} + /> + )} ) } From 1922b8aea9eea349144bc820d5f3c170530c3dfe Mon Sep 17 00:00:00 2001 From: EMSHVAC Date: Mon, 24 Feb 2025 11:54:10 -0600 Subject: [PATCH 4/4] test: update HistoryView delete task test to handle confirmation dialog --- .../src/components/history/__tests__/HistoryView.test.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/components/history/__tests__/HistoryView.test.tsx b/webview-ui/src/components/history/__tests__/HistoryView.test.tsx index 7408b268786..12b0181af6b 100644 --- a/webview-ui/src/components/history/__tests__/HistoryView.test.tsx +++ b/webview-ui/src/components/history/__tests__/HistoryView.test.tsx @@ -135,7 +135,7 @@ describe("HistoryView", () => { }) }) - it("handles task deletion", () => { + it("handles task deletion", async () => { const onDone = jest.fn() render() @@ -143,9 +143,14 @@ describe("HistoryView", () => { const taskContainer = screen.getByTestId("virtuoso-item-1") fireEvent.mouseEnter(taskContainer) + // Click delete button to open confirmation dialog const deleteButton = within(taskContainer).getByTitle("Delete Task") fireEvent.click(deleteButton) + // Find and click the confirm delete button in the dialog + const confirmDeleteButton = screen.getByRole("button", { name: /delete/i }) + fireEvent.click(confirmDeleteButton) + // Verify vscode message was sent expect(vscode.postMessage).toHaveBeenCalledWith({ type: "deleteTaskWithId",