feat(dashboard): generic <ToolCard> — header/pill/duration/caret #991

Merged
reviewer merged 1 commit from dev/960 into main 2026-05-08 19:09:06 +00:00
Collaborator

Generic <ToolCard> primitive every tool widget can compose into, matching Vercel AI Elements Tool ergonomics with Tokyo Night styling.

Test plan

  • just qa green (28 new Vitest tests pass: 6 snapshots per ToolCallState, open/closed policy per state, click-to-toggle x2, pill labels, target chip, duration, data-attrs)
  • Errors (output-error) and approvals (approval-requested, output-denied) render open by default
  • Successes (output-available) render collapsed by default
  • Streaming states (input-streaming, input-available) render open with spinner pill
  • Caret toggles open/closed; prefers-reduced-motion suppresses rotation animation
  • No raw <button> — caret uses <Button variant="ghost">

Closes #960

Generic `<ToolCard>` primitive every tool widget can compose into, matching Vercel AI Elements `Tool` ergonomics with Tokyo Night styling. ## Test plan - [ ] `just qa` green (28 new Vitest tests pass: 6 snapshots per `ToolCallState`, open/closed policy per state, click-to-toggle x2, pill labels, target chip, duration, data-attrs) - [ ] Errors (`output-error`) and approvals (`approval-requested`, `output-denied`) render open by default - [ ] Successes (`output-available`) render collapsed by default - [ ] Streaming states (`input-streaming`, `input-available`) render open with spinner pill - [ ] Caret toggles open/closed; `prefers-reduced-motion` suppresses rotation animation - [ ] No raw `<button>` — caret uses `<Button variant="ghost">` Closes #960
dev self-assigned this 2026-05-08 19:04:33 +00:00
feat(dashboard): generic <ToolCard> — header/pill/duration/caret (#960)
All checks were successful
qa / sql-layer-check (pull_request) Successful in 13s
qa / i18n-string-check (pull_request) Successful in 13s
qa / dockerfile (pull_request) Successful in 13s
qa / db-schema (pull_request) Successful in 16s
qa / qa-1 (pull_request) Successful in 2m21s
qa / qa (pull_request) Successful in 0s
986dbe8608
- ToolCard in apps/web/src/components/agent/tool-card.tsx
- ToolCardHeader: lucide icon per ToolKind, provider name, target chip,
  ToolCallState pill, live duration counter, caret toggle via <Button ghost>
- ToolCardBody: collapsible inputView/outputView slots (always mounted)
- Default-open for input-streaming, input-available, output-error,
  approval-requested, output-denied; collapsed for output-available
- motion-reduce:transition-none on caret rotation and body collapse
- 28 Vitest + RTL tests: snapshot per state, open/closed policy, click-toggle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dev requested review from reviewer 2026-05-08 19:07:36 +00:00
reviewer approved these changes 2026-05-08 19:09:02 +00:00
reviewer left a comment

All ACs met, CI green, 28 tests pass.

Nit: the caret <Button iconOnly> serialises as a self-closing <button /> in every snapshot — no <ChevronRight> SVG inside. The interaction tests prove the button works, so this is likely a jsdom/Lucide serialisation quirk rather than a runtime regression, but worth a quick visual spot-check in the browser to confirm the chevron actually renders.

All ACs met, CI green, 28 tests pass. Nit: the caret `<Button iconOnly>` serialises as a self-closing `<button />` in every snapshot — no `<ChevronRight>` SVG inside. The interaction tests prove the button works, so this is likely a jsdom/Lucide serialisation quirk rather than a runtime regression, but worth a quick visual spot-check in the browser to confirm the chevron actually renders.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!991
No description provided.