From c6c8760d4e96ba487d650a451909b53d189aa299 Mon Sep 17 00:00:00 2001 From: Canyon Robins Date: Wed, 28 May 2025 18:36:42 -0700 Subject: [PATCH 1/5] [Condense] Move condense button out of expanded task menu --- .../src/components/chat/TaskActions.tsx | 9 +------ webview-ui/src/components/chat/TaskHeader.tsx | 25 +++++++++---------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/webview-ui/src/components/chat/TaskActions.tsx b/webview-ui/src/components/chat/TaskActions.tsx index 2eebc6ccb3..18325af8fb 100644 --- a/webview-ui/src/components/chat/TaskActions.tsx +++ b/webview-ui/src/components/chat/TaskActions.tsx @@ -12,10 +12,9 @@ import { IconButton } from "./IconButton" interface TaskActionsProps { item?: HistoryItem buttonsDisabled: boolean - handleCondenseContext: (taskId: string) => void } -export const TaskActions = ({ item, buttonsDisabled, handleCondenseContext }: TaskActionsProps) => { +export const TaskActions = ({ item, buttonsDisabled }: TaskActionsProps) => { const [deleteTaskId, setDeleteTaskId] = useState(null) const { t } = useTranslation() @@ -29,12 +28,6 @@ export const TaskActions = ({ item, buttonsDisabled, handleCondenseContext }: Ta /> {!!item?.size && item.size > 0 && ( <> - handleCondenseContext(item.id)} - />
{/* Collapsed state: Track context and cost if we have any */} {!isTaskExpanded && contextWindow > 0 && ( -
+
+ currentTaskItem && handleCondenseContext(currentTaskItem.id)} + className="shrink-0" + style={{ minHeight: "20px", minWidth: "20px", padding: "2px" }} + /> {!!totalCost && ${totalCost.toFixed(2)}}
)} @@ -169,13 +178,7 @@ const TaskHeader = ({ )}
- {!totalCost && ( - - )} + {!totalCost && }
{doesModelSupportPromptCache && @@ -204,11 +207,7 @@ const TaskHeader = ({ {t("chat:task.apiCost")} ${totalCost?.toFixed(2)} - + )} From 855c856436dc0d8d3f78e38698150addedf4da63 Mon Sep 17 00:00:00 2001 From: Canyon Robins Date: Wed, 28 May 2025 18:39:20 -0700 Subject: [PATCH 2/5] tests --- .../chat/__tests__/TaskHeader.test.tsx | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx index 12f43b8bea..b70d9a7b80 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx @@ -1,13 +1,20 @@ // npx jest src/components/chat/__tests__/TaskHeader.test.tsx import React from "react" -import { render, screen } from "@testing-library/react" +import { render, screen, fireEvent } from "@testing-library/react" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import type { ProviderSettings } from "@roo-code/types" import TaskHeader, { TaskHeaderProps } from "../TaskHeader" +// Mock i18n +jest.mock("react-i18next", () => ({ + useTranslation: () => ({ + t: (key: string) => key, // Simple mock that returns the key + }), +})) + // Mock the vscode API jest.mock("@/utils/vscode", () => ({ vscode: { @@ -28,7 +35,7 @@ jest.mock("@src/context/ExtensionStateContext", () => ({ apiKey: "test-api-key", // Add relevant fields apiModelId: "claude-3-opus-20240229", // Add relevant fields } as ProviderSettings, // Optional: Add type assertion if ProviderSettings is imported - currentTaskItem: null, + currentTaskItem: { id: "test-task-id" }, // Add a mock currentTaskItem for the condense button }), })) @@ -79,4 +86,23 @@ describe("TaskHeader", () => { renderTaskHeader({ totalCost: NaN }) expect(screen.queryByText(/\$/)).not.toBeInTheDocument() }) + + it("should render the condense context button", () => { + renderTaskHeader() + expect(screen.getByTitle("chat:task.condenseContext")).toBeInTheDocument() + }) + + it("should call handleCondenseContext when condense context button is clicked", () => { + const handleCondenseContext = jest.fn() + renderTaskHeader({ handleCondenseContext }) + const condenseButton = screen.getByTitle("chat:task.condenseContext") + fireEvent.click(condenseButton) + expect(handleCondenseContext).toHaveBeenCalledWith("test-task-id") + }) + + it("should disable the condense context button when buttonsDisabled is true", () => { + renderTaskHeader({ buttonsDisabled: true }) + const condenseButton = screen.getByTitle("chat:task.condenseContext") + expect(condenseButton).toBeDisabled() + }) }) From 98017d0f32962df7e72f26616ac5f4b0dfd5b95a Mon Sep 17 00:00:00 2001 From: Canyon Robins Date: Wed, 28 May 2025 18:43:49 -0700 Subject: [PATCH 3/5] fix test --- .../src/components/chat/__tests__/TaskHeader.test.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx index b70d9a7b80..a935f52b1f 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx @@ -13,6 +13,11 @@ jest.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string) => key, // Simple mock that returns the key }), + // Mock initReactI18next to prevent initialization errors in tests + initReactI18next: { + type: "3rdParty", + init: jest.fn(), + }, })) // Mock the vscode API @@ -35,7 +40,7 @@ jest.mock("@src/context/ExtensionStateContext", () => ({ apiKey: "test-api-key", // Add relevant fields apiModelId: "claude-3-opus-20240229", // Add relevant fields } as ProviderSettings, // Optional: Add type assertion if ProviderSettings is imported - currentTaskItem: { id: "test-task-id" }, // Add a mock currentTaskItem for the condense button + currentTaskItem: { id: "test-task-id" }, }), })) From fbd76bc7a7e167a6fd47c83046e5fe9932a13057 Mon Sep 17 00:00:00 2001 From: Canyon Robins Date: Wed, 28 May 2025 18:47:27 -0700 Subject: [PATCH 4/5] fix test again --- .../src/components/chat/__tests__/TaskHeader.test.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx index a935f52b1f..9d0de80191 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx @@ -106,8 +106,10 @@ describe("TaskHeader", () => { }) it("should disable the condense context button when buttonsDisabled is true", () => { - renderTaskHeader({ buttonsDisabled: true }) + const handleCondenseContext = jest.fn() + renderTaskHeader({ buttonsDisabled: true, handleCondenseContext }) const condenseButton = screen.getByTitle("chat:task.condenseContext") - expect(condenseButton).toBeDisabled() + fireEvent.click(condenseButton) + expect(handleCondenseContext).not.toHaveBeenCalled() }) }) From 3753f3fdf6b5ed0cac51a713e304795a83103df2 Mon Sep 17 00:00:00 2001 From: Canyon Robins Date: Wed, 28 May 2025 18:49:28 -0700 Subject: [PATCH 5/5] tailwind css --- webview-ui/src/components/chat/TaskHeader.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/webview-ui/src/components/chat/TaskHeader.tsx b/webview-ui/src/components/chat/TaskHeader.tsx index 92475536b6..7bad41316e 100644 --- a/webview-ui/src/components/chat/TaskHeader.tsx +++ b/webview-ui/src/components/chat/TaskHeader.tsx @@ -113,8 +113,7 @@ const TaskHeader = ({ title={t("chat:task.condenseContext")} disabled={buttonsDisabled} onClick={() => currentTaskItem && handleCondenseContext(currentTaskItem.id)} - className="shrink-0" - style={{ minHeight: "20px", minWidth: "20px", padding: "2px" }} + className="shrink-0 min-h-[20px] min-w-[20px] p-[2px]" /> {!!totalCost && ${totalCost.toFixed(2)}}