diff --git a/apps/web/src/components/ChatMarkdown.tsx b/apps/web/src/components/ChatMarkdown.tsx index 6a85ccee96a..e92d4dfb1ec 100644 --- a/apps/web/src/components/ChatMarkdown.tsx +++ b/apps/web/src/components/ChatMarkdown.tsx @@ -180,15 +180,21 @@ function MarkdownCodeBlock({ code, children }: { code: string; children: ReactNo return (
- + + + } + > + {copied ? : } + + {copied ? "Copied" : "Copy code"} + {children}
); @@ -489,7 +495,7 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ side="top" className="max-w-[min(40rem,calc(100vw-2rem))] font-mono text-[11px] leading-tight" > -
+
{displayPath}
diff --git a/apps/web/src/components/ChatView.browser.tsx b/apps/web/src/components/ChatView.browser.tsx index bb62d8edbc0..f73e4ae9f04 100644 --- a/apps/web/src/components/ChatView.browser.tsx +++ b/apps/web/src/components/ChatView.browser.tsx @@ -2250,7 +2250,7 @@ describe("ChatView timeline estimator parity (full app)", () => { const runButton = await waitForElement( () => Array.from(document.querySelectorAll("button")).find( - (button) => button.title === "Run Lint", + (button) => button.getAttribute("aria-label") === "Run Lint", ) as HTMLButtonElement | null, "Unable to find Run Lint button.", ); @@ -2329,7 +2329,7 @@ describe("ChatView timeline estimator parity (full app)", () => { const runButton = await waitForElement( () => Array.from(document.querySelectorAll("button")).find( - (button) => button.title === "Run Test", + (button) => button.getAttribute("aria-label") === "Run Test", ) as HTMLButtonElement | null, "Unable to find Run Test button.", ); @@ -3068,8 +3068,7 @@ describe("ChatView timeline estimator parity (full app)", () => { }); try { - const initialModeButton = await waitForInteractionModeButton("Build"); - expect(initialModeButton.title).toContain("enter plan mode"); + await waitForInteractionModeButton("Build"); window.dispatchEvent( new KeyboardEvent("keydown", { @@ -3081,7 +3080,7 @@ describe("ChatView timeline estimator parity (full app)", () => { ); await waitForLayout(); - expect((await waitForInteractionModeButton("Build")).title).toContain("enter plan mode"); + await waitForInteractionModeButton("Build"); const composerEditor = await waitForComposerEditor(); composerEditor.focus(); @@ -3096,9 +3095,7 @@ describe("ChatView timeline estimator parity (full app)", () => { await vi.waitFor( async () => { - expect((await waitForInteractionModeButton("Plan")).title).toContain( - "return to normal build mode", - ); + expect(await waitForInteractionModeButton("Plan")).toBeTruthy(); }, { timeout: 8_000, interval: 16 }, ); @@ -3114,7 +3111,7 @@ describe("ChatView timeline estimator parity (full app)", () => { await vi.waitFor( async () => { - expect((await waitForInteractionModeButton("Build")).title).toContain("enter plan mode"); + expect(await waitForInteractionModeButton("Build")).toBeTruthy(); }, { timeout: 8_000, interval: 16 }, ); diff --git a/apps/web/src/components/DiffPanel.tsx b/apps/web/src/components/DiffPanel.tsx index f178a69fb43..c85ac32a026 100644 --- a/apps/web/src/components/DiffPanel.tsx +++ b/apps/web/src/components/DiffPanel.tsx @@ -39,6 +39,7 @@ import { useSettings } from "../hooks/useSettings"; import { formatShortTimestamp } from "../timestampFormat"; import { DiffPanelLoadingState, DiffPanelShell, type DiffPanelMode } from "./DiffPanelShell"; import { ToggleGroup, Toggle } from "./ui/toggle-group"; +import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; type DiffRenderMode = "stacked" | "split"; type DiffThemeType = "light" | "dark"; @@ -534,35 +535,41 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) {
{orderedTurnDiffSummaries.map((summary) => ( - + + {summary.turnId} + ))} @@ -586,30 +593,50 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { - { - setDiffWordWrap(Boolean(pressed)); - }} - > - - - { - setDiffIgnoreWhitespace(Boolean(pressed)); - }} - > - - + + { + setDiffWordWrap(Boolean(pressed)); + }} + /> + } + > + + + + {diffWordWrap ? "Disable line wrapping" : "Enable line wrapping"} + + + + { + setDiffIgnoreWhitespace(Boolean(pressed)); + }} + /> + } + > + + + + {diffIgnoreWhitespace ? "Show whitespace changes" : "Hide whitespace changes"} + + ); @@ -683,26 +710,36 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { ( - + + { + event.stopPropagation(); + toggleDiffFileCollapsed(fileKey); + }} + /> + } + > + {collapsed ? ( + + ) : ( + + )} + + + {collapsed ? "Expand diff" : "Collapse diff"} + + )} options={{ collapsed, diff --git a/apps/web/src/components/ProjectScriptsControl.tsx b/apps/web/src/components/ProjectScriptsControl.tsx index 4a9cda19d65..92e41cfa887 100644 --- a/apps/web/src/components/ProjectScriptsControl.tsx +++ b/apps/web/src/components/ProjectScriptsControl.tsx @@ -53,6 +53,7 @@ import { Menu, MenuItem, MenuPopup, MenuShortcut, MenuTrigger } from "./ui/menu" import { Popover, PopoverPopup, PopoverTrigger } from "./ui/popover"; import { Switch } from "./ui/switch"; import { Textarea } from "./ui/textarea"; +import { Tooltip, TooltipPopup, TooltipTrigger } from "./ui/tooltip"; const SCRIPT_ICONS: Array<{ id: ProjectScriptIcon; label: string }> = [ { id: "play", label: "Play" }, @@ -219,17 +220,24 @@ export default function ProjectScriptsControl({ <> {primaryScript ? ( - + + onRunScript(primaryScript)} + aria-label={`Run ${primaryScript.name}`} + /> + } + > + + + {primaryScript.name} + + + {`Run ${primaryScript.name}`} + ) : ( - + + + } + > + + + Add action + + + Add action + )}
{terminalStatus && ( - - - + + + } + > + + + {terminalStatus.label} + )}
)} {jumpLabel ? ( - - {jumpLabel} - + + + } + > + {jumpLabel} + + + {jumpLabel} + + ) : ( {!projectExpanded && projectStatus ? ( -