[Condense] Move condense button out of expanded task menu (#4093)

* [Condense] Move condense button out of expanded task menu

* tests

* fix test

* fix test again

* tailwind css
This commit is contained in:
Canyon Robins 2025-05-28 18:58:08 -07:00 committed by GitHub
parent 3ee7786a1b
commit 70e753ebb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 47 additions and 23 deletions

View file

@ -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()
@ -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"

View file

@ -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
@ -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}
@ -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>
)}
@ -169,13 +177,7 @@ const TaskHeader = ({
</span>
)}
</div>
{!totalCost && (
<TaskActions
item={currentTaskItem}
buttonsDisabled={buttonsDisabled}
handleCondenseContext={handleCondenseContext}
/>
)}
{!totalCost && <TaskActions item={currentTaskItem} buttonsDisabled={buttonsDisabled} />}
</div>
{doesModelSupportPromptCache &&
@ -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>

View file

@ -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: {
@ -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" },
}),
}))
@ -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()
})
})