AI 任務計畫追蹤(React)
agent 計畫清單的 React 元件:步驟由資料驅動在待辦→執行中→完成/失敗/略過間流轉,含工具圖示 chip、巢狀子步驟與連接線、目前步驟呼吸脈動、完成率與總耗時;狀態切換用 AnimatePresence 換圖示,新步驟從下方滑入。
像 agent 產品裡的 todo 追蹤面板:把 steps 資料丟進來,每一步依 status 顯示待處理空圈、執行中旋轉圈(整列微光呼吸)、完成打勾彈入、失敗叉、略過虛線圈;標題旁有工具 chip(工具名自動對到內建 lucide 圖示,可用 toolIcons 覆寫)與耗時,有說明或子步驟的列可展開,子步驟縮排並以左側連接線串起。頂部顯示完成率 x/y、三段式細進度條(完成/失敗/略過)與總耗時。元件不跑任何計時器——狀態全部由資料決定,你的 agent 回報什麼就畫什麼;狀態變化用 AnimatePresence 換圖示,新增的步驟從下方滑入。
npx shadcn@latest add https://webberui.com/r/ai-plan-steps.jsonPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<AiPlanSteps />
安裝
npx shadcn@latest add https://webberui.com/r/ai-plan-steps.json或在 components.json 設定 registries 後,改用 @webberui/ai-plan-steps 安裝。
使用
import { AiPlanSteps, type PlanStep } from "@/components/ui/ai-plan-steps";
const steps: PlanStep[] = [
{
id: "audit",
title: "盤點現有登入流程",
status: "done",
tool: "read",
durationMs: 1050,
children: [
{ id: "audit-read", title: "讀取 auth/ 目錄", status: "done", tool: "read", durationMs: 640 },
{ id: "audit-grep", title: "標記重複的驗證邏輯", status: "done", tool: "grep", durationMs: 410 },
],
},
{ id: "extract", title: "抽出共用的 validateCredentials()", status: "running", tool: "edit" },
{ id: "test", title: "執行單元測試", status: "pending", tool: "test" },
];
<AiPlanSteps
steps={steps}
title="任務計畫"
onStepClick={(step) => console.log(step.id)}
/>狀態流轉由你更新 steps 陣列驅動(例如 agent 每次回報就 setState 一次),元件只負責把差異畫成動畫。
Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
steps | PlanStep[] | — | 步驟資料(含巢狀 children);狀態流轉完全由這份資料驅動 |
title | string | "任務計畫" | 頂部標題文字;空字串則不顯示標題 |
toolIcons | Record<string, PlanToolIcon> | — | 工具名 → 圖示對照,會覆蓋同名的內建對照(鍵請用小寫) |
showProgress | boolean | true | 是否顯示頂部完成率(x/y)、細進度條與總耗時 |
collapsible | boolean | true | 有 detail 或子步驟的列是否可點擊收合;false 時永遠攤開且不顯示箭頭 |
defaultCollapsed | boolean | false | 非受控模式下,可收合的列一開始是否收合 |
expandedIds | string[] | — | 受控的展開清單(step id 陣列);提供時展開狀態完全由外部管理 |
onExpandedChange | (ids: string[]) => void | — | 展開清單變更時回呼,參數為變更後所有展開列的 id |
onStepClick | (step: PlanStep) => void | — | 點擊任一列時回呼(與收合互不影響) |
compact | boolean | false | 緊湊模式:較小的字級、間距與圖示,工具 chip 只留圖示 |
strikeDone | boolean | false | 已完成的步驟標題是否加刪除線 |
labels | Partial<AiPlanStepsLabels> | — | 覆寫介面文字(狀態朗讀字樣、完成率字樣、空狀態等) |
className | string | — | 透傳到最外層容器 |
PlanStep
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
id | string | — | 唯一識別,用於 React key、展開狀態與 aria-controls;建議只含英數、-、_ |
title | string | — | 步驟標題 |
status | "pending" | "running" | "done" | "failed" | "skipped" | — | 目前狀態 |
tool | string | — | 使用的工具名(如 read、bash);對應到 toolIcons 的圖示並顯示為 chip |
detail | string | — | 展開後顯示的補充說明(結果摘要、錯誤訊息等);失敗狀態以紅字顯示 |
durationMs | number | — | 耗時(毫秒);提供時顯示於列尾並計入總耗時 |
children | PlanStep[] | — | 子步驟;有子步驟或 detail 的列會出現展開箭頭 |
AiPlanStepsLabels
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
pending | string | "待處理" | 待處理狀態的朗讀文字 |
running | string | "執行中" | 執行中狀態的朗讀文字,也用於即時區域的「執行中:…」 |
done | string | "完成" | 完成狀態的朗讀文字 |
failed | string | "失敗" | 失敗狀態的朗讀文字 |
skipped | string | "略過" | 略過狀態的朗讀文字 |
progress | string | "已完成" | 完成率數字後的字樣 |
totalDuration | string | "總耗時" | 總耗時的無障礙標籤 |
empty | string | "尚無步驟" | 沒有任何步驟時顯示的文字 |
另外具名匯出 summarizePlanSteps(steps)(回傳扁平化後各狀態數量與總耗時)、formatPlanDuration(ms)(820ms / 1.4s / 12s / 1m 05s),以及 PlanStep、PlanStepStatus、PlanToolIcon、PlanSummary、AiPlanStepsLabels、AiPlanStepsProps 型別。
細節
- 內建工具圖示對照:
read、write、edit、search、grep、glob、bash、shell、terminal、web、fetch、browse、db、database、sql、git、test、build、deploy、code、think、plan。查找時先比對整個小寫名稱,再用「包含關鍵字」比對(read_file→read、web_search→search,長鍵優先),都沒中就顯示扳手圖示;用toolIcons傳入自己的對照即可覆寫或新增 - 完成率與總耗時:數量以整棵樹扁平化後計算(含所有層級的子步驟);總耗時則是父步驟自己有
durationMs就以父為準,沒有才加總子步驟,避免父子重複計算 - 展開狀態:非受控模式只記錄使用者動過的列,其餘依
defaultCollapsed推定,因此事後新增的步驟也套用同一個預設;需要記憶或同步時改用expandedIds+onExpandedChange受控 - 動畫:狀態圖示以
AnimatePresencepopLayout 換場(完成打勾用 spring 彈入)、執行中列疊一層淡藍底做呼吸、進度條寬度平滑過渡、新列以 layout 位置動畫從下方滑入、移除的列淡出後由其餘列補位;元件本身沒有任何 setTimeout/setInterval
可及性
- 最外層為
section並以標題aria-labelledby;清單用role="list"/role="listitem"(Safari 對list-style: none的清單會拿掉語意,明確標註才保得住),執行中的列加aria-current="step" - 可收合的列是原生
button(type="button"),帶aria-expanded與aria-controls指向說明區;鍵盤 Tab/Enter/Space 可操作,focus-visible有 ring - 每列標題後附僅供螢幕閱讀器的狀態文字(「(執行中)」等,可用
labels換語言);頂部另有role="status"的aria-live="polite"摘要,完成率或執行中步驟變化時會被朗讀 - 進度條為
role="progressbar",aria-valuenow為完成數、aria-valuemax為總步驟數 - 使用者系統開啟「減少動態效果」時,停用旋轉、呼吸、彈入、滑入與 layout 位移動畫,狀態切換只保留淡入淡出與顏色變化