Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions webview-ui/src/components/chat/TaskActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | null>(null)
const { t } = useTranslation()

Expand All @@ -29,12 +28,6 @@ export const TaskActions = ({ item, buttonsDisabled, handleCondenseContext }: Ta
/>
{!!item?.size && item.size > 0 && (
<>
<IconButton
iconClass="codicon-fold"
title={t("chat:task.condenseContext")}
disabled={buttonsDisabled}
onClick={() => handleCondenseContext(item.id)}
/>
<div className="flex items-center">
<IconButton
iconClass="codicon-trash"
Expand Down
24 changes: 11 additions & 13 deletions webview-ui/src/components/chat/TaskHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Thumbnails from "../common/Thumbnails"
import { TaskActions } from "./TaskActions"
import { ContextWindowProgress } from "./ContextWindowProgress"
import { Mention } from "./Mention"
import { IconButton } from "./IconButton"

export interface TaskHeaderProps {
task: ClineMessage
Expand Down Expand Up @@ -97,7 +98,7 @@ const TaskHeader = ({
</div>
{/* Collapsed state: Track context and cost if we have any */}
{!isTaskExpanded && contextWindow > 0 && (
<div className={`w-full flex flex-row gap-1 h-auto`}>
<div className={`w-full flex flex-row items-center gap-1 h-auto`}>
<ContextWindowProgress
contextWindow={contextWindow}
contextTokens={contextTokens || 0}
Expand All @@ -107,6 +108,13 @@ const TaskHeader = ({
: undefined
}
/>
<IconButton
iconClass="codicon-fold"
title={t("chat:task.condenseContext")}
disabled={buttonsDisabled}
onClick={() => currentTaskItem && handleCondenseContext(currentTaskItem.id)}
className="shrink-0 min-h-[20px] min-w-[20px] p-[2px]"
/>
{!!totalCost && <VSCodeBadge>${totalCost.toFixed(2)}</VSCodeBadge>}
</div>
)}
Expand Down Expand Up @@ -169,13 +177,7 @@ const TaskHeader = ({
</span>
)}
</div>
{!totalCost && (
<TaskActions
item={currentTaskItem}
buttonsDisabled={buttonsDisabled}
handleCondenseContext={handleCondenseContext}
/>
)}
{!totalCost && <TaskActions item={currentTaskItem} buttonsDisabled={buttonsDisabled} />}
</div>

{doesModelSupportPromptCache &&
Expand Down Expand Up @@ -204,11 +206,7 @@ const TaskHeader = ({
<span className="font-bold">{t("chat:task.apiCost")}</span>
<span>${totalCost?.toFixed(2)}</span>
</div>
<TaskActions
item={currentTaskItem}
buttonsDisabled={buttonsDisabled}
handleCondenseContext={handleCondenseContext}
/>
<TaskActions item={currentTaskItem} buttonsDisabled={buttonsDisabled} />
</div>
)}
</div>
Expand Down
37 changes: 35 additions & 2 deletions webview-ui/src/components/chat/__tests__/TaskHeader.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
// 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 initReactI18next to prevent initialization errors in tests
initReactI18next: {
type: "3rdParty",
init: jest.fn(),
},
}))

// Mock the vscode API
jest.mock("@/utils/vscode", () => ({
vscode: {
Expand All @@ -28,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: null,
currentTaskItem: { id: "test-task-id" },
}),
}))

Expand Down Expand Up @@ -79,4 +91,25 @@ 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", () => {
const handleCondenseContext = jest.fn()
renderTaskHeader({ buttonsDisabled: true, handleCondenseContext })
const condenseButton = screen.getByTitle("chat:task.condenseContext")
fireEvent.click(condenseButton)
expect(handleCondenseContext).not.toHaveBeenCalled()
})
})