Skip to content

Commit 3c937c3

Browse files
authored
Task header theme fixes (#2721)
1 parent b077267 commit 3c937c3

File tree

6 files changed

+85
-135
lines changed

6 files changed

+85
-135
lines changed

evals/packages/db/scripts/copy-run.mts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,17 @@ const copyRun = async (runId: number) => {
5757
tasks,
5858
async (task) => {
5959
// eslint-disable-next-line @typescript-eslint/no-unused-vars
60-
const { id: _, ...newTaskMetricsValues } = task.taskMetrics!
60+
const { id: _, ...newTaskMetricsValues } = task.taskMetrics || {
61+
duration: 0,
62+
tokensIn: 0,
63+
tokensOut: 0,
64+
tokensContext: 0,
65+
cacheWrites: 0,
66+
cacheReads: 0,
67+
cost: 0,
68+
createdAt: new Date(),
69+
}
70+
6171
const [newTaskMetrics] = await destDb.insert(schema.taskMetrics).values(newTaskMetricsValues).returning()
6272

6373
if (!newTaskMetrics) {

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 18 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
2-
import deepEqual from "fast-deep-equal"
31
import React, { memo, useEffect, useMemo, useRef, useState } from "react"
42
import { useSize } from "react-use"
5-
import { useCopyToClipboard } from "../../utils/clipboard"
63
import { useTranslation, Trans } from "react-i18next"
4+
import deepEqual from "fast-deep-equal"
5+
import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
6+
7+
import { Button } from "@/components/ui"
8+
9+
import { useCopyToClipboard } from "../../utils/clipboard"
710
import { safeJsonParse } from "../../utils/json"
811
import {
912
ClineApiReqInfo,
@@ -25,7 +28,7 @@ import McpResourceRow from "../mcp/McpResourceRow"
2528
import McpToolRow from "../mcp/McpToolRow"
2629
import { highlightMentions } from "./TaskHeader"
2730
import { CheckpointSaved } from "./checkpoints/CheckpointSaved"
28-
import FollowUpSuggest from "./FollowUpSuggest"
31+
import { FollowUpSuggest } from "./FollowUpSuggest"
2932

3033
interface ChatRowProps {
3134
message: ClineMessage
@@ -230,7 +233,8 @@ export const ChatRowContent = ({
230233
return [
231234
<span
232235
className="codicon codicon-question"
233-
style={{ color: normalColor, marginBottom: "-1.5px" }}></span>,
236+
style={{ color: normalColor, marginBottom: "-1.5px" }}
237+
/>,
234238
<span style={{ color: normalColor, fontWeight: "bold" }}>{t("chat:questions.hasQuestion")}</span>,
235239
]
236240
default:
@@ -795,39 +799,6 @@ export const ChatRowContent = ({
795799
</>
796800
)}
797801
</p>
798-
799-
{/* {apiProvider === "" && (
800-
<div
801-
style={{
802-
display: "flex",
803-
alignItems: "center",
804-
backgroundColor:
805-
"color-mix(in srgb, var(--vscode-errorForeground) 20%, transparent)",
806-
color: "var(--vscode-editor-foreground)",
807-
padding: "6px 8px",
808-
borderRadius: "3px",
809-
margin: "10px 0 0 0",
810-
fontSize: "12px",
811-
}}>
812-
<i
813-
className="codicon codicon-warning"
814-
style={{
815-
marginRight: 6,
816-
fontSize: 16,
817-
color: "var(--vscode-errorForeground)",
818-
}}></i>
819-
<span>
820-
Uh-oh, this could be a problem on end. We've been alerted and
821-
will resolve this ASAP. You can also{" "}
822-
<a
823-
href=""
824-
style={{ color: "inherit", textDecoration: "underline" }}>
825-
contact us
826-
</a>
827-
.
828-
</span>
829-
</div>
830-
)} */}
831802
</>
832803
)}
833804

@@ -853,46 +824,19 @@ export const ChatRowContent = ({
853824
)
854825
case "user_feedback":
855826
return (
856-
<div
857-
className="outline rounded p-4"
858-
style={{
859-
color: "var(--vscode-badge-foreground)",
860-
padding: "4px",
861-
overflow: "hidden",
862-
whiteSpace: "pre-wrap",
863-
wordBreak: "break-word",
864-
overflowWrap: "anywhere",
865-
}}>
866-
<div
867-
style={{
868-
display: "flex",
869-
justifyContent: "space-between",
870-
alignItems: "flex-start",
871-
gap: "10px",
872-
}}>
873-
<span style={{ display: "block", flexGrow: 1, padding: "4px" }}>
874-
{highlightMentions(message.text)}
875-
</span>
876-
<VSCodeButton
877-
appearance="icon"
878-
style={{
879-
padding: "3px",
880-
flexShrink: 0,
881-
height: "24px",
882-
marginTop: "-3px",
883-
marginBottom: "-3px",
884-
marginRight: "-6px",
885-
}}
827+
<div className="bg-vscode-editor-background border rounded-xs p-1 overflow-hidden whitespace-pre-wrap word-break-break-word overflow-wrap-anywhere">
828+
<div className="flex justify-between gap-2">
829+
<div className="flex-grow px-2 py-1">{highlightMentions(message.text)}</div>
830+
<Button
831+
variant="ghost"
832+
size="icon"
886833
disabled={isStreaming}
887834
onClick={(e) => {
888835
e.stopPropagation()
889-
vscode.postMessage({
890-
type: "deleteMessage",
891-
value: message.ts,
892-
})
836+
vscode.postMessage({ type: "deleteMessage", value: message.ts })
893837
}}>
894-
<span className="codicon codicon-trash"></span>
895-
</VSCodeButton>
838+
<span className="codicon codicon-trash" />
839+
</Button>
896840
</div>
897841
{message.images && message.images.length > 0 && (
898842
<Thumbnails images={message.images} style={{ marginTop: "8px" }} />
Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useCallback } from "react"
2-
import { cn } from "../../lib/utils"
3-
import { Button } from "../ui/button"
4-
import { Edit } from "lucide-react"
2+
import { ArrowRight, Edit } from "lucide-react"
3+
4+
import { Button } from "@/components/ui"
5+
56
import { useAppTranslation } from "../../i18n/TranslationContext"
67

78
interface FollowUpSuggestProps {
@@ -10,7 +11,7 @@ interface FollowUpSuggestProps {
1011
ts: number
1112
}
1213

13-
const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: FollowUpSuggestProps) => {
14+
export const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: FollowUpSuggestProps) => {
1415
const { t } = useAppTranslation()
1516
const handleSuggestionClick = useCallback(
1617
(suggestion: string, event: React.MouseEvent) => {
@@ -19,45 +20,39 @@ const FollowUpSuggest = ({ suggestions = [], onSuggestionClick, ts = 1 }: Follow
1920
[onSuggestionClick],
2021
)
2122

22-
// Don't render if there are no suggestions or no click handler
23+
// Don't render if there are no suggestions or no click handler.
2324
if (!suggestions?.length || !onSuggestionClick) {
2425
return null
2526
}
2627

2728
return (
28-
<div className="h-full">
29-
<div className="h-full scrollbar-thin scrollbar-thumb-vscode-scrollbarSlider-background scrollbar-track-transparent">
30-
<div className={cn("flex gap-2.5 pb-2 flex-col h-full")}>
31-
{suggestions.map((suggestion) => (
32-
<div key={`${suggestion}-${ts}`} className="w-full relative group">
33-
<Button
34-
variant="secondary"
35-
className="w-full text-left whitespace-normal break-words h-auto min-h-[28px] py-2 justify-start pr-8"
36-
onClick={(event) => handleSuggestionClick(suggestion, event)}
37-
aria-label={suggestion}>
38-
<span className="text-left">{suggestion}</span>
39-
</Button>
40-
<div
41-
className="absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity"
42-
onClick={(e) => {
43-
e.stopPropagation()
44-
// Simulate shift-click by directly calling the handler with shiftKey=true
45-
onSuggestionClick?.(suggestion, { ...e, shiftKey: true })
46-
}}
47-
title={t("chat:followUpSuggest.copyToInput")}>
48-
<Button
49-
variant="ghost"
50-
size="icon"
51-
className="h-6 w-6 p-1 hover:bg-vscode-button-hoverBackground">
52-
<Edit className="h-4 w-4" />
53-
</Button>
54-
</div>
29+
<div className="flex mb-2 flex-col h-full border rounded-xs">
30+
{suggestions.map((suggestion) => (
31+
<div key={`${suggestion}-${ts}`} className="w-full relative group">
32+
<Button
33+
variant="ghost"
34+
className="text-left whitespace-normal break-words w-full h-auto py-3 justify-start pr-8"
35+
onClick={(event) => handleSuggestionClick(suggestion, event)}
36+
aria-label={suggestion}>
37+
<div className="flex flex-row items-center gap-2">
38+
<ArrowRight />
39+
<div>{suggestion}</div>
5540
</div>
56-
))}
41+
</Button>
42+
<div
43+
className="absolute top-1 right-1 opacity-0 group-hover:opacity-100 transition-opacity"
44+
onClick={(e) => {
45+
e.stopPropagation()
46+
// Simulate shift-click by directly calling the handler with shiftKey=true.
47+
onSuggestionClick?.(suggestion, { ...e, shiftKey: true })
48+
}}
49+
title={t("chat:followUpSuggest.copyToInput")}>
50+
<Button variant="ghost" size="icon">
51+
<Edit />
52+
</Button>
53+
</div>
5754
</div>
58-
</div>
55+
))}
5956
</div>
6057
)
6158
}
62-
63-
export default FollowUpSuggest

webview-ui/src/components/chat/TaskHeader.tsx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import React, { memo, useMemo, useRef, useState } from "react"
22
import { useWindowSize } from "react-use"
3-
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
43
import prettyBytes from "pretty-bytes"
54
import { useTranslation } from "react-i18next"
65

76
import { vscode } from "@/utils/vscode"
87
import { formatLargeNumber } from "@/utils/format"
98
import { calculateTokenDistribution, getMaxTokensForModel } from "@/utils/model-utils"
10-
import { Button } from "@/components/ui"
9+
import { Button, Badge } from "@/components/ui"
1110

1211
import { ClineMessage } from "../../../../src/shared/ExtensionMessage"
1312
import { mentionRegexGlobal } from "../../../../src/shared/context-mentions"
@@ -17,6 +16,7 @@ import { useExtensionState } from "../../context/ExtensionStateContext"
1716
import Thumbnails from "../common/Thumbnails"
1817
import { normalizeApiConfiguration } from "../settings/ApiOptions"
1918
import { DeleteTaskDialog } from "../history/DeleteTaskDialog"
19+
import { cn } from "@/lib/utils"
2020

2121
interface TaskHeaderProps {
2222
task: ClineMessage
@@ -55,10 +55,15 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
5555
const shouldShowPromptCacheInfo = doesModelSupportPromptCache && apiConfiguration?.apiProvider !== "openrouter"
5656

5757
return (
58-
<div className="py-[10px] px-[13px]">
58+
<div className="py-2 px-3">
5959
<div
60-
className={`rounded p-[10px] flex flex-col gap-[6px] relative z-1 outline hover:outline-vscode-badge-foreground hover:text-vscode-badge-foreground transition-color duration-500 ${!!isTaskExpanded ? "outline-vscode-badge-foreground text-vscode-badge-foreground" : "outline-vscode-badge-foreground/80 text-vscode-badge-foreground/80"}`}>
61-
<div className="flex justify-between items-center">
60+
className={cn(
61+
"rounded-xs p-2.5 flex flex-col gap-1.5 relative z-1 border",
62+
!!isTaskExpanded
63+
? "border-vscode-panel-border text-vscode-foreground"
64+
: "border-vscode-panel-border/80 text-vscode-foreground/80",
65+
)}>
66+
<div className="flex justify-between items-center gap-2">
6267
<div
6368
className="flex items-center cursor-pointer -ml-0.5 select-none grow min-w-0"
6469
onClick={() => setIsTaskExpanded(!isTaskExpanded)}>
@@ -73,14 +78,14 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
7378
{!isTaskExpanded && <span className="ml-1">{highlightMentions(task.text, false)}</span>}
7479
</div>
7580
</div>
76-
77-
<VSCodeButton
78-
appearance="icon"
81+
<Button
82+
variant="ghost"
83+
size="icon"
7984
onClick={onClose}
80-
className="ml-1.5 shrink-0 text-vscode-badge-foreground"
81-
title={t("chat:task.closeAndStart")}>
82-
<span className="codicon codicon-close"></span>
83-
</VSCodeButton>
85+
title={t("chat:task.closeAndStart")}
86+
className="shrink-0 w-5 h-5">
87+
<span className="codicon codicon-close" />
88+
</Button>
8489
</div>
8590
{/* Collapsed state: Track context and cost if we have any */}
8691
{!isTaskExpanded && contextWindow > 0 && (
@@ -90,11 +95,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
9095
contextTokens={contextTokens || 0}
9196
maxTokens={getMaxTokensForModel(selectedModelInfo, apiConfiguration)}
9297
/>
93-
{!!totalCost && (
94-
<div className="ml-2.5 bg-vscode-editor-foreground text-vscode-editor-background py-0.5 px-1 rounded-full text-[11px] font-medium inline-block shrink-0">
95-
${totalCost?.toFixed(2)}
96-
</div>
97-
)}
98+
{!!totalCost && <Badge>${totalCost.toFixed(2)}</Badge>}
9899
</div>
99100
)}
100101
{/* Expanded state: Show task text and images */}
@@ -271,7 +272,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
271272
<div className="flex-1 relative">
272273
{/* Invisible overlay for hover area */}
273274
<div
274-
className="absolute w-full cursor-pointer h-4 -top-[7px] z-5"
275+
className="absolute w-full h-4 -top-[7px] z-5"
275276
title={t("chat:tokenProgress.availableSpace", { amount: formatLargeNumber(availableSize) })}
276277
data-testid="context-available-space"
277278
/>
@@ -282,7 +283,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
282283
<div className="relative h-full" style={{ width: `${currentPercent}%` }}>
283284
{/* Invisible overlay for current tokens section */}
284285
<div
285-
className="absolute cursor-pointer h-4 -top-[7px] w-full z-6"
286+
className="absolute h-4 -top-[7px] w-full z-6"
286287
title={t("chat:tokenProgress.tokensUsed", {
287288
used: formatLargeNumber(safeContextTokens),
288289
total: formatLargeNumber(safeContextWindow),
@@ -297,7 +298,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
297298
<div className="relative h-full" style={{ width: `${reservedPercent}%` }}>
298299
{/* Invisible overlay for reserved section */}
299300
<div
300-
className="absolute cursor-pointer h-4 -top-[7px] w-full z-6"
301+
className="absolute h-4 -top-[7px] w-full z-6"
301302
title={t("chat:tokenProgress.reservedForResponse", {
302303
amount: formatLargeNumber(reservedForOutput),
303304
})}
@@ -312,7 +313,7 @@ const ContextWindowProgress = ({ contextWindow, contextTokens, maxTokens }: Cont
312313
<div className="relative h-full" style={{ width: `${availablePercent}%` }}>
313314
{/* Invisible overlay for available space */}
314315
<div
315-
className="absolute cursor-pointer h-4 -top-[7px] w-full z-6"
316+
className="absolute h-4 -top-[7px] w-full z-6"
316317
title={t("chat:tokenProgress.availableSpace", {
317318
amount: formatLargeNumber(availableSize),
318319
})}

webview-ui/src/components/ui/badge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority"
44
import { cn } from "@/lib/utils"
55

66
const badgeVariants = cva(
7-
"inline-flex items-center rounded-xs border border-transparent shadow px-2 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
7+
"inline-flex items-center rounded-full border border-transparent px-2 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
88
{
99
variants: {
1010
variant: {

webview-ui/src/components/ui/button.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ import { cva, type VariantProps } from "class-variance-authority"
55
import { cn } from "@/lib/utils"
66

77
const buttonVariants = cva(
8-
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer",
8+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-80",
99
{
1010
variants: {
1111
variant: {
1212
default:
1313
"border border-vscode-input-border bg-primary text-primary-foreground shadow hover:bg-primary/90",
1414
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
1515
outline:
16-
"border border-vscode-input-border bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
16+
"border border-vscode-input-border bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
1717
secondary:
1818
"border border-vscode-input-border bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
1919
ghost: "hover:bg-accent hover:text-accent-foreground",

0 commit comments

Comments
 (0)