From 408d63013b6deff3a179d497992baaa6443fef69 Mon Sep 17 00:00:00 2001 From: yyyyaaa Date: Thu, 22 Oct 2026 10:15:59 +0700 Subject: [PATCH 1/2] feat(ai): page AskCard questions, add card eyebrows, and rail the tool trace - AskCard shows one question at a time with a footer pager, radio rows, and Skip/Continue on the right; `eyebrow` and `icon` props - ApprovalCard takes an `eyebrow` and uses a secondary skip button - ToolTrace hangs its calls from one continuous rail and gains an `error` status --- .../ui/src/components/ai/approval-card.tsx | 10 +- packages/ui/src/components/ai/ask-card.tsx | 172 +++++++++++------- packages/ui/src/components/ai/tool-trace.tsx | 22 ++- packages/ui/test/ai-ask-card.test.tsx | 25 +++ 4 files changed, 153 insertions(+), 76 deletions(-) diff --git a/packages/ui/src/components/ai/approval-card.tsx b/packages/ui/src/components/ai/approval-card.tsx index 14f1a382..ccc7b707 100644 --- a/packages/ui/src/components/ai/approval-card.tsx +++ b/packages/ui/src/components/ai/approval-card.tsx @@ -30,6 +30,8 @@ type ApprovalCardProps = { destructive?: boolean; /** Preview node under the title (tables, diffs, etc.). */ preview?: React.ReactNode; + /** A small line above the title in single-confirm mode, e.g. why the run paused. */ + eyebrow?: React.ReactNode; onConfirm?: (payload: { answers?: Record }) => void; onSkip?: () => void; onDismiss?: () => void; @@ -49,6 +51,7 @@ function ApprovalCard({ skipLabel = 'Skip', destructive = false, preview, + eyebrow, onConfirm, onSkip, onDismiss, @@ -135,6 +138,9 @@ function ApprovalCard({ >
+ {eyebrow ? ( +
{eyebrow}
+ ) : null} {title ? (
{title}
) : null} @@ -155,9 +161,9 @@ function ApprovalCard({ ) : null}
{preview ?
{preview}
: null} -
+
{onSkip ? ( - ) : null} diff --git a/packages/ui/src/components/ai/ask-card.tsx b/packages/ui/src/components/ai/ask-card.tsx index 5c9383a3..d1400628 100644 --- a/packages/ui/src/components/ai/ask-card.tsx +++ b/packages/ui/src/components/ai/ask-card.tsx @@ -1,6 +1,6 @@ 'use client'; -import { CircleCheck, CircleHelp } from 'lucide-react'; +import { ChevronDown, ChevronUp, CircleCheck, CircleHelp } from 'lucide-react'; import * as React from 'react'; import { cn } from '../../lib/utils'; @@ -34,32 +34,40 @@ type AskCardProps = Omit, 'onSubmit'> & { skipLabel?: React.ReactNode; /** Name and placeholder of the free-text row. */ otherLabel?: string; + /** A small line above the question, e.g. who is asking or why the run paused. */ + eyebrow?: React.ReactNode; + /** Glyph beside each question. Defaults to a help circle; `null` leaves the question bare, e.g. under an eyebrow. */ + icon?: React.ReactNode; disabled?: boolean; }; -const KEYS = 'ABCDEFGHIJ'; - -function QuestionHeading({ id, children }: { id?: string; children: React.ReactNode }) { +function QuestionHeading({ id, icon, children }: { id?: string; icon?: React.ReactNode; children: React.ReactNode }) { + const glyph = icon === undefined ? : icon; return ( -
-