From c5e405deb9522c217db295531f75387a214d1be7 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 12 May 2026 10:50:13 +0000 Subject: [PATCH] fix: add cancel confirmation, panel scroll constraint, and Phase 6 extension-point comments --- src/core/task/BackgroundTaskRunner.ts | 10 +++++ .../components/chat/BackgroundTasksPanel.tsx | 43 +++++++++++++++---- .../__tests__/BackgroundTasksPanel.spec.tsx | 11 ++++- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/core/task/BackgroundTaskRunner.ts b/src/core/task/BackgroundTaskRunner.ts index e7ed7127c2..638845198d 100644 --- a/src/core/task/BackgroundTaskRunner.ts +++ b/src/core/task/BackgroundTaskRunner.ts @@ -8,6 +8,16 @@ * - Are not added to the clineStack * * This is Phase 4 of the parallel execution roadmap: Background Read-Only Concurrency. + * + * Phase 6+ extension points: + * - To support write-capable background tasks, extend BACKGROUND_TASK_ALLOWED_TOOLS + * and add a file-locking mechanism to prevent conflicts with foreground edits. + * - For real-time progress streaming, add an `onProgressUpdate` callback to + * BackgroundTaskInfo and emit partial tool-call summaries from Task. + * - For persistent history across sessions, serialize completedTasks to global + * state via the TaskHistoryStore and restore on provider initialization. + * - For tab-based switching, expose the background task's clineMessages via + * getTasksStatus() so the webview can render a full conversation view. */ import { BackgroundTaskStatusInfo } from "@roo-code/types" diff --git a/webview-ui/src/components/chat/BackgroundTasksPanel.tsx b/webview-ui/src/components/chat/BackgroundTasksPanel.tsx index d431415165..1830e11866 100644 --- a/webview-ui/src/components/chat/BackgroundTasksPanel.tsx +++ b/webview-ui/src/components/chat/BackgroundTasksPanel.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo } from "react" +import React, { useState, useCallback, useMemo } from "react" import type { BackgroundTaskStatusInfo } from "@roo-code/types" @@ -69,11 +69,20 @@ function getStatusColor(status: BackgroundTaskStatusInfo["status"]): string { function BackgroundTaskItem({ task }: { task: BackgroundTaskStatusInfo }) { const [showResult, setShowResult] = useState(false) + const [confirmingCancel, setConfirmingCancel] = useState(false) const isRunning = task.status === "running" - const handleCancel = () => { + const handleCancelClick = useCallback(() => { + if (!confirmingCancel) { + setConfirmingCancel(true) + // Auto-reset after 3 seconds if user doesn't confirm + setTimeout(() => setConfirmingCancel(false), 3000) + return + } + // Second click confirms cancellation + setConfirmingCancel(false) vscode.postMessage({ type: "cancelBackgroundTask", taskId: task.taskId }) - } + }, [confirmingCancel, task.taskId]) const shortId = task.taskId.slice(0, 8) @@ -102,10 +111,18 @@ function BackgroundTaskItem({ task }: { task: BackgroundTaskStatusInfo }) { )} {isRunning && ( )} @@ -123,6 +140,16 @@ function BackgroundTaskItem({ task }: { task: BackgroundTaskStatusInfo }) { * BackgroundTasksPanel shows active and recently completed background tasks * as a collapsible section in the chat sidebar. Only renders when there are * background tasks to display. + * + * Phase 6+ evolution notes: + * - This panel can be promoted to a tab-based view alongside the main chat + * by extracting the task list into a shared component and rendering it in + * both the sidebar panel and a dedicated "Background Tasks" tab. + * - For real-time progress streaming, each BackgroundTaskItem could accept + * a `progressMessages` prop with the last N tool-call summaries. + * - For conversation replay, clicking a completed task could open its full + * message history in a read-only chat view (reuse ChatView with a + * `readOnly` flag and the task's clineMessages). */ const BackgroundTasksPanel: React.FC = () => { const { backgroundTasks } = useExtensionState() @@ -155,7 +182,7 @@ const BackgroundTasksPanel: React.FC = () => { {tasks.length} total {!isCollapsed && ( -
+
{tasks.map((task) => ( ))} diff --git a/webview-ui/src/components/chat/__tests__/BackgroundTasksPanel.spec.tsx b/webview-ui/src/components/chat/__tests__/BackgroundTasksPanel.spec.tsx index 3eb52351a3..45d370ad09 100644 --- a/webview-ui/src/components/chat/__tests__/BackgroundTasksPanel.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/BackgroundTasksPanel.spec.tsx @@ -80,7 +80,7 @@ describe("BackgroundTasksPanel", () => { expect(cancelButton).toBeDefined() }) - it("should send cancelBackgroundTask message when cancel is clicked", () => { + it("should require two clicks to cancel (confirmation pattern)", () => { mockBackgroundTasks.push({ taskId: "task-cancel-me", parentTaskId: "parent-1", @@ -90,8 +90,15 @@ describe("BackgroundTasksPanel", () => { render() const cancelButton = screen.getByTitle("Cancel background task") - fireEvent.click(cancelButton) + // First click shows confirmation text, does NOT send message + fireEvent.click(cancelButton) + expect(vscode.postMessage).not.toHaveBeenCalled() + expect(screen.getByText("Cancel?")).toBeDefined() + + // Second click confirms and sends the cancel message + const confirmButton = screen.getByTitle("Click again to confirm cancellation") + fireEvent.click(confirmButton) expect(vscode.postMessage).toHaveBeenCalledWith({ type: "cancelBackgroundTask", taskId: "task-cancel-me",