@lotics/ui 5.3.0 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +29 -16
- package/examples/tpl_assistant.tsx +36 -24
- package/examples/tpl_extract.tsx +1 -1
- package/examples/tpl_lookup.tsx +1 -1
- package/examples/tpl_pick.tsx +22 -14
- package/examples/tpl_ratedesk.tsx +24 -19
- package/package.json +1 -2
- package/src/agent_progress.tsx +14 -4
- package/src/agent_run.tsx +128 -133
- package/src/animation_fade_in.tsx +12 -5
- package/src/change_review.tsx +128 -80
- package/src/share_or_download.test.ts +11 -0
- package/src/stepper.tsx +206 -65
- package/src/step_list.tsx +0 -128
package/AGENTS.md
CHANGED
|
@@ -75,16 +75,18 @@ Pick by capability, not by name. (→ the source file for the API.)
|
|
|
75
75
|
- **Files** — `FileDropzone`, `FileThumbnail` / `FileThumbnailGrid`, `FilePreview` /
|
|
76
76
|
`FileGalleryModal`, `ImageGallery`; for gated CRUD compose locally with `useSelectionMode` +
|
|
77
77
|
`shareOrDownloadFiles` + `rotateImageToBlob` (see §Data entry → Attachments).
|
|
78
|
-
- **Specialized work surfaces** — `ScanField` (scan/verify), `
|
|
79
|
-
|
|
80
|
-
`
|
|
78
|
+
- **Specialized work surfaces** — `ScanField` (scan/verify), `Stepper` (a guided run / progress
|
|
79
|
+
sequence — done · current · upcoming, horizontal OR vertical), `RemainderMeter` + `AllocationRow`
|
|
80
|
+
(allocation), `Timeline` (a heterogeneous event LOG — icons + expandable details, not progress),
|
|
81
|
+
`Calendar`, `Gantt`, `comments_thread`.
|
|
81
82
|
- **AI surfaces** — `Composer` (the adaptive command/chat composer — a compact pill when empty that
|
|
82
83
|
expands for long text + attachments; the surface that triggers agent work),
|
|
83
84
|
`AgentRun` (the live streaming work feed) + `AgentProgress` (its compact, floating, expandable
|
|
84
85
|
form — a composer's "working" state), `ReviewCard` (THE single-proposal review card — compositional
|
|
85
86
|
body via `children`: a `RecordFields` record (header-first) or a `MatchSides` pairing (body-first))
|
|
86
|
-
+ `Confidence`; `ChangeReview` (the BATCH review
|
|
87
|
-
`renderItem`, with `ChangeDiff` for the before→after body),
|
|
87
|
+
+ `Confidence`; `ChangeReview` (the BATCH review list — whole-set OR 1-by-1; compositional via
|
|
88
|
+
`renderItem`, with `ChangeDiff` for the before→after body) + `ChangeReviewActions` (its commit bar,
|
|
89
|
+
pinned by the host in a `DialogFooter`/`DrawerFooter` or inline),
|
|
88
90
|
`Clarify` (the agent asks back — selectable `ChoiceList` options),
|
|
89
91
|
`Sources` (provenance chips for AI output). For STRUCTURED AI output the review
|
|
90
92
|
surfaces above don't cover: `SpecList` (the "exact breakdown" — a labeled-value spec sheet, the
|
|
@@ -263,9 +265,13 @@ Compose the surfaces as a loop, and reach for the right one by job:
|
|
|
263
265
|
attaching HOLDS the file for review; the human presses Send. The canvas (`tpl_dieline`) uses it this
|
|
264
266
|
way; while running the host swaps `Composer` for `AgentProgress` (same pill geometry, so it reads as
|
|
265
267
|
a morph).
|
|
266
|
-
- **Show the work** — `AgentRun`: a live feed of the agent's
|
|
267
|
-
|
|
268
|
-
|
|
268
|
+
- **Show the work** — `AgentRun`: a live feed of the agent's work — its streamed narration (with a
|
|
269
|
+
blinking caret) + tool calls as a vertical `Stepper` of neutral dots (the latest pulsing while live,
|
|
270
|
+
a white-check dot once done). No title, no avatar — just the work. A terminal "Done" step (the
|
|
271
|
+
`complete` node) appears ONLY once the run finishes. A step can carry `peek` content to glance into
|
|
272
|
+
via a popover. Tool labels resolve from the raw tool name via a built-in default map + an optional
|
|
273
|
+
`labelForTool` override (localize THERE — the kit stays English). `doneLabel` localizes the terminal.
|
|
274
|
+
Transparent work, NEVER a bare spinner — the
|
|
269
275
|
intelligence is legible. On a canvas/composer app reach for `AgentProgress` — `AgentRun`
|
|
270
276
|
collapsed into a floating pill (avatar + current step) that EXPANDS on press; the composer
|
|
271
277
|
morphs into it while running, and reveals again when done.
|
|
@@ -281,8 +287,13 @@ Compose the surfaces as a loop, and reach for the right one by job:
|
|
|
281
287
|
→ `tpl_match`). Stack several (rank by confidence) for a shortlist or a document's records.
|
|
282
288
|
- **`ChangeReview`** — THE batch engine for a SET you decide each then commit together. `renderItem`
|
|
283
289
|
draws each proposal (a `ChangeDiff` before→after body, a record, an editable form), 1-by-1
|
|
284
|
-
Keep/Drop collapses each
|
|
285
|
-
|
|
290
|
+
Keep/Drop collapses each (e.g. ingested rate lines — `tpl_ratedesk`); whole-set mode reviews the
|
|
291
|
+
lot. It is the LIST only — the commit bar (Accept all / Apply / Discard) is the SEPARATE
|
|
292
|
+
**`ChangeReviewActions`**, which the host places where commit bars belong (a `DialogFooter` /
|
|
293
|
+
`DrawerFooter`, or inline under the list). Don't bundle a commit into a scroll body — like every
|
|
294
|
+
other footer in the kit it's the container's to pin (`tpl_ratedesk` puts it in the `DialogFooter`).
|
|
295
|
+
`ChangeReviewActions` reads the same `items`/`statusOf`, so it owns Accept-all + the kept count —
|
|
296
|
+
never re-derive them in the host.
|
|
286
297
|
The body atoms (`RecordFields`, `MatchSides`, `ChangeDiff`) are pure presentation — usable inside
|
|
287
298
|
either engine OR standalone (a live-edit field card). The decide / accept-all / apply mechanics are
|
|
288
299
|
never re-implemented per surface.
|
|
@@ -359,9 +370,11 @@ controls — while **status/severity/diffs use functional colour** the way the r
|
|
|
359
370
|
- **Confidence** — a 3-tick meter + word, emerald / amber / zinc by level.
|
|
360
371
|
- **Finding severity** — a coloured dot `Badge` + metric: red critical, amber warning, blue note,
|
|
361
372
|
emerald on-track (+ stacking order, most severe first).
|
|
362
|
-
- **AgentRun** —
|
|
363
|
-
|
|
364
|
-
|
|
373
|
+
- **Stepper / AgentRun nodes** — progress dots on a spine: `current` a **pulsing accent ring** (white
|
|
374
|
+
centre), `done` a filled accent dot + **white check**, `upcoming` a faint **grey** ring, the terminal
|
|
375
|
+
`complete` a **blackish ring + black check**, `warning` **amber**. Default accent is neutral ink
|
|
376
|
+
(`color` themes it); `AgentRun` keeps the neutral default + appends the `complete` "Done" node only
|
|
377
|
+
when the run finishes.
|
|
365
378
|
- **ChangeReview diffs** — the old value struck in **red**, the new value in **green**.
|
|
366
379
|
- **Discrepancy** — the agent's pick gets a **blue** highlight; `Mismatch` reads amber, `Resolved`
|
|
367
380
|
emerald.
|
|
@@ -578,8 +591,8 @@ inline_time_picker (the Inline* family — per-field editors on `inline_edit`'s
|
|
|
578
591
|
list · list_item · menu_button · menu_list_item · detail_row · pressable_row · action_menu ·
|
|
579
592
|
floating_action_bar · filter_pill · column_filter (ColumnFilter — the typed per-column filter pill +
|
|
580
593
|
columnFilterToConditions; for a register filtering on several columns) · chip_group · search_input ·
|
|
581
|
-
sort_header · table · pagination · accordion · stepper ·
|
|
582
|
-
step_progress ·
|
|
594
|
+
sort_header · table · pagination · accordion · stepper (Stepper + Step — done/current/upcoming/warning/complete progress on a track (horizontal) or spine (vertical); compound `<Step status>children` OR data `steps[]`+`current`; the guided-run / agent-feed primitive — subsumes the old StepList) ·
|
|
595
|
+
step_progress · timeline (heterogeneous event LOG — per-row icon + expandable details, models the past; NOT progress) · drawer (+ DrawerFooter) · dialog · popover · tooltip ·
|
|
583
596
|
command_menu · alert · peek · empty_state · completion_state · callout (Callout · CalloutTitle ·
|
|
584
597
|
CalloutText · CalloutActions) · kpi_card · kpi_strip · metric · trend_chip · sparkline ·
|
|
585
598
|
bar_chart · line_chart · pie_chart · ring_gauge · progress_bar · stacked_progress_bar · breakdown ·
|
|
@@ -590,7 +603,7 @@ spacer · stack · section_card · page_header · page_content · calendar (cale
|
|
|
590
603
|
comments_thread · agent_run (live streaming work feed) · agent_progress (its compact floating
|
|
591
604
|
expandable form — a composer's working state) · composer (Composer — the adaptive command/chat
|
|
592
605
|
composer: a compact pill that expands for long text + attachments) · review_card (ReviewCard — THE single-proposal review card; compositional body via children + a generic actions footer; header-first with a title/eyebrow, body-first without) · confidence (calibrated high/med/low) ·
|
|
593
|
-
record_fields (RecordFields — the editable extracted-record BODY for a ReviewCard, or a standalone live-edit field card) · change_review (ChangeReview — the BATCH review
|
|
606
|
+
record_fields (RecordFields — the editable extracted-record BODY for a ReviewCard, or a standalone live-edit field card) · change_review (ChangeReview — the BATCH review LIST, whole-set OR 1-by-1; compositional `renderItem` body + the `ChangeDiff` before→after helper, `labels` localizes Undo/Applied/Discarded/counter — PLUS `ChangeReviewActions`, the separate commit bar the host pins in a `DialogFooter`/`DrawerFooter` or inline so it never scrolls away) ·
|
|
594
607
|
clarify (the agent asks back, via ChoiceList) · choice_list (ChoiceList — selectable answer options,
|
|
595
608
|
the agent's quick-reply surface) · sources (provenance chips, per-kind glyphs) · spec_list (SpecList — the exact
|
|
596
609
|
labeled-value breakdown, the panel of an answer) · match_sides (MatchSides — the two-sided pairing BODY for a body-first ReviewCard reconciliation; composable side slots + the MatchSideText default) ·
|
|
@@ -4,7 +4,7 @@ import { colors } from "@lotics/ui/colors";
|
|
|
4
4
|
import { Text } from "@lotics/ui/text";
|
|
5
5
|
import { DotsIndicator } from "@lotics/ui/dots_indicator";
|
|
6
6
|
import { Composer } from "@lotics/ui/composer";
|
|
7
|
-
import { ChangeReview, ChangeDiff, type ChangeReviewItemStatus } from "@lotics/ui/change_review";
|
|
7
|
+
import { ChangeReview, ChangeReviewActions, ChangeDiff, type ChangeReviewItemStatus } from "@lotics/ui/change_review";
|
|
8
8
|
|
|
9
9
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
10
10
|
// Template · AI assistant — a CHAT workflow, a different shape from the design
|
|
@@ -115,30 +115,42 @@ export function TplAssistant() {
|
|
|
115
115
|
) : null}
|
|
116
116
|
{m.text ? <Text size="sm">{m.text}</Text> : null}
|
|
117
117
|
{m.changes ? (
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
<
|
|
131
|
-
|
|
118
|
+
<View style={{ gap: 14 }}>
|
|
119
|
+
<ChangeReview
|
|
120
|
+
items={m.changes}
|
|
121
|
+
getKey={(c, i) => `${m.id}:${i}`}
|
|
122
|
+
statusOf={(_, i) => decisions[`${m.id}:${i}`] ?? "pending"}
|
|
123
|
+
renderItem={(c) => (
|
|
124
|
+
<>
|
|
125
|
+
<Text size="xs" color="muted" weight="medium">{c.label}</Text>
|
|
126
|
+
<ChangeDiff before={c.before} after={c.after} />
|
|
127
|
+
</>
|
|
128
|
+
)}
|
|
129
|
+
renderSummary={(c, kept) => (
|
|
130
|
+
<View style={{ flexDirection: "row", alignItems: "center", gap: 10 }}>
|
|
131
|
+
<Text size="sm" weight="medium" numberOfLines={1}>{c.label}</Text>
|
|
132
|
+
<Text size="sm" numberOfLines={1} color={kept ? "default" : "muted"} style={[{ flex: 1 }, kept ? undefined : { textDecorationLine: "line-through" }]}>{kept ? c.after : (c.before ?? c.after)}</Text>
|
|
133
|
+
</View>
|
|
134
|
+
)}
|
|
135
|
+
status={m.applied ? "applied" : "open"}
|
|
136
|
+
onAcceptItem={active ? (i) => decide(m.id, i, "accepted") : undefined}
|
|
137
|
+
onRejectItem={active ? (i) => decide(m.id, i, "rejected") : undefined}
|
|
138
|
+
onUndoItem={active ? (i) => setDecisions((d) => { const n = { ...d }; delete n[`${m.id}:${i}`]; return n; }) : undefined}
|
|
139
|
+
/>
|
|
140
|
+
{/* Inline (no dialog) — the commit bar sits under the list behind a divider. */}
|
|
141
|
+
{active && !m.applied ? (
|
|
142
|
+
<View style={{ borderTopWidth: 1, borderTopColor: colors.zinc[200], paddingTop: 14, flexDirection: "row" }}>
|
|
143
|
+
<ChangeReviewActions
|
|
144
|
+
items={m.changes}
|
|
145
|
+
statusOf={(_, i) => decisions[`${m.id}:${i}`] ?? "pending"}
|
|
146
|
+
applyLabel="Apply accepted"
|
|
147
|
+
onAcceptItem={(i) => decide(m.id, i, "accepted")}
|
|
148
|
+
onApply={() => applyMsg(m.id)}
|
|
149
|
+
onDiscard={() => setMessages((ms) => ms.map((x) => (x.id === m.id ? { ...x, applied: true } : x)))}
|
|
150
|
+
/>
|
|
132
151
|
</View>
|
|
133
|
-
)}
|
|
134
|
-
|
|
135
|
-
applyLabel="Apply accepted"
|
|
136
|
-
onAcceptItem={active ? (i) => decide(m.id, i, "accepted") : undefined}
|
|
137
|
-
onRejectItem={active ? (i) => decide(m.id, i, "rejected") : undefined}
|
|
138
|
-
onUndoItem={active ? (i) => setDecisions((d) => { const n = { ...d }; delete n[`${m.id}:${i}`]; return n; }) : undefined}
|
|
139
|
-
onApply={active ? () => applyMsg(m.id) : undefined}
|
|
140
|
-
onDiscard={active ? () => setMessages((ms) => ms.map((x) => (x.id === m.id ? { ...x, applied: true } : x))) : undefined}
|
|
141
|
-
/>
|
|
152
|
+
) : null}
|
|
153
|
+
</View>
|
|
142
154
|
) : null}
|
|
143
155
|
</View>
|
|
144
156
|
</View>
|
package/examples/tpl_extract.tsx
CHANGED
|
@@ -133,7 +133,7 @@ export function TplExtract() {
|
|
|
133
133
|
|
|
134
134
|
{phase === "extracting" ? (
|
|
135
135
|
<Card>
|
|
136
|
-
<AgentRun
|
|
136
|
+
<AgentRun steps={steps} state={streaming ? "streaming" : "done"} />
|
|
137
137
|
</Card>
|
|
138
138
|
) : null}
|
|
139
139
|
|
package/examples/tpl_lookup.tsx
CHANGED
|
@@ -201,7 +201,7 @@ export function TplLookup() {
|
|
|
201
201
|
|
|
202
202
|
<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 16 }}>
|
|
203
203
|
{/* current run */}
|
|
204
|
-
<AgentRun
|
|
204
|
+
<AgentRun steps={steps} state={streaming ? "streaming" : "done"} />
|
|
205
205
|
|
|
206
206
|
<View style={{ gap: 8 }}>
|
|
207
207
|
<Text size="xs" color="muted" weight="medium">Nearest matches</Text>
|
package/examples/tpl_pick.tsx
CHANGED
|
@@ -11,7 +11,7 @@ import { Divider } from "@lotics/ui/divider";
|
|
|
11
11
|
import { Popover, PopoverContent, PopoverFooter, PopoverTrigger } from "@lotics/ui/popover";
|
|
12
12
|
import { ProgressBar } from "@lotics/ui/progress_bar";
|
|
13
13
|
import { ScanField } from "@lotics/ui/scan_field";
|
|
14
|
-
import {
|
|
14
|
+
import { Stepper, Step, type StepStatus } from "@lotics/ui/stepper";
|
|
15
15
|
import { CompletionState } from "@lotics/ui/completion_state";
|
|
16
16
|
|
|
17
17
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -155,18 +155,6 @@ function Complete({ lines, onReset }: { lines: PickLine[]; onReset: () => void }
|
|
|
155
155
|
// The right rail — the whole run at a glance: done · now · up next. Read-only;
|
|
156
156
|
// the run is sequential, so position is shown, not chosen.
|
|
157
157
|
function RunPath({ lines, currentIndex }: { lines: PickLine[]; currentIndex: number }) {
|
|
158
|
-
const steps: StepListItem[] = lines.map((l, i) => ({
|
|
159
|
-
id: l.id,
|
|
160
|
-
status: l.status === "short" ? "warning" : l.status === "picked" ? "done" : i === currentIndex ? "current" : "pending",
|
|
161
|
-
title: l.bin,
|
|
162
|
-
subtitle: l.item,
|
|
163
|
-
trailing:
|
|
164
|
-
l.status === "short" ? (
|
|
165
|
-
<Badge variant="dot" label={`${l.picked ?? 0} of ${l.qty}`} color="amber" />
|
|
166
|
-
) : (
|
|
167
|
-
<Text size="sm" color="muted" tabular>{`×${l.qty}`}</Text>
|
|
168
|
-
),
|
|
169
|
-
}));
|
|
170
158
|
return (
|
|
171
159
|
<Card style={{ padding: 0 }}>
|
|
172
160
|
<View style={{ paddingHorizontal: 16, paddingVertical: 12 }}>
|
|
@@ -174,7 +162,27 @@ function RunPath({ lines, currentIndex }: { lines: PickLine[]; currentIndex: num
|
|
|
174
162
|
</View>
|
|
175
163
|
<Divider />
|
|
176
164
|
<View style={{ paddingHorizontal: 16, paddingVertical: 14 }}>
|
|
177
|
-
<
|
|
165
|
+
<Stepper orientation="vertical" accessibilityLabel="Pick path">
|
|
166
|
+
{lines.map((l, i) => {
|
|
167
|
+
const status: StepStatus =
|
|
168
|
+
l.status === "short" ? "warning" : l.status === "picked" ? "done" : i === currentIndex ? "current" : "upcoming";
|
|
169
|
+
return (
|
|
170
|
+
<Step key={l.id} status={status}>
|
|
171
|
+
<View style={{ flexDirection: "row", alignItems: "flex-start", gap: 12, flex: 1 }}>
|
|
172
|
+
<View style={{ flex: 1, gap: 1 }}>
|
|
173
|
+
<Text size="sm">{l.bin}</Text>
|
|
174
|
+
<Text size="xs" color="muted" numberOfLines={1}>{l.item}</Text>
|
|
175
|
+
</View>
|
|
176
|
+
{l.status === "short" ? (
|
|
177
|
+
<Badge variant="dot" label={`${l.picked ?? 0} of ${l.qty}`} color="amber" />
|
|
178
|
+
) : (
|
|
179
|
+
<Text size="sm" color="muted" tabular>{`×${l.qty}`}</Text>
|
|
180
|
+
)}
|
|
181
|
+
</View>
|
|
182
|
+
</Step>
|
|
183
|
+
);
|
|
184
|
+
})}
|
|
185
|
+
</Stepper>
|
|
178
186
|
</View>
|
|
179
187
|
</Card>
|
|
180
188
|
);
|
|
@@ -17,7 +17,7 @@ import { AgentRun, type AgentRunStep } from "@lotics/ui/agent_run";
|
|
|
17
17
|
import { Table, TableRow, TableCell, type TableColumn } from "@lotics/ui/table";
|
|
18
18
|
import { InlineNumberInput } from "@lotics/ui/inline_number_input";
|
|
19
19
|
import { CompletionState } from "@lotics/ui/completion_state";
|
|
20
|
-
import { ChangeReview, type ChangeReviewItemStatus } from "@lotics/ui/change_review";
|
|
20
|
+
import { ChangeReview, ChangeReviewActions, type ChangeReviewItemStatus } from "@lotics/ui/change_review";
|
|
21
21
|
import { Dialog, DialogHeader, DialogHeaderTitle, DialogScrollArea, DialogFooter } from "@lotics/ui/dialog";
|
|
22
22
|
import { formatDate } from "@lotics/ui/format_date";
|
|
23
23
|
import { colors, solid, type ColorName } from "@lotics/ui/colors";
|
|
@@ -238,7 +238,7 @@ export function TplRatedesk() {
|
|
|
238
238
|
</View>
|
|
239
239
|
) : null}
|
|
240
240
|
|
|
241
|
-
{phase === "reading" ? <AgentRun
|
|
241
|
+
{phase === "reading" ? <AgentRun steps={runSteps} state="streaming" /> : null}
|
|
242
242
|
|
|
243
243
|
{phase === "review" ? (
|
|
244
244
|
<ChangeReview
|
|
@@ -254,12 +254,9 @@ export function TplRatedesk() {
|
|
|
254
254
|
<Text size="xs" color="muted" numberOfLines={1} tabular style={[{ flex: 1 }, kept ? undefined : { textDecorationLine: "line-through" }]}>{l.carrier} · {l.unit} · sell {usd(l.sell)}</Text>
|
|
255
255
|
</View>
|
|
256
256
|
)}
|
|
257
|
-
applyLabel={`Apply ${lines.filter((l) => decisions[l.id] === "accepted").length} kept`}
|
|
258
257
|
onAcceptItem={(i) => decide(lines[i].id, "accepted")}
|
|
259
258
|
onRejectItem={(i) => decide(lines[i].id, "rejected")}
|
|
260
259
|
onUndoItem={(i) => decide(lines[i].id, null)}
|
|
261
|
-
onApply={applyAccepted}
|
|
262
|
-
onDiscard={reset}
|
|
263
260
|
/>
|
|
264
261
|
) : null}
|
|
265
262
|
|
|
@@ -268,21 +265,29 @@ export function TplRatedesk() {
|
|
|
268
265
|
) : null}
|
|
269
266
|
</DialogScrollArea>
|
|
270
267
|
|
|
271
|
-
{/* idle
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
{/* idle / review / done carry footer actions; reading just streams. The
|
|
269
|
+
review commit bar pins HERE via ChangeReviewActions — it never scrolls
|
|
270
|
+
away inside the list. */}
|
|
271
|
+
{phase === "idle" ? (
|
|
274
272
|
<DialogFooter>
|
|
275
|
-
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
273
|
+
{files.length > 0 ? <Button title="Clear" color="muted" shape="rounded" onPress={() => setFiles([])} /> : null}
|
|
274
|
+
<Button title={files.length ? `Read ${files.length} sheets` : "Read sheets"} color="primary" shape="rounded" disabled={!files.length} onPress={() => { setRevealed(0); setPhase("reading"); }} />
|
|
275
|
+
</DialogFooter>
|
|
276
|
+
) : phase === "review" ? (
|
|
277
|
+
<DialogFooter>
|
|
278
|
+
<ChangeReviewActions
|
|
279
|
+
items={lines}
|
|
280
|
+
statusOf={(l) => decisions[l.id] ?? "pending"}
|
|
281
|
+
onAcceptItem={(i) => decide(lines[i].id, "accepted")}
|
|
282
|
+
onApply={applyAccepted}
|
|
283
|
+
onDiscard={reset}
|
|
284
|
+
applyLabel={`Apply ${lines.filter((l) => decisions[l.id] === "accepted").length} kept`}
|
|
285
|
+
/>
|
|
286
|
+
</DialogFooter>
|
|
287
|
+
) : phase === "done" ? (
|
|
288
|
+
<DialogFooter>
|
|
289
|
+
<Button title="Import more" color="secondary" shape="rounded" onPress={reset} />
|
|
290
|
+
<Button title="Done" color="primary" shape="rounded" onPress={closeImport} />
|
|
286
291
|
</DialogFooter>
|
|
287
292
|
) : null}
|
|
288
293
|
</Dialog>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lotics/ui",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./tokens": "./src/tokens.ts",
|
|
@@ -139,7 +139,6 @@
|
|
|
139
139
|
"./table": "./src/table.tsx",
|
|
140
140
|
"./detail_row": "./src/detail_row.tsx",
|
|
141
141
|
"./scan_field": "./src/scan_field.tsx",
|
|
142
|
-
"./step_list": "./src/step_list.tsx",
|
|
143
142
|
"./completion_state": "./src/completion_state.tsx",
|
|
144
143
|
"./remainder_meter": "./src/remainder_meter.tsx",
|
|
145
144
|
"./allocation_row": "./src/allocation_row.tsx",
|
package/src/agent_progress.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { colors } from "./colors";
|
|
|
4
4
|
import { Text } from "./text";
|
|
5
5
|
import { WaveAvatar } from "./wave_avatar";
|
|
6
6
|
import { PressableHighlight } from "./pressable_highlight";
|
|
7
|
-
import { AgentRun, type AgentRunStep } from "./agent_run";
|
|
7
|
+
import { AgentRun, resolveToolMeta, type AgentRunStep } from "./agent_run";
|
|
8
8
|
|
|
9
9
|
export interface AgentProgressProps {
|
|
10
10
|
steps: AgentRunStep[];
|
|
@@ -12,6 +12,11 @@ export interface AgentProgressProps {
|
|
|
12
12
|
/** The collapsed-pill label. Defaults to the running step's label (or
|
|
13
13
|
* "Working…" / "Done"). */
|
|
14
14
|
label?: string;
|
|
15
|
+
/** The agent's streamed text — forwarded to the expanded `AgentRun`. */
|
|
16
|
+
text?: string;
|
|
17
|
+
/** Localize / override a tool step's label by raw tool name — applied to both
|
|
18
|
+
* the collapsed pill and the expanded feed. */
|
|
19
|
+
labelForTool?: (toolName: string) => string | undefined;
|
|
15
20
|
defaultExpanded?: boolean;
|
|
16
21
|
}
|
|
17
22
|
|
|
@@ -24,11 +29,16 @@ export interface AgentProgressProps {
|
|
|
24
29
|
* label, so the surface stays calm until you ask to see the steps.
|
|
25
30
|
*/
|
|
26
31
|
export function AgentProgress(props: AgentProgressProps) {
|
|
27
|
-
const { steps, state = "streaming", label, defaultExpanded } = props;
|
|
32
|
+
const { steps, state = "streaming", label, text, labelForTool, defaultExpanded } = props;
|
|
28
33
|
const [expanded, setExpanded] = useState(defaultExpanded ?? false);
|
|
29
34
|
|
|
30
35
|
const running = steps.filter((s) => s.status === "running").at(-1);
|
|
31
|
-
const
|
|
36
|
+
const runningLabel = running
|
|
37
|
+
? running.kind === "tool"
|
|
38
|
+
? resolveToolMeta(running.label, labelForTool).label
|
|
39
|
+
: running.label
|
|
40
|
+
: undefined;
|
|
41
|
+
const compact = label ?? runningLabel ?? (state === "done" ? "Done" : state === "error" ? "Stopped" : "Working…");
|
|
32
42
|
const streaming = state === "streaming";
|
|
33
43
|
|
|
34
44
|
return (
|
|
@@ -36,7 +46,7 @@ export function AgentProgress(props: AgentProgressProps) {
|
|
|
36
46
|
{expanded ? (
|
|
37
47
|
<View style={styles.panel}>
|
|
38
48
|
<ScrollView style={{ maxHeight: 260 }} contentContainerStyle={{ padding: 16 }}>
|
|
39
|
-
<AgentRun steps={steps} state={state} />
|
|
49
|
+
<AgentRun steps={steps} state={state} text={text} labelForTool={labelForTool} />
|
|
40
50
|
</ScrollView>
|
|
41
51
|
</View>
|
|
42
52
|
) : null}
|