From 6953336e1a7f094f43083800b3276457468a01bc Mon Sep 17 00:00:00 2001 From: awschmeder Date: Sat, 13 Jun 2026 13:47:29 -0700 Subject: [PATCH 1/3] feat(webview): surface condense context button and progress bar in collapsed task header --- ...ondense-button-to-collapsed-task-header.md | 5 ++++ webview-ui/src/components/chat/TaskHeader.tsx | 8 +++++++ .../chat/__tests__/TaskHeader.spec.tsx | 23 +++++++++---------- 3 files changed, 24 insertions(+), 12 deletions(-) create mode 100644 .changeset/add-condense-button-to-collapsed-task-header.md diff --git a/.changeset/add-condense-button-to-collapsed-task-header.md b/.changeset/add-condense-button-to-collapsed-task-header.md new file mode 100644 index 0000000000..2e231eb8e1 --- /dev/null +++ b/.changeset/add-condense-button-to-collapsed-task-header.md @@ -0,0 +1,5 @@ +--- +"zoo-code": patch +--- + +Surface the manual context compaction button and linear context window progress bar on the right side of the collapsed task header. diff --git a/webview-ui/src/components/chat/TaskHeader.tsx b/webview-ui/src/components/chat/TaskHeader.tsx index 4ddf5ef35c..e596c72131 100644 --- a/webview-ui/src/components/chat/TaskHeader.tsx +++ b/webview-ui/src/components/chat/TaskHeader.tsx @@ -274,6 +274,14 @@ const TaskHeader = ({ )} +
+ + {condenseButton} +
)} {/* Expanded state: Show task text and images */} diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx index 41aa452ab1..fd0513bfb0 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx @@ -133,13 +133,20 @@ describe("TaskHeader", () => { expect(screen.queryByText(/\$/)).not.toBeInTheDocument() }) + it("should render the condense context button in the collapsed state", () => { + renderTaskHeader() + // Button is visible without expanding the task header + const buttons = screen.getAllByRole("button") + const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) + expect(condenseButton).toBeDefined() + expect(condenseButton?.querySelector("svg")).toBeInTheDocument() + }) + it("should render the condense context button when expanded", () => { renderTaskHeader() - // First click to expand the task header const taskHeader = screen.getByText("Test task") fireEvent.click(taskHeader) - // Now find the condense button in the expanded state const buttons = screen.getAllByRole("button") const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) expect(condenseButton).toBeDefined() @@ -150,11 +157,7 @@ describe("TaskHeader", () => { const handleCondenseContext = vi.fn() renderTaskHeader({ handleCondenseContext }) - // First click to expand the task header - const taskHeader = screen.getByText("Test task") - fireEvent.click(taskHeader) - - // Find the button that contains the FoldVertical icon + // Button is clickable in collapsed state without expanding first const buttons = screen.getAllByRole("button") const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) expect(condenseButton).toBeDefined() @@ -166,11 +169,7 @@ describe("TaskHeader", () => { const handleCondenseContext = vi.fn() renderTaskHeader({ buttonsDisabled: true, handleCondenseContext }) - // First click to expand the task header - const taskHeader = screen.getByText("Test task") - fireEvent.click(taskHeader) - - // Find the button that contains the FoldVertical icon + // Button is disabled in collapsed state without expanding first const buttons = screen.getAllByRole("button") const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) expect(condenseButton).toBeDefined() From ff85f672daa7826b1805bfbe9327c6dbfec57654 Mon Sep 17 00:00:00 2001 From: awschmeder Date: Sun, 21 Jun 2026 10:31:07 -0700 Subject: [PATCH 2/3] feat(webview): replace FoldVertical with ListChevronsDownUp/ScissorsLineDashed, bump lucide-react to ^1.18.0 --- pnpm-lock.yaml | 10 +++++----- webview-ui/package.json | 2 +- webview-ui/src/components/chat/TaskHeader.tsx | 4 ++-- .../chat/context-management/CondensationResultRow.tsx | 4 ++-- .../chat/context-management/TruncationResultRow.tsx | 4 ++-- .../components/settings/ContextManagementSettings.tsx | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9129571e93..a88d579e95 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -851,8 +851,8 @@ importers: specifier: ^11.1.0 version: 11.1.0 lucide-react: - specifier: ^0.518.0 - version: 0.518.0(react@18.3.1) + specifier: ^1.18.0 + version: 1.21.0(react@18.3.1) mermaid: specifier: ^11.4.1 version: 11.15.0 @@ -6671,8 +6671,8 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - lucide-react@0.518.0: - resolution: {integrity: sha512-kFg34uQqnVl/7HwAiigxPSpj//43VIVHQbMygQPtS1yT4btMXHCWUipHcgcXHD2pm1Z2nUBA/M+Vnh/YmWXQUw==} + lucide-react@1.21.0: + resolution: {integrity: sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -15848,7 +15848,7 @@ snapshots: dependencies: yallist: 4.0.0 - lucide-react@0.518.0(react@18.3.1): + lucide-react@1.21.0(react@18.3.1): dependencies: react: 18.3.1 diff --git a/webview-ui/package.json b/webview-ui/package.json index c797f75833..e16c981450 100644 --- a/webview-ui/package.json +++ b/webview-ui/package.json @@ -50,7 +50,7 @@ "i18next": "^25.0.0", "katex": "^0.16.11", "lru-cache": "^11.1.0", - "lucide-react": "^0.518.0", + "lucide-react": "^1.18.0", "mermaid": "^11.4.1", "posthog-js": "^1.227.2", "pretty-bytes": "^7.0.0", diff --git a/webview-ui/src/components/chat/TaskHeader.tsx b/webview-ui/src/components/chat/TaskHeader.tsx index e596c72131..c59813eb91 100644 --- a/webview-ui/src/components/chat/TaskHeader.tsx +++ b/webview-ui/src/components/chat/TaskHeader.tsx @@ -1,6 +1,6 @@ import { memo, useRef, useState, useMemo } from "react" import { useTranslation } from "react-i18next" -import { ChevronUp, ChevronDown, HardDriveDownload, HardDriveUpload, FoldVertical, ArrowLeft } from "lucide-react" +import { ChevronUp, ChevronDown, HardDriveDownload, HardDriveUpload, ListChevronsDownUp, ArrowLeft } from "lucide-react" import prettyBytes from "pretty-bytes" import type { ClineMessage } from "@roo-code/types" @@ -81,7 +81,7 @@ const TaskHeader = ({ const condenseButton = ( currentTaskItem && handleCondenseContext(currentTaskItem.id)} /> diff --git a/webview-ui/src/components/chat/context-management/CondensationResultRow.tsx b/webview-ui/src/components/chat/context-management/CondensationResultRow.tsx index 526ebebbe7..e9a9cfdf09 100644 --- a/webview-ui/src/components/chat/context-management/CondensationResultRow.tsx +++ b/webview-ui/src/components/chat/context-management/CondensationResultRow.tsx @@ -1,7 +1,7 @@ import { useState } from "react" import { useTranslation } from "react-i18next" import { VSCodeBadge } from "@vscode/webview-ui-toolkit/react" -import { FoldVertical } from "lucide-react" +import { ListChevronsDownUp } from "lucide-react" import type { ContextCondense } from "@roo-code/types" @@ -32,7 +32,7 @@ export function CondensationResultRow({ data }: CondensationResultRowProps) { className="flex items-center justify-between cursor-pointer select-none" onClick={() => setIsExpanded(!isExpanded)}>
- + {t("chat:contextManagement.condensation.title")} diff --git a/webview-ui/src/components/chat/context-management/TruncationResultRow.tsx b/webview-ui/src/components/chat/context-management/TruncationResultRow.tsx index ec6a32f316..625c850161 100644 --- a/webview-ui/src/components/chat/context-management/TruncationResultRow.tsx +++ b/webview-ui/src/components/chat/context-management/TruncationResultRow.tsx @@ -1,6 +1,6 @@ import { useState } from "react" import { useTranslation } from "react-i18next" -import { FoldVertical } from "lucide-react" +import { ScissorsLineDashed } from "lucide-react" import type { ContextTruncation } from "@roo-code/types" @@ -33,7 +33,7 @@ export function TruncationResultRow({ data }: TruncationResultRowProps) { className="flex items-center justify-between cursor-pointer select-none" onClick={() => setIsExpanded(!isExpanded)}>
- + {t("chat:contextManagement.truncation.title")} diff --git a/webview-ui/src/components/settings/ContextManagementSettings.tsx b/webview-ui/src/components/settings/ContextManagementSettings.tsx index 8663ea6e03..8a6fa079ff 100644 --- a/webview-ui/src/components/settings/ContextManagementSettings.tsx +++ b/webview-ui/src/components/settings/ContextManagementSettings.tsx @@ -2,7 +2,7 @@ import { HTMLAttributes } from "react" import React from "react" import { useAppTranslation } from "@/i18n/TranslationContext" import { VSCodeCheckbox, VSCodeTextArea } from "@vscode/webview-ui-toolkit/react" -import { FoldVertical } from "lucide-react" +import { ListChevronsDownUp } from "lucide-react" import { supportPrompt } from "@roo/support-prompt" @@ -487,7 +487,7 @@ export const ContextManagementSettings = ({ {autoCondenseContext && (
- +
{t("settings:contextManagement.condensingThreshold.label")}
From a7c61633795b1c823ac88e083aae2a5543ccf47a Mon Sep 17 00:00:00 2001 From: awschmeder Date: Sun, 21 Jun 2026 11:04:08 -0700 Subject: [PATCH 3/3] fix(test): update SVG selector from lucide-fold-vertical to lucide-list-chevrons-down-up --- .../src/components/chat/__tests__/TaskHeader.spec.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx b/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx index fd0513bfb0..dfa30d1982 100644 --- a/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/TaskHeader.spec.tsx @@ -137,7 +137,7 @@ describe("TaskHeader", () => { renderTaskHeader() // Button is visible without expanding the task header const buttons = screen.getAllByRole("button") - const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) + const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-list-chevrons-down-up")) expect(condenseButton).toBeDefined() expect(condenseButton?.querySelector("svg")).toBeInTheDocument() }) @@ -148,7 +148,7 @@ describe("TaskHeader", () => { fireEvent.click(taskHeader) const buttons = screen.getAllByRole("button") - const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) + const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-list-chevrons-down-up")) expect(condenseButton).toBeDefined() expect(condenseButton?.querySelector("svg")).toBeInTheDocument() }) @@ -159,7 +159,7 @@ describe("TaskHeader", () => { // Button is clickable in collapsed state without expanding first const buttons = screen.getAllByRole("button") - const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) + const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-list-chevrons-down-up")) expect(condenseButton).toBeDefined() fireEvent.click(condenseButton!) expect(handleCondenseContext).toHaveBeenCalledWith("test-task-id") @@ -171,7 +171,7 @@ describe("TaskHeader", () => { // Button is disabled in collapsed state without expanding first const buttons = screen.getAllByRole("button") - const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-fold-vertical")) + const condenseButton = buttons.find((button) => button.querySelector("svg.lucide-list-chevrons-down-up")) expect(condenseButton).toBeDefined() expect(condenseButton).toBeDisabled() fireEvent.click(condenseButton!)