From 12f51bbd5e955e5544259f2adefc00f2b9be93cb Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 4 Nov 2025 21:04:58 +0000 Subject: [PATCH] feat: Add delete functionality for AI messages and subsequent nodes - Added delete button to AI text messages, API request messages, and completion messages - Implemented right-click context menu for delete operation - Reuses existing backend deletion logic that removes selected message and all subsequent messages - Only shows delete controls when message is not streaming Fixes #9035 --- webview-ui/src/components/chat/ChatRow.tsx | 188 +++++++++++++++------ 1 file changed, 141 insertions(+), 47 deletions(-) diff --git a/webview-ui/src/components/chat/ChatRow.tsx b/webview-ui/src/components/chat/ChatRow.tsx index fd3d480014..fdb18daf0b 100644 --- a/webview-ui/src/components/chat/ChatRow.tsx +++ b/webview-ui/src/components/chat/ChatRow.tsx @@ -16,6 +16,12 @@ import { findMatchingResourceOrTemplate } from "@src/utils/mcp" import { vscode } from "@src/utils/vscode" import { removeLeadingNonAlphanumeric } from "@src/utils/removeLeadingNonAlphanumeric" import { getLanguageFromPath } from "@src/utils/getLanguageFromPath" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@src/components/ui/dropdown-menu" import { ToolUseBlock, ToolUseBlockHeader } from "../common/ToolUseBlock" import UpdateTodoListToolBlock from "./UpdateTodoListToolBlock" @@ -1002,29 +1008,63 @@ export const ChatRowContent = ({ return ( <> -
-
- {icon} - {title} -
-
0 ? 1 : 0 }}> - ${Number(cost || 0)?.toFixed(4)} -
-
+ + +
e.preventDefault()}> +
+ {icon} + {title} +
+
+
0 ? 1 : 0, + }}> + ${Number(cost || 0)?.toFixed(4)} +
+
{ + e.stopPropagation() + vscode.postMessage({ type: "deleteMessage", value: message.ts }) + }} + title={t("chat:deleteMessageAndSubsequent")}> + +
+
+
+
+ + vscode.postMessage({ type: "deleteMessage", value: message.ts })} + className="flex items-center gap-2" + disabled={isApiRequestInProgress}> + + + {t( + "chat:deleteMessageAndSubsequent", + "Delete message and subsequent nodes", + )} + + + +
{(((cost === null || cost === undefined) && apiRequestFailedMessage) || apiReqStreamingFailedMessage) && ( -
- - {t("chat:text.rooSaid")} -
-
- - {message.images && message.images.length > 0 && ( -
- {message.images.map((image, index) => ( - - ))} + + +
e.preventDefault()}> +
+
+ + {t("chat:text.rooSaid")} +
+
{ + e.stopPropagation() + vscode.postMessage({ type: "deleteMessage", value: message.ts }) + }} + title={t("chat:deleteMessageAndSubsequent")}> + +
- )} -
-
+
+ + {message.images && message.images.length > 0 && ( +
+ {message.images.map((image, index) => ( + + ))} +
+ )} +
+
+ + + vscode.postMessage({ type: "deleteMessage", value: message.ts })} + className="flex items-center gap-2" + disabled={isStreaming}> + + + {t("chat:deleteMessageAndSubsequent", "Delete message and subsequent nodes")} + + + + ) case "user_feedback": return ( @@ -1162,15 +1229,42 @@ export const ChatRowContent = ({ return case "completion_result": return ( - <> -
- {icon} - {title} -
-
- -
- + + +
e.preventDefault()}> +
+
+ {icon} + {title} +
+
{ + e.stopPropagation() + vscode.postMessage({ type: "deleteMessage", value: message.ts }) + }} + title={t("chat:deleteMessageAndSubsequent")}> + +
+
+
+ +
+
+
+ + vscode.postMessage({ type: "deleteMessage", value: message.ts })} + className="flex items-center gap-2" + disabled={isStreaming}> + + + {t("chat:deleteMessageAndSubsequent", "Delete message and subsequent nodes")} + + + +
) case "shell_integration_warning": return