From ea43c87f7f00fcdc9802fc62cebc5facd36242ec Mon Sep 17 00:00:00 2001 From: Bruno Bergher Date: Tue, 5 Aug 2025 21:59:41 +0100 Subject: [PATCH] Fixes logic for displaying CloudNotificationBanner and adjusts tests --- .../chat/CloudNotificationBanner.tsx | 14 +++++-- webview-ui/src/components/chat/TaskHeader.tsx | 4 +- .../TaskHeader.cloud-notification.spec.tsx | 37 ++++++++++++++++--- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/webview-ui/src/components/chat/CloudNotificationBanner.tsx b/webview-ui/src/components/chat/CloudNotificationBanner.tsx index f050cd13bc..011c23ee2e 100644 --- a/webview-ui/src/components/chat/CloudNotificationBanner.tsx +++ b/webview-ui/src/components/chat/CloudNotificationBanner.tsx @@ -1,6 +1,7 @@ import { useTranslation } from "react-i18next" import { Lightbulb, X } from "lucide-react" import { cn } from "@src/lib/utils" +import { vscode } from "@src/utils/vscode" interface CloudNotificationBannerProps { onDismiss: () => void @@ -14,16 +15,20 @@ export const CloudNotificationBanner = ({ onDismiss, className }: CloudNotificat onDismiss() } - const handleClick = () => { + const handleNavigate = () => { + vscode.postMessage({ type: "switchTab", tab: "account" }) handleDismiss() } return ( -
+
{/* Main notification container with speech bubble */}
+ onClick={handleNavigate} + data-testid="navigate-button"> {/* Speech bubble triangle */}
+ aria-label="Close notification" + data-testid="dismiss-button">
diff --git a/webview-ui/src/components/chat/TaskHeader.tsx b/webview-ui/src/components/chat/TaskHeader.tsx index b3209ddf33..10dfbbd272 100644 --- a/webview-ui/src/components/chat/TaskHeader.tsx +++ b/webview-ui/src/components/chat/TaskHeader.tsx @@ -70,12 +70,12 @@ const TaskHeader = ({ // Show notification if task has been running for more than 2 minutes // and hasn't been dismissed for this task - const shouldShow = duration > threshold && !dismissedCloudNotifications.has(taskId) + const shouldShow = duration > threshold && !dismissedCloudNotifications.has(taskId) && buttonsDisabled setShowCloudNotification(shouldShow) }, 1000) return () => clearInterval(interval) - }, [task.ts, currentTaskItem?.id, dismissedCloudNotifications]) + }, [task.ts, currentTaskItem?.id, dismissedCloudNotifications, buttonsDisabled]) const handleDismissCloudNotification = () => { if (currentTaskItem?.id) { diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.cloud-notification.spec.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.cloud-notification.spec.tsx index cb56449452..d019489644 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.cloud-notification.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.cloud-notification.spec.tsx @@ -110,7 +110,7 @@ describe("TaskHeader Cloud Notification", () => { tokensOut: 50, totalCost: 0.05, contextTokens: 1000, - buttonsDisabled: false, + buttonsDisabled: true, handleCondenseContext: vi.fn(), } @@ -146,6 +146,7 @@ describe("TaskHeader Cloud Notification", () => { const taskStartTime = Date.now() - 3 * 60 * 1000 // 3 minutes ago renderTaskHeader({ task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running }) // Fast-forward timers to trigger the interval @@ -162,6 +163,7 @@ describe("TaskHeader Cloud Notification", () => { const taskStartTime = Date.now() - 1 * 60 * 1000 // 1 minute ago renderTaskHeader({ task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running }) // Fast-forward timers to trigger the interval @@ -180,6 +182,24 @@ describe("TaskHeader Cloud Notification", () => { renderTaskHeader({ task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running + }) + + // Fast-forward timers to trigger the interval + act(() => { + vi.advanceTimersByTime(1000) + }) + + await waitFor(() => { + expect(screen.queryByTestId("cloud-notification-banner")).not.toBeInTheDocument() + }) + }) + + it("does not show cloud notification for completed tasks (buttonsDisabled: false)", async () => { + const taskStartTime = Date.now() - 3 * 60 * 1000 // 3 minutes ago + renderTaskHeader({ + task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: false, // Task is completed/not running }) // Fast-forward timers to trigger the interval @@ -196,6 +216,7 @@ describe("TaskHeader Cloud Notification", () => { const taskStartTime = Date.now() - 3 * 60 * 1000 // 3 minutes ago renderTaskHeader({ task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running }) // Expand the task to see TaskActions @@ -219,6 +240,7 @@ describe("TaskHeader Cloud Notification", () => { const taskStartTime = Date.now() - 3 * 60 * 1000 // 3 minutes ago renderTaskHeader({ task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running }) // Fast-forward timers to trigger the interval @@ -244,6 +266,7 @@ describe("TaskHeader Cloud Notification", () => { const taskStartTime = Date.now() - 3 * 60 * 1000 // 3 minutes ago renderTaskHeader({ task: { type: "say", ts: taskStartTime, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running }) // Fast-forward timers to trigger the interval @@ -279,6 +302,7 @@ describe("TaskHeader Cloud Notification", () => { it("updates duration tracking when task changes", async () => { const { rerender } = renderTaskHeader({ task: { type: "say", ts: Date.now() - 1 * 60 * 1000, text: "Test task", images: [] }, + buttonsDisabled: true, // Task is still running }) // Fast-forward timers @@ -292,10 +316,13 @@ describe("TaskHeader Cloud Notification", () => { // Update task to be older rerender( - + + + , )