@invana/boards 0.0.32
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/README.md +130 -0
- package/dist/index.cjs +1121 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1013 -0
- package/dist/index.d.ts +1013 -0
- package/dist/index.js +1069 -0
- package/dist/index.js.map +1 -0
- package/package.json +77 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1013 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { BlockPatch, AskState, BlockKind, BlockOptionsByKind, SpecStream } from '@invana/blocks';
|
|
3
|
+
import { StatusDotProps, Bound, DiffOp, Layer, Narrowing, LensUsage, LayerPalette, MarkChip, TouchItem } from '@invana/ui';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* How a board changes while it streams. A panel's options stream by the
|
|
7
|
+
* block's own {@link BlockPatch} — the patch a conversation streams the same
|
|
8
|
+
* block by — so a gantt panel and a gantt answer take one stream.
|
|
9
|
+
*/
|
|
10
|
+
type BoardPatch =
|
|
11
|
+
/** Stream a panel's options — its block's spec — by a block patch. `panel` is its `id`. */
|
|
12
|
+
{
|
|
13
|
+
op: "patch-panel";
|
|
14
|
+
panel: string;
|
|
15
|
+
patch: BlockPatch;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The panel's own fields — its `aside` as the run moves, its `state` once
|
|
19
|
+
* answered; `null` removes one. Never its `id`, `kind` or `options`.
|
|
20
|
+
*/
|
|
21
|
+
| {
|
|
22
|
+
op: "update-panel";
|
|
23
|
+
panel: string;
|
|
24
|
+
fields: {
|
|
25
|
+
[F in keyof Omit<PanelBase, "id" | "render">]?: PanelBase[F] | null;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
type BoardPatchOp = BoardPatch["op"];
|
|
29
|
+
declare class BoardPatchError extends Error {
|
|
30
|
+
}
|
|
31
|
+
/** A board's spec after one patch: the panel it names, wherever it sits — a row, or a tab's row. */
|
|
32
|
+
declare function applyBoardPatch<X extends ExtraPanels>(spec: BoardSpec<X>, patch: BoardPatch): BoardSpec<X>;
|
|
33
|
+
/** Apply patches in order — a recorded stream, replayed. */
|
|
34
|
+
declare function applyBoardPatches<X extends ExtraPanels>(spec: BoardSpec<X>, patches: BoardPatch[]): BoardSpec<X>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A board is **data**. Everything in this file is JSON-serialisable, with
|
|
38
|
+
* one deliberate exception noted on {@link PanelSpec.render}.
|
|
39
|
+
*
|
|
40
|
+
* That constraint is the whole design. A spec can come from an API, be stored
|
|
41
|
+
* as `board.yml` beside a plan, be diffed between two runs, and be rendered
|
|
42
|
+
* by a component that has never heard of the record it is describing. So
|
|
43
|
+
* nothing here is a function, a React node, or a class instance — behaviour
|
|
44
|
+
* arrives through {@link BoardProps.onAction} and the panel registry, keyed
|
|
45
|
+
* by strings the JSON carries.
|
|
46
|
+
*/
|
|
47
|
+
type Tone = "running" | "success" | "warning" | "error" | "info" | "muted";
|
|
48
|
+
/** A chip in a header or beside a row. */
|
|
49
|
+
interface ChipSpec {
|
|
50
|
+
label: string;
|
|
51
|
+
/** Renders a `BoundChip` instead of a `Badge`. Set `label` or this, not both. */
|
|
52
|
+
bound?: Bound;
|
|
53
|
+
/**
|
|
54
|
+
* The bound's swatch class — `bg-data-7`. `BoundChip` ships no hues, so a
|
|
55
|
+
* spec that names a bound and no swatch draws in the neutral.
|
|
56
|
+
*/
|
|
57
|
+
swatch?: string;
|
|
58
|
+
tone?: Tone;
|
|
59
|
+
variant?: "default" | "outline" | "secondary" | "destructive";
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Something a person can do. The spec carries only what it is called and what
|
|
63
|
+
* it means; **what it does arrives as `onAction(id)`**, because a function is
|
|
64
|
+
* not JSON and a board that shipped callbacks in its data would not be one.
|
|
65
|
+
*/
|
|
66
|
+
interface ActionSpec {
|
|
67
|
+
id: string;
|
|
68
|
+
label?: string;
|
|
69
|
+
/** A key into {@link BoardProps.icons}. Unknown names render nothing. */
|
|
70
|
+
icon?: string;
|
|
71
|
+
variant?: "default" | "outline" | "ghost" | "secondary" | "destructive";
|
|
72
|
+
/** A set of mutually exclusive views — `Board` ⁄ `board.yml`. */
|
|
73
|
+
options?: string[];
|
|
74
|
+
/** Which option is active. Only with `options`. */
|
|
75
|
+
value?: string;
|
|
76
|
+
/**
|
|
77
|
+
* Draw `options` as a dropdown rather than a segmented switch — for a choice
|
|
78
|
+
* among named records (`agent`), too many or too long to lay side by side.
|
|
79
|
+
* Dispatches with `{ option }` exactly as the switch does.
|
|
80
|
+
*/
|
|
81
|
+
picker?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Draw `options` as a menu behind this action's button — `⋯` opening
|
|
84
|
+
* `Versions · Arguments · Export YAML`. A menu is a list of acts, not a
|
|
85
|
+
* choice: nothing is selected and `value` is ignored. Dispatches with
|
|
86
|
+
* `{ option }`, and `optionLabels` names each item. With an `icon`, the
|
|
87
|
+
* button draws the icon alone and `label` is its accessible name.
|
|
88
|
+
*/
|
|
89
|
+
menu?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* What the reader sees for an option, by option. The option itself is what
|
|
92
|
+
* dispatches, so a picker can show a name and send an id. An option with no
|
|
93
|
+
* label shows as itself.
|
|
94
|
+
*/
|
|
95
|
+
optionLabels?: Record<string, string>;
|
|
96
|
+
/**
|
|
97
|
+
* An on/off setting — `Fit`. Set, the action draws as a labelled `Switch` in
|
|
98
|
+
* this state and dispatches with `{ pressed }`, the state it is switched to.
|
|
99
|
+
*/
|
|
100
|
+
pressed?: boolean;
|
|
101
|
+
disabled?: boolean;
|
|
102
|
+
}
|
|
103
|
+
/** The record identity across the top — see `RecordHeader`. */
|
|
104
|
+
interface HeaderSpec {
|
|
105
|
+
/** The bar's height on the control scale: `lg` (default) tops a page, `md` a panel or a drawer. */
|
|
106
|
+
size?: "md" | "lg";
|
|
107
|
+
tone?: StatusDotProps["tone"];
|
|
108
|
+
/** Outermost first; the last is the record this board is about. */
|
|
109
|
+
crumbs: string[];
|
|
110
|
+
/**
|
|
111
|
+
* An action per crumb, by index — a crumb with one is a link back to the
|
|
112
|
+
* record it names (`run:7d3184f1` above a step). `undefined` stays text.
|
|
113
|
+
*/
|
|
114
|
+
crumbActions?: (string | undefined)[];
|
|
115
|
+
/**
|
|
116
|
+
* The last crumb opens a picker of its siblings — every step of a run. A
|
|
117
|
+
* pick dispatches `action` with `{ itemId }`.
|
|
118
|
+
*/
|
|
119
|
+
crumbMenu?: CrumbMenuSpec;
|
|
120
|
+
chips?: ChipSpec[];
|
|
121
|
+
actions?: ActionSpec[];
|
|
122
|
+
/**
|
|
123
|
+
* The record's own description, on one line under the crumbs — see
|
|
124
|
+
* `RecordDescription`. `More` shows the whole of it and {@link details}.
|
|
125
|
+
*/
|
|
126
|
+
description?: string;
|
|
127
|
+
/** The record's facts, shown under the description by `More`. */
|
|
128
|
+
details?: Array<{
|
|
129
|
+
label: string;
|
|
130
|
+
value: string;
|
|
131
|
+
mono?: boolean;
|
|
132
|
+
}>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* What is staged and not yet published — drawn as a `StagedBar` between the
|
|
136
|
+
* header and the tabs, on every tab, while a draft is open. Absent draws nothing.
|
|
137
|
+
*/
|
|
138
|
+
interface StagedSpec {
|
|
139
|
+
items: Array<{
|
|
140
|
+
id: string;
|
|
141
|
+
op: "add" | "remove" | "change";
|
|
142
|
+
name: string;
|
|
143
|
+
note?: string;
|
|
144
|
+
}>;
|
|
145
|
+
/** Dispatched with `{ itemId }` by an item's `×`. Absent, the items carry none. */
|
|
146
|
+
discardAction?: string;
|
|
147
|
+
/** Dispatched by `Discard all`. Absent, there is no `Discard all`. */
|
|
148
|
+
discardAllAction?: string;
|
|
149
|
+
/** The shortcut that finishes the set — `⌘↵ publish`. */
|
|
150
|
+
hint?: string;
|
|
151
|
+
}
|
|
152
|
+
/** The siblings the last crumb can switch to. */
|
|
153
|
+
interface CrumbMenuSpec {
|
|
154
|
+
action: string;
|
|
155
|
+
/** The field's placeholder over the list — `Jump to a step`. */
|
|
156
|
+
placeholder?: string;
|
|
157
|
+
items: Array<{
|
|
158
|
+
id: string;
|
|
159
|
+
label: string;
|
|
160
|
+
/** Right-aligned, mono — a duration. */
|
|
161
|
+
aside?: string;
|
|
162
|
+
tone?: StatusDotProps["tone"];
|
|
163
|
+
}>;
|
|
164
|
+
/** The item the page is on. */
|
|
165
|
+
selected?: string;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* One tab of a board — its own bands under the shared header.
|
|
169
|
+
*
|
|
170
|
+
* Tabs are readings of one record, never other records: a spec with tabs is
|
|
171
|
+
* still one document, which is why a saved report keeps every tab.
|
|
172
|
+
*/
|
|
173
|
+
interface TabSpec<X extends ExtraPanels = Record<never, never>> {
|
|
174
|
+
id: string;
|
|
175
|
+
label: string;
|
|
176
|
+
rows: RowSpec<X>[];
|
|
177
|
+
/**
|
|
178
|
+
* Nothing to read here yet — the tab draws dimmed with a lock and cannot be
|
|
179
|
+
* picked. Why it is locked is said where the reader already is, not on the tab.
|
|
180
|
+
*/
|
|
181
|
+
locked?: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Drop the body padding, so the tab's one band meets the tab strip and the
|
|
184
|
+
* page's edges — a canvas, which is a surface and not a card on one.
|
|
185
|
+
*/
|
|
186
|
+
flush?: boolean;
|
|
187
|
+
}
|
|
188
|
+
interface JsonOptions {
|
|
189
|
+
/** The document, as a string. Objects are stringified with 2-space indent. */
|
|
190
|
+
value: string | Record<string, unknown>;
|
|
191
|
+
maxHeight?: number;
|
|
192
|
+
}
|
|
193
|
+
interface CodeOptions {
|
|
194
|
+
value: string;
|
|
195
|
+
language?: "python" | "shell" | "javascript" | "json" | "cypher" | "yaml" | "plain";
|
|
196
|
+
maxHeight?: number;
|
|
197
|
+
showLineNumbers?: boolean;
|
|
198
|
+
}
|
|
199
|
+
interface LogOptions {
|
|
200
|
+
lines: Array<{
|
|
201
|
+
time?: string;
|
|
202
|
+
level?: "info" | "warn" | "error" | "debug";
|
|
203
|
+
source?: string;
|
|
204
|
+
message: string;
|
|
205
|
+
}>;
|
|
206
|
+
/** Overrides the `time · LEVEL · source · message` column widths. */
|
|
207
|
+
columnTemplate?: string;
|
|
208
|
+
}
|
|
209
|
+
/** One thing the engine wrote — a task started, a call made, a line logged. */
|
|
210
|
+
interface EventSpec {
|
|
211
|
+
id: string;
|
|
212
|
+
/** From the run's zero, in ms. */
|
|
213
|
+
atMs: number;
|
|
214
|
+
level: "debug" | "info" | "warn" | "error";
|
|
215
|
+
/** The engine's own word — `task_started`, `llm_call`, `retry_scheduled`. Drawn in its level's colour. */
|
|
216
|
+
kind: string;
|
|
217
|
+
/** The task it belongs to, by key. */
|
|
218
|
+
task?: string;
|
|
219
|
+
tookMs?: number;
|
|
220
|
+
message: string;
|
|
221
|
+
/** Everything else it carries, opened under the event in the tree. */
|
|
222
|
+
fields?: Record<string, string>;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* The run's event stream, read one of two ways. `log` is every event in
|
|
226
|
+
* order, a page at a time, searched and narrowed by kind, task and level.
|
|
227
|
+
* `tree` is the tasks as a tree, each task's own events under it before
|
|
228
|
+
* the tasks it split into, an event opening into its fields.
|
|
229
|
+
*/
|
|
230
|
+
interface EventsOptions {
|
|
231
|
+
events: EventSpec[];
|
|
232
|
+
layout?: "log" | "tree";
|
|
233
|
+
/** The tasks, for `tree` — a task with no `parent` is a root. */
|
|
234
|
+
tasks?: Array<{
|
|
235
|
+
key: string;
|
|
236
|
+
parent?: string;
|
|
237
|
+
status: string;
|
|
238
|
+
summary?: string;
|
|
239
|
+
startMs?: number;
|
|
240
|
+
durationMs?: number;
|
|
241
|
+
}>;
|
|
242
|
+
/** Leave out the task column and its chip — a log already about one task. */
|
|
243
|
+
hideTask?: boolean;
|
|
244
|
+
/** `log` only. Default `25`. */
|
|
245
|
+
pageSize?: number;
|
|
246
|
+
/**
|
|
247
|
+
* Dispatched with `{ panelId, value: <task key> }` when a row is picked — an
|
|
248
|
+
* event's task, or the task itself in the tree. Absent, rows do not pick.
|
|
249
|
+
*/
|
|
250
|
+
selectAction?: string;
|
|
251
|
+
}
|
|
252
|
+
interface ListOptions {
|
|
253
|
+
items: Array<{
|
|
254
|
+
id?: string;
|
|
255
|
+
tone?: StatusDotProps["tone"];
|
|
256
|
+
icon?: string;
|
|
257
|
+
title: string;
|
|
258
|
+
/** Right-aligned fact — a duration, a size, a count. */
|
|
259
|
+
meta?: string;
|
|
260
|
+
chip?: ChipSpec;
|
|
261
|
+
mono?: boolean;
|
|
262
|
+
/** Emits `onAction(this, { itemId })` when the row is picked. */
|
|
263
|
+
action?: string;
|
|
264
|
+
}>;
|
|
265
|
+
}
|
|
266
|
+
interface ExchangeOptions {
|
|
267
|
+
/** `PROMPT · 1,204 tokens` over a mono block, twice. */
|
|
268
|
+
blocks: Array<{
|
|
269
|
+
label: string;
|
|
270
|
+
value: string;
|
|
271
|
+
language?: CodeOptions["language"];
|
|
272
|
+
}>;
|
|
273
|
+
}
|
|
274
|
+
interface ParamsOptions {
|
|
275
|
+
params: Array<{
|
|
276
|
+
name: string;
|
|
277
|
+
type?: string;
|
|
278
|
+
source: "literal" | "argument" | "binding";
|
|
279
|
+
value: string;
|
|
280
|
+
note?: string;
|
|
281
|
+
invalid?: boolean;
|
|
282
|
+
disabled?: boolean;
|
|
283
|
+
}>;
|
|
284
|
+
/** Emits `onAction(changeAction, { name, source, value })` on every edit. */
|
|
285
|
+
changeAction?: string;
|
|
286
|
+
}
|
|
287
|
+
interface TextOptions {
|
|
288
|
+
/** Plain paragraphs. No markdown — a board states facts, it does not write. */
|
|
289
|
+
text: string;
|
|
290
|
+
tone?: "default" | "muted" | "success" | "warning" | "error" | "info";
|
|
291
|
+
/** Renders inside an `Alert` rather than as a bare paragraph. */
|
|
292
|
+
callout?: boolean;
|
|
293
|
+
actions?: ActionSpec[];
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* A panel whose renderer is **not** built in — a canvas, a flow, a map.
|
|
297
|
+
*
|
|
298
|
+
* `@invana/canvas` is the reason this kind exists. The board does not
|
|
299
|
+
* import it: the consumer registers a renderer for `kind: "canvas"` and the
|
|
300
|
+
* spec carries only the data that renderer needs. That keeps PixiJS out of
|
|
301
|
+
* every consumer that only wanted tiles and a log.
|
|
302
|
+
*/
|
|
303
|
+
interface CustomOptions {
|
|
304
|
+
[key: string]: unknown;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Kind → the options that kind reads.
|
|
308
|
+
*
|
|
309
|
+
* This map is what makes a spec **checkable**: a `gantt` panel whose task
|
|
310
|
+
* carries a status the Gantt has never heard of is a compile error, not a band
|
|
311
|
+
* that silently renders empty tracks. It did exactly that once, which is why
|
|
312
|
+
* the map exists.
|
|
313
|
+
*/
|
|
314
|
+
interface PanelOptionsByKind {
|
|
315
|
+
json: JsonOptions;
|
|
316
|
+
code: CodeOptions;
|
|
317
|
+
exchange: ExchangeOptions;
|
|
318
|
+
log: LogOptions;
|
|
319
|
+
events: EventsOptions;
|
|
320
|
+
list: ListOptions;
|
|
321
|
+
params: ParamsOptions;
|
|
322
|
+
text: TextOptions;
|
|
323
|
+
}
|
|
324
|
+
type BuiltInPanelKind = keyof PanelOptionsByKind;
|
|
325
|
+
type PanelOptions = PanelOptionsByKind[BuiltInPanelKind] | BlockOptionsByKind[BlockKind] | CustomOptions;
|
|
326
|
+
/** Everything a panel carries apart from its kind and its options. */
|
|
327
|
+
interface PanelBase {
|
|
328
|
+
id?: string;
|
|
329
|
+
/**
|
|
330
|
+
* The label bar over the panel. Every panel is drawn in a `PanelBox` — the
|
|
331
|
+
* board frames what it draws, as an answer card frames a block — and
|
|
332
|
+
* `title` only adds the bar. Without it the box frames its content alone.
|
|
333
|
+
*/
|
|
334
|
+
title?: string;
|
|
335
|
+
/** The fact on the right of the box header. Ignored without a `title`. */
|
|
336
|
+
aside?: string;
|
|
337
|
+
/** A chip on the right of the box header, instead of `aside`. */
|
|
338
|
+
asideChip?: ChipSpec;
|
|
339
|
+
/**
|
|
340
|
+
* Controls on the right of the box header, after `aside` — a reading of this
|
|
341
|
+
* panel, such as a `Fit` toggle. Dispatched with `{ panelId }`.
|
|
342
|
+
* Ignored without a `title`.
|
|
343
|
+
*/
|
|
344
|
+
actions?: ActionSpec[];
|
|
345
|
+
/** Fixed column width in px. Without it the panel takes an equal share. */
|
|
346
|
+
width?: number;
|
|
347
|
+
/** Relative share of the row when several panels grow. Default `1`. */
|
|
348
|
+
grow?: number;
|
|
349
|
+
/** Drop the box padding, so a table or a canvas meets the border. */
|
|
350
|
+
flush?: boolean;
|
|
351
|
+
/**
|
|
352
|
+
* Where a block that returns a value stands — a `form`, a `confirm` — and the
|
|
353
|
+
* value given. The consumer moves it on `reply`, as the API patches an ask
|
|
354
|
+
* turn; unset, the block is open.
|
|
355
|
+
*/
|
|
356
|
+
state?: AskState;
|
|
357
|
+
value?: unknown;
|
|
358
|
+
/**
|
|
359
|
+
* **Nobody recorded this band** — draw why, instead of the panel.
|
|
360
|
+
*
|
|
361
|
+
* A rule of the board and not of each renderer, because every kind has
|
|
362
|
+
* the same three ways of having nothing to draw and they are three different
|
|
363
|
+
* facts: `unrecorded` (the document is written when the row settles),
|
|
364
|
+
* `purged` (it existed and aged out) and `declared-none` (the step's contract
|
|
365
|
+
* has no such output). A renderer left to decide for itself reaches for an
|
|
366
|
+
* empty table, which claims the step returned an empty result.
|
|
367
|
+
*
|
|
368
|
+
* A panel with **no title and no options** is better left out of the spec
|
|
369
|
+
* altogether — absence is for a band a reader expects to find.
|
|
370
|
+
*/
|
|
371
|
+
absent?: {
|
|
372
|
+
reason: "unrecorded" | "purged" | "declared-none";
|
|
373
|
+
/** Overrides the word — the engine's own term where there is one. */
|
|
374
|
+
label?: string;
|
|
375
|
+
/** Why, in the record's terms. */
|
|
376
|
+
note?: string;
|
|
377
|
+
};
|
|
378
|
+
/**
|
|
379
|
+
* The one escape from JSON: a node rendered in place of a registered kind.
|
|
380
|
+
*
|
|
381
|
+
* It exists because a real surface always has one panel the schema has not
|
|
382
|
+
* caught up with, and the alternative is a fork of the board. A spec that
|
|
383
|
+
* uses it is no longer serialisable — which is the honest cost, and why it is
|
|
384
|
+
* named after what it breaks rather than something comfortable like `content`.
|
|
385
|
+
*/
|
|
386
|
+
render?: React.ReactNode;
|
|
387
|
+
}
|
|
388
|
+
/** A panel of a kind the board ships. Its options are checked against the map. */
|
|
389
|
+
type BuiltInPanelSpec = {
|
|
390
|
+
[K in BuiltInPanelKind]: PanelBase & {
|
|
391
|
+
kind: K;
|
|
392
|
+
options: PanelOptionsByKind[K];
|
|
393
|
+
};
|
|
394
|
+
}[BuiltInPanelKind];
|
|
395
|
+
/**
|
|
396
|
+
* A block as a panel: its kind, and the options the same block reads in a
|
|
397
|
+
* conversation turn — `{ kind: "timeseries", title: "Demand", options: { series } }`.
|
|
398
|
+
* A kind the consumer registers itself is theirs, not the block's.
|
|
399
|
+
*/
|
|
400
|
+
type BlockPanelSpec<X extends ExtraPanels = Record<never, never>> = {
|
|
401
|
+
[K in Exclude<BlockKind, keyof X>]: PanelBase & {
|
|
402
|
+
kind: K;
|
|
403
|
+
options: BlockOptionsByKind[K];
|
|
404
|
+
};
|
|
405
|
+
}[Exclude<BlockKind, keyof X>];
|
|
406
|
+
/**
|
|
407
|
+
* The extra kinds a consumer registers — `{ canvas: CanvasOptions }`.
|
|
408
|
+
*
|
|
409
|
+
* A board's type is **parametrised by its registry**, which is the only way
|
|
410
|
+
* the built-in kinds stay checked. The obvious design — a catch-all member with
|
|
411
|
+
* `kind: string` — silently checks nothing: a union with one permissive member
|
|
412
|
+
* accepts every object, so a `gantt` panel full of invalid statuses compiles
|
|
413
|
+
* and renders empty tracks. It did. Hence this.
|
|
414
|
+
*/
|
|
415
|
+
type ExtraPanels = Record<string, unknown>;
|
|
416
|
+
type RegisteredPanelSpec<X extends ExtraPanels> = {
|
|
417
|
+
[K in keyof X & string]: PanelBase & {
|
|
418
|
+
kind: K;
|
|
419
|
+
options: X[K];
|
|
420
|
+
};
|
|
421
|
+
}[keyof X & string];
|
|
422
|
+
/**
|
|
423
|
+
* A panel. With no type argument this is the built-ins and nothing else, so a
|
|
424
|
+
* `canvas` panel is a compile error until you say what its options are:
|
|
425
|
+
*
|
|
426
|
+
* ```ts
|
|
427
|
+
* const spec: BoardSpec<{ canvas: { nodes: TaskNodeSpec[] } }> = { … }
|
|
428
|
+
* ```
|
|
429
|
+
*
|
|
430
|
+
* For a spec arriving off the wire, where nothing can be checked anyway, use
|
|
431
|
+
* {@link AnyBoardSpec}.
|
|
432
|
+
*/
|
|
433
|
+
type PanelSpec<X extends ExtraPanels = Record<never, never>> = BuiltInPanelSpec | BlockPanelSpec<X> | RegisteredPanelSpec<X>;
|
|
434
|
+
interface RowSpec<X extends ExtraPanels = Record<never, never>> {
|
|
435
|
+
id?: string;
|
|
436
|
+
panels: PanelSpec<X>[];
|
|
437
|
+
/** Pin the row's height in px — for a flow, which has no content height. */
|
|
438
|
+
height?: number;
|
|
439
|
+
/**
|
|
440
|
+
* Take the height the tab has left — a canvas, which has no content height
|
|
441
|
+
* and no one right height either. Ignored with {@link height}.
|
|
442
|
+
*/
|
|
443
|
+
fill?: boolean;
|
|
444
|
+
/** Gap between panels in px. Defaults to the board's `gap`. */
|
|
445
|
+
gap?: number;
|
|
446
|
+
}
|
|
447
|
+
interface BoardSpec<X extends ExtraPanels = Record<never, never>> {
|
|
448
|
+
/** For the document title and nothing else; the header draws the crumbs. */
|
|
449
|
+
title?: string;
|
|
450
|
+
header?: HeaderSpec;
|
|
451
|
+
/** The staged set, as a bar under the header — see {@link StagedSpec}. */
|
|
452
|
+
staged?: StagedSpec;
|
|
453
|
+
/** The bands. Ignored when `tabs` is set — each tab carries its own. */
|
|
454
|
+
rows: RowSpec<X>[];
|
|
455
|
+
/** Readings of the record, as a tab strip under the header. */
|
|
456
|
+
tabs?: TabSpec<X>[];
|
|
457
|
+
/** The active tab's `id`. Absent reads the first. */
|
|
458
|
+
tab?: string;
|
|
459
|
+
/**
|
|
460
|
+
* Dispatched with `{ option: <tab id> }` when a tab is picked. Absent, the
|
|
461
|
+
* board keeps the tab itself — which is how a frozen report reads.
|
|
462
|
+
*/
|
|
463
|
+
tabAction?: string;
|
|
464
|
+
/**
|
|
465
|
+
* Controls on the right of the tab strip that apply to every tab — the
|
|
466
|
+
* window a plan's numbers are read over. Ignored without `tabs`.
|
|
467
|
+
*/
|
|
468
|
+
tabActions?: ActionSpec[];
|
|
469
|
+
/**
|
|
470
|
+
* One thing picked out of this board, read beside it — a task of a run
|
|
471
|
+
* beside the run's tree. Its own board (header, tabs, bands) in a column on
|
|
472
|
+
* the right, under this board's header, scrolling on its own, so the record
|
|
473
|
+
* it was picked from stays in view. Absent, the body takes the full width.
|
|
474
|
+
*/
|
|
475
|
+
inspector?: InspectorSpec<X>;
|
|
476
|
+
/** Gap between rows and between panels, in px. Default `12`. */
|
|
477
|
+
gap?: number;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* The column beside a board. Its header is drawn at `md`, as a panel's is; an
|
|
481
|
+
* `inspector` inside it is ignored — one record beside another, never a chain.
|
|
482
|
+
*/
|
|
483
|
+
interface InspectorSpec<X extends ExtraPanels = Record<never, never>> {
|
|
484
|
+
spec: BoardSpec<X>;
|
|
485
|
+
/** In px. Default `440`. */
|
|
486
|
+
width?: number;
|
|
487
|
+
}
|
|
488
|
+
/** What `onAction` is told, beyond the action's own id. */
|
|
489
|
+
interface ActionContext {
|
|
490
|
+
panelId?: string;
|
|
491
|
+
/** Set by `list`'s row select and a crumb or staged item. */
|
|
492
|
+
itemId?: string;
|
|
493
|
+
/** Set by `params` on an edit. */
|
|
494
|
+
param?: {
|
|
495
|
+
name: string;
|
|
496
|
+
source: string;
|
|
497
|
+
value: string;
|
|
498
|
+
};
|
|
499
|
+
/** Set by a segmented action — which option was picked. */
|
|
500
|
+
option?: string;
|
|
501
|
+
/** Set by a switch action — the state it was switched to. */
|
|
502
|
+
pressed?: boolean;
|
|
503
|
+
/** Set by `trace`'s row select — the step a reader picked out of a run. */
|
|
504
|
+
stepId?: string;
|
|
505
|
+
/** Set by `lens`'s row select — the lens a reader picked, by name. */
|
|
506
|
+
lens?: string;
|
|
507
|
+
/** Set by a block panel — what its action carries: a row's key, a form's values. */
|
|
508
|
+
value?: unknown;
|
|
509
|
+
/** Set by `BoardPages` — the page a pick, a close or a board's own action came from. */
|
|
510
|
+
pageId?: string;
|
|
511
|
+
}
|
|
512
|
+
interface PanelRendererProps<O = PanelOptions> {
|
|
513
|
+
/**
|
|
514
|
+
* The panel's own fields. Not a `PanelSpec` — a renderer reads `id`, `title`
|
|
515
|
+
* and `kind`, and receives its options separately and already narrowed, so
|
|
516
|
+
* tying it to the spec union would make every renderer generic for nothing.
|
|
517
|
+
*/
|
|
518
|
+
panel: PanelBase & {
|
|
519
|
+
kind: string;
|
|
520
|
+
};
|
|
521
|
+
options: O;
|
|
522
|
+
onAction: (actionId: string, ctx?: ActionContext) => void;
|
|
523
|
+
icons: Record<string, React.ComponentType<{
|
|
524
|
+
className?: string;
|
|
525
|
+
}>>;
|
|
526
|
+
/**
|
|
527
|
+
* The board's own gap, in px.
|
|
528
|
+
*
|
|
529
|
+
* Passed down so a panel that lays out a grid of its own — the tile strip —
|
|
530
|
+
* keeps the surface's rhythm instead of inventing a second one. A board
|
|
531
|
+
* whose bands sit 12px apart and whose tiles sit 6px apart reads as two
|
|
532
|
+
* grids that happen to share a page.
|
|
533
|
+
*/
|
|
534
|
+
gap: number;
|
|
535
|
+
}
|
|
536
|
+
type PanelRenderer<O = any> = React.ComponentType<PanelRendererProps<O>>;
|
|
537
|
+
/** Kind → renderer. Consumer entries win over the built-ins. */
|
|
538
|
+
type PanelRegistry = Record<string, PanelRenderer>;
|
|
539
|
+
interface BoardProps<X extends ExtraPanels = Record<never, never>> extends React.HTMLAttributes<HTMLDivElement> {
|
|
540
|
+
spec: BoardSpec<X>;
|
|
541
|
+
/**
|
|
542
|
+
* Everything a person can do. Called with the action's `id` from the spec and
|
|
543
|
+
* whatever context the panel had — see {@link ActionContext}.
|
|
544
|
+
*/
|
|
545
|
+
onAction?: (actionId: string, ctx?: ActionContext) => void;
|
|
546
|
+
/**
|
|
547
|
+
* Extra panel kinds, merged over the built-ins. This is where
|
|
548
|
+
* `@invana/canvas` arrives: `{ canvas: MyFlowPanel }`.
|
|
549
|
+
*/
|
|
550
|
+
registry?: PanelRegistry;
|
|
551
|
+
/** Icon names the spec may use. Unknown names render nothing. */
|
|
552
|
+
icons?: Record<string, React.ComponentType<{
|
|
553
|
+
className?: string;
|
|
554
|
+
}>>;
|
|
555
|
+
/**
|
|
556
|
+
* Patches to `spec` as they arrive — a panel's block streaming by the same
|
|
557
|
+
* patch a conversation streams it by (`patch-panel`), or its own fields
|
|
558
|
+
* moving (`update-panel`). The board draws `spec` with them applied; a new
|
|
559
|
+
* `spec` starts over from it. Sources and their rules are the block stream's:
|
|
560
|
+
* `fromNdjson`, `fromEventSource`, a generator, or `playScript`, or a
|
|
561
|
+
* function `(signal) => source` kept stable.
|
|
562
|
+
*/
|
|
563
|
+
stream?: SpecStream<BoardPatch>;
|
|
564
|
+
/** The stream ended; the spec as it left it. */
|
|
565
|
+
onStreamEnd?: (spec: BoardSpec<X>) => void;
|
|
566
|
+
/** A patch did not apply, or the source failed. The stream stops there. */
|
|
567
|
+
onStreamError?: (error: unknown) => void;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* A spec whose panel kinds are not known at compile time — one fetched from an
|
|
571
|
+
* API, or read from a `board.yml`. Nothing about it is checked, which is
|
|
572
|
+
* the truth about JSON off the wire rather than a weakness of the type.
|
|
573
|
+
*/
|
|
574
|
+
type AnyBoardSpec = BoardSpec<Record<string, CustomOptions>>;
|
|
575
|
+
/** One page of a {@link BoardPagesSpec}: its tab, and the board behind it. */
|
|
576
|
+
interface BoardPageSpec<X extends ExtraPanels = Record<never, never>> {
|
|
577
|
+
id: string;
|
|
578
|
+
title: string;
|
|
579
|
+
/** A key into {@link BoardPagesProps.icons}. Unknown names render nothing. */
|
|
580
|
+
icon?: string;
|
|
581
|
+
disabled?: boolean;
|
|
582
|
+
/** Draws an `×` on the tab, dispatching `closeAction`. Only with `closeAction`. */
|
|
583
|
+
closable?: boolean;
|
|
584
|
+
board: BoardSpec<X>;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Several boards behind one tab strip — the open boards of a shell. Like a
|
|
588
|
+
* board's own tabs, the pick is the strip's to keep until the spec names
|
|
589
|
+
* `selectAction`; then it is reported with `{ pageId }` and `active` is the host's.
|
|
590
|
+
*/
|
|
591
|
+
interface BoardPagesSpec<X extends ExtraPanels = Record<never, never>> {
|
|
592
|
+
pages: BoardPageSpec<X>[];
|
|
593
|
+
/** The page shown. Defaults to the first. */
|
|
594
|
+
active?: string;
|
|
595
|
+
/** Dispatched with `{ pageId }` when a tab is picked. */
|
|
596
|
+
selectAction?: string;
|
|
597
|
+
/** Dispatched with `{ pageId }` by a closable tab's `×`. */
|
|
598
|
+
closeAction?: string;
|
|
599
|
+
/** Draws a `+` that dispatches this. Absent, there is no `+`. */
|
|
600
|
+
addAction?: string;
|
|
601
|
+
/** The `+`'s tooltip — `New board`. */
|
|
602
|
+
addLabel?: string;
|
|
603
|
+
/** Where the tabs sit: over the boards (default) or under them, as a spreadsheet's do. */
|
|
604
|
+
tabPosition?: "top" | "bottom";
|
|
605
|
+
/** Which end of the strip the prev / next / `+` buttons dock at. Default `end`. */
|
|
606
|
+
pagerPosition?: "start" | "end";
|
|
607
|
+
}
|
|
608
|
+
interface BoardPagesProps<X extends ExtraPanels = Record<never, never>> {
|
|
609
|
+
spec: BoardPagesSpec<X>;
|
|
610
|
+
/** Every page's actions and the strip's own, told apart by `pageId`. */
|
|
611
|
+
onAction?: (actionId: string, ctx?: ActionContext) => void;
|
|
612
|
+
registry?: PanelRegistry;
|
|
613
|
+
icons?: Record<string, React.ComponentType<{
|
|
614
|
+
className?: string;
|
|
615
|
+
}>>;
|
|
616
|
+
className?: string;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* The panels only a board has. Everything a conversation also draws — a
|
|
621
|
+
* table, a band of figures, a record, a chart — is a block, and every block
|
|
622
|
+
* kind is a panel kind too (see `BLOCK_PANELS`).
|
|
623
|
+
*
|
|
624
|
+
* Eight, and the number is meant to stay near it. Another belongs here only
|
|
625
|
+
* when two unrelated surfaces both need it and a conversation does not —
|
|
626
|
+
* otherwise it is a block, or a consumer's registry entry. `events` passes:
|
|
627
|
+
* a run page and a telemetry view both read an engine's event stream.
|
|
628
|
+
*
|
|
629
|
+
* Deliberately absent: **`canvas`**. A flow, a map or a graph needs
|
|
630
|
+
* `@invana/canvas`, and importing it here would put PixiJS in the bundle of
|
|
631
|
+
* every consumer that only wanted tiles and a log. It arrives as a registry
|
|
632
|
+
* entry instead — see the `canvas` note in `types.ts`.
|
|
633
|
+
*/
|
|
634
|
+
declare const BUILT_IN_PANELS: PanelRegistry;
|
|
635
|
+
/**
|
|
636
|
+
* Every kind a board can draw: the blocks, then the panels only a
|
|
637
|
+
* board has, then the consumer's own. Later entries win, so a registered
|
|
638
|
+
* kind replaces a block of the same name — `RUN_PANELS`' `trace` does.
|
|
639
|
+
*/
|
|
640
|
+
declare function resolveRegistry(extra?: PanelRegistry): PanelRegistry;
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* A board, assembled from JSON.
|
|
644
|
+
*
|
|
645
|
+
* The spec says what bands there are, what kind each one is and what data it
|
|
646
|
+
* carries; this decides nothing except layout. That split is the point — the
|
|
647
|
+
* same component renders a run, a step, a plan and a draft, and adding a
|
|
648
|
+
* seventh surface is a new document rather than a new screen.
|
|
649
|
+
*
|
|
650
|
+
* **Behaviour is not in the spec.** Actions carry an `id` and arrive back
|
|
651
|
+
* through `onAction`; a gantt row's pick, a list row's click and a
|
|
652
|
+
* parameter edit all come through the same seam. So a spec can be fetched,
|
|
653
|
+
* stored beside a plan as `board.yml`, diffed between two runs, and handed
|
|
654
|
+
* to a renderer that has never heard of the record it describes.
|
|
655
|
+
*
|
|
656
|
+
* **It owns one scroller.** The body scrolls; no band does. A `PanelBox` is
|
|
657
|
+
* content-height by construction, which is what keeps twenty of them in a
|
|
658
|
+
* column from becoming twenty scroll regions.
|
|
659
|
+
*/
|
|
660
|
+
declare function Board<X extends ExtraPanels = Record<never, never>>({ spec: given, onAction, registry: extraRegistry, icons, stream, onStreamEnd, onStreamError, className, ...props }: BoardProps<X>): React.JSX.Element;
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Several boards in one {@link Workbook} — the open boards of a shell's
|
|
664
|
+
* main section. Each page is a {@link Board} drawn from its own spec; every
|
|
665
|
+
* page stays mounted, so switching keeps a board's scroll and tab.
|
|
666
|
+
*
|
|
667
|
+
* Uncontrolled unless the spec names `selectAction`, as a board's own tabs
|
|
668
|
+
* are: then the pick is reported and `active` is the host's to change.
|
|
669
|
+
*/
|
|
670
|
+
declare function BoardPages<X extends ExtraPanels = Record<never, never>>({ spec, onAction, registry, icons, className, }: BoardPagesProps<X>): React.JSX.Element;
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* A block as a panel: the same JSON a conversation turn draws, framed by the
|
|
674
|
+
* panel. The block draws bare — its title and aside are the panel's — and what
|
|
675
|
+
* it does arrives as `onAction(action, { panelId, value })`, so a row picked in
|
|
676
|
+
* a `table` is `select` with the row's key, told apart by the panel it came from;
|
|
677
|
+
* an action its spec declares arrives by its own id — `approve`.
|
|
678
|
+
*/
|
|
679
|
+
declare function BlockPanel({ panel, options, onAction }: PanelRendererProps): React.JSX.Element;
|
|
680
|
+
/** Every block kind, drawn by {@link BlockPanel}. A kind with no renderer yet is a labelled placeholder. */
|
|
681
|
+
declare const BLOCK_PANELS: PanelRegistry;
|
|
682
|
+
|
|
683
|
+
interface AttemptRow {
|
|
684
|
+
/** `queued` · `attempt 1` · `attempt 2` · `settled`. */
|
|
685
|
+
label: React.ReactNode;
|
|
686
|
+
/** When it started, on the run's own clock — `+44.5s`. */
|
|
687
|
+
started?: React.ReactNode;
|
|
688
|
+
/** How long it took — `30.0s`, or `4.2s…` while it is still running. */
|
|
689
|
+
took?: React.ReactNode;
|
|
690
|
+
/** What happened, in one line. */
|
|
691
|
+
what?: React.ReactNode;
|
|
692
|
+
tone?: "muted" | "info" | "success" | "warning" | "destructive";
|
|
693
|
+
/** It ran and it did not stick. **Struck, never dropped.** */
|
|
694
|
+
struck?: boolean;
|
|
695
|
+
}
|
|
696
|
+
interface AttemptClockProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
697
|
+
rows: AttemptRow[];
|
|
698
|
+
/**
|
|
699
|
+
* What the two numbers are — `elapsed 32.4s · working 2.3s · the gap is the
|
|
700
|
+
* attempt that timed out`.
|
|
701
|
+
*
|
|
702
|
+
* **Stated, never left as arithmetic.** A reader who has to subtract two
|
|
703
|
+
* durations to find a 30-second timeout has been handed a sum instead of an
|
|
704
|
+
* answer.
|
|
705
|
+
*/
|
|
706
|
+
summary?: React.ReactNode;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* A step's clock, attempt by attempt.
|
|
710
|
+
*
|
|
711
|
+
* One duration cannot say what happened to a step that timed out once and then
|
|
712
|
+
* returned: `2.1s` is what it *did*, `32.4s` is what a reader waited, and the
|
|
713
|
+
* gap between them **is** the first attempt. So the clock is a row per attempt
|
|
714
|
+
* — queued, each try, settled — and the try that failed keeps its place, struck.
|
|
715
|
+
*
|
|
716
|
+
* Nothing new is recorded for this: it is the `timing` and `attempt` fields the
|
|
717
|
+
* interpreter already writes, read as a list instead of as a total.
|
|
718
|
+
*/
|
|
719
|
+
declare const AttemptClock: React.ForwardRefExoticComponent<AttemptClockProps & React.RefAttributes<HTMLDivElement>>;
|
|
720
|
+
|
|
721
|
+
interface RecordDescriptionDetail {
|
|
722
|
+
label: React.ReactNode;
|
|
723
|
+
value: React.ReactNode;
|
|
724
|
+
/** The value in the mono face — an id, a mode, a date. */
|
|
725
|
+
mono?: boolean;
|
|
726
|
+
}
|
|
727
|
+
interface RecordDescriptionProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
728
|
+
/** The one field a reader scans — one line, truncated, until `More`. */
|
|
729
|
+
description?: React.ReactNode;
|
|
730
|
+
/** What `More` shows beneath the full description, as label/value pairs. */
|
|
731
|
+
details?: RecordDescriptionDetail[];
|
|
732
|
+
moreLabel?: string;
|
|
733
|
+
lessLabel?: string;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* A record's own metadata, on the line under its `RecordHeader`.
|
|
737
|
+
*
|
|
738
|
+
* The description reads on one line, and `More` puts the rest — the whole
|
|
739
|
+
* description, then the record's facts as a `PropertyList` — in place, and
|
|
740
|
+
* `Less` folds it back. Not in a tooltip or a dialog: the reader is already
|
|
741
|
+
* looking at the record.
|
|
742
|
+
*
|
|
743
|
+
* `More` is there only when there is more: details to show, or a description
|
|
744
|
+
* the line cuts.
|
|
745
|
+
*/
|
|
746
|
+
declare const RecordDescription: React.ForwardRefExoticComponent<RecordDescriptionProps & React.RefAttributes<HTMLDivElement>>;
|
|
747
|
+
|
|
748
|
+
interface StagedBarItem {
|
|
749
|
+
id: string;
|
|
750
|
+
op: DiffOp;
|
|
751
|
+
/** What changed, in the mono face — `airport.timezone`. */
|
|
752
|
+
name: React.ReactNode;
|
|
753
|
+
/** What the change is — `property`, `integer → float`. */
|
|
754
|
+
note?: React.ReactNode;
|
|
755
|
+
}
|
|
756
|
+
interface StagedBarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "children"> {
|
|
757
|
+
items: StagedBarItem[];
|
|
758
|
+
/** Discard one change. Left out, the items carry no `×`. */
|
|
759
|
+
onDiscard?: (id: string) => void;
|
|
760
|
+
/** Discard every change. Left out, there is no `Discard all`. */
|
|
761
|
+
onDiscardAll?: () => void;
|
|
762
|
+
/** The keyboard route to what finishes the set — `⌘↵ publish`. */
|
|
763
|
+
hint?: React.ReactNode;
|
|
764
|
+
discardAllLabel?: string;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* What is staged and not yet published, as one bar across the surface it
|
|
768
|
+
* changes.
|
|
769
|
+
*
|
|
770
|
+
* The count, then each change as a chip with its sign spelled out — a reader
|
|
771
|
+
* who cannot separate red from green still tells an addition from a removal —
|
|
772
|
+
* and its own `×`; `Discard all` and the shortcut that publishes on the right.
|
|
773
|
+
* It sits under the record's header while a draft is open, and not at all
|
|
774
|
+
* otherwise: a bar reading *0 staged* is noise.
|
|
775
|
+
*/
|
|
776
|
+
declare const StagedBar: React.ForwardRefExoticComponent<StagedBarProps & React.RefAttributes<HTMLDivElement>>;
|
|
777
|
+
|
|
778
|
+
/** A chip from its spec — a bound renders as a `BoundChip`, everything else as a `Badge`. */
|
|
779
|
+
declare function SpecChip({ chip }: {
|
|
780
|
+
chip: ChipSpec;
|
|
781
|
+
}): React.JSX.Element;
|
|
782
|
+
declare function SpecChips({ chips }: {
|
|
783
|
+
chips?: ChipSpec[];
|
|
784
|
+
}): React.JSX.Element | null;
|
|
785
|
+
/**
|
|
786
|
+
* An action from its spec.
|
|
787
|
+
*
|
|
788
|
+
* `options` turns it into a segmented switch, because a view switch is one
|
|
789
|
+
* decision with several positions and rendering it as three buttons would let a
|
|
790
|
+
* reader think they could pick two. `picker` draws the same choice as a
|
|
791
|
+
* dropdown, for records too many or too long to lay side by side. `menu` puts
|
|
792
|
+
* them behind the action's own button, as acts rather than a choice.
|
|
793
|
+
*/
|
|
794
|
+
declare function SpecAction({ action, onAction, icons, ctx, }: {
|
|
795
|
+
action: ActionSpec;
|
|
796
|
+
onAction: (id: string, ctx?: ActionContext) => void;
|
|
797
|
+
icons: Record<string, React.ComponentType<{
|
|
798
|
+
className?: string;
|
|
799
|
+
}>>;
|
|
800
|
+
ctx?: ActionContext;
|
|
801
|
+
}): React.JSX.Element;
|
|
802
|
+
declare function SpecActions({ actions, onAction, icons, ctx, }: {
|
|
803
|
+
actions?: ActionSpec[];
|
|
804
|
+
onAction: (id: string, ctx?: ActionContext) => void;
|
|
805
|
+
icons: Record<string, React.ComponentType<{
|
|
806
|
+
className?: string;
|
|
807
|
+
}>>;
|
|
808
|
+
ctx?: ActionContext;
|
|
809
|
+
}): React.JSX.Element | null;
|
|
810
|
+
|
|
811
|
+
declare function JsonPanel({ options }: PanelRendererProps<JsonOptions>): React.JSX.Element;
|
|
812
|
+
declare function CodePanel({ options }: PanelRendererProps<CodeOptions>): React.JSX.Element;
|
|
813
|
+
/**
|
|
814
|
+
* A labelled pair of mono blocks — a prompt and what came back.
|
|
815
|
+
*
|
|
816
|
+
* Its own kind rather than two `code` panels, because the two are one record:
|
|
817
|
+
* a completion shown without the prompt that produced it is not evidence.
|
|
818
|
+
*/
|
|
819
|
+
declare function ExchangePanel({ options }: PanelRendererProps<ExchangeOptions>): React.JSX.Element;
|
|
820
|
+
|
|
821
|
+
declare function LogPanel({ options }: PanelRendererProps<LogOptions>): React.JSX.Element;
|
|
822
|
+
/**
|
|
823
|
+
* Rows that are not a table: artifacts, the runs of a plan, a version history.
|
|
824
|
+
*
|
|
825
|
+
* A table is for values you compare down a column. These are records you scan
|
|
826
|
+
* and open, which is what `Item` is for — so a list panel is never a
|
|
827
|
+
* one-column table.
|
|
828
|
+
*/
|
|
829
|
+
declare function ListPanel({ panel, options, onAction, icons }: PanelRendererProps<ListOptions>): React.JSX.Element;
|
|
830
|
+
declare function ParamsPanel({ panel, options, onAction }: PanelRendererProps<ParamsOptions>): React.JSX.Element;
|
|
831
|
+
declare function TextPanel({ panel, options, onAction, icons }: PanelRendererProps<TextOptions>): React.JSX.Element;
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* The run's event stream — see {@link EventsOptions}. Both layouts read the
|
|
835
|
+
* same events, so a log and a tree of one run never disagree.
|
|
836
|
+
*/
|
|
837
|
+
declare function EventsPanel(props: PanelRendererProps<EventsOptions>): React.JSX.Element;
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* The panels a **run page** is made of.
|
|
841
|
+
*
|
|
842
|
+
* They are not in `BUILT_IN_PANELS`, and that is deliberate: the built-in list
|
|
843
|
+
* is eleven kinds two unrelated surfaces each need, and these six are one
|
|
844
|
+
* surface family's — a run read in order, what it touched, a step's clock, the
|
|
845
|
+
* files it left, what governed it, and the ask it settled. The layers it spent
|
|
846
|
+
* are the `gantt` block — a row per layer, a bar per task that reached it — so
|
|
847
|
+
* a conversation draws them too.
|
|
848
|
+
* Shipping them here rather than in the default registry keeps a consumer that
|
|
849
|
+
* only wanted tiles and a log from carrying the run vocabulary, while keeping
|
|
850
|
+
* the adapter in the kit rather than copied into every product that draws runs.
|
|
851
|
+
*
|
|
852
|
+
* ```ts
|
|
853
|
+
* <Board spec={spec} registry={RUN_PANELS} />
|
|
854
|
+
* ```
|
|
855
|
+
*/
|
|
856
|
+
/** One row of a trace — a step, a loop that holds rows, or a gate between them. */
|
|
857
|
+
type TraceEntry = {
|
|
858
|
+
kind?: "step";
|
|
859
|
+
seq?: number | string;
|
|
860
|
+
name: string;
|
|
861
|
+
description?: string;
|
|
862
|
+
layer?: string;
|
|
863
|
+
role?: string;
|
|
864
|
+
duration?: string;
|
|
865
|
+
note?: string;
|
|
866
|
+
/** The exception this row carries — `↺ 2 of 3`, `live`, `↳ delegates`. */
|
|
867
|
+
mark?: string;
|
|
868
|
+
markTone?: React.ComponentProps<typeof MarkChip>["tone"];
|
|
869
|
+
depth?: number;
|
|
870
|
+
dim?: boolean;
|
|
871
|
+
struck?: boolean;
|
|
872
|
+
/** Fired as `selectAction` with `{ stepId }`. */
|
|
873
|
+
id?: string;
|
|
874
|
+
} | {
|
|
875
|
+
kind: "loop";
|
|
876
|
+
label: string;
|
|
877
|
+
summary?: string;
|
|
878
|
+
tone?: "warning" | "info" | "muted";
|
|
879
|
+
rounds: TraceEntry[];
|
|
880
|
+
} | {
|
|
881
|
+
kind: "gate";
|
|
882
|
+
label: string;
|
|
883
|
+
note?: string;
|
|
884
|
+
tone?: "destructive" | "warning" | "muted";
|
|
885
|
+
edge?: "before" | "after";
|
|
886
|
+
};
|
|
887
|
+
interface TraceOptions {
|
|
888
|
+
entries: TraceEntry[];
|
|
889
|
+
palette?: LayerPalette;
|
|
890
|
+
/** Which step is open elsewhere. */
|
|
891
|
+
selectedId?: string | null;
|
|
892
|
+
/** Dispatched with `{ stepId }` when a row is picked. */
|
|
893
|
+
selectAction?: string;
|
|
894
|
+
}
|
|
895
|
+
interface TouchedOptions {
|
|
896
|
+
items: TouchItem[];
|
|
897
|
+
palette?: LayerPalette;
|
|
898
|
+
}
|
|
899
|
+
interface AttemptsOptions {
|
|
900
|
+
rows: AttemptRow[];
|
|
901
|
+
summary?: string;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* One file a step left, as **data**.
|
|
905
|
+
*
|
|
906
|
+
* `ArtifactTable`'s own `Artifact` types every cell as a `ReactNode`, which a
|
|
907
|
+
* spec cannot be. These are strings: a board is fetched, stored beside a
|
|
908
|
+
* plan and diffed, and a `ReactNode` survives none of that.
|
|
909
|
+
*/
|
|
910
|
+
interface ArtifactSpec {
|
|
911
|
+
name: string;
|
|
912
|
+
kind?: string;
|
|
913
|
+
size?: string;
|
|
914
|
+
/** The address — eight characters, drawn mono ([SR58]). */
|
|
915
|
+
digest?: string;
|
|
916
|
+
written?: string;
|
|
917
|
+
/** Retention took the bytes. The row stays, struck. */
|
|
918
|
+
gone?: boolean;
|
|
919
|
+
}
|
|
920
|
+
interface ArtifactsOptions {
|
|
921
|
+
files: ArtifactSpec[];
|
|
922
|
+
/** Dispatched with `{ digest, name, index }`. Omitted, the column is absent. */
|
|
923
|
+
openAction?: string;
|
|
924
|
+
downloadAction?: string;
|
|
925
|
+
}
|
|
926
|
+
/** One lens row under the layer it narrows. */
|
|
927
|
+
interface LensRowSpec {
|
|
928
|
+
name: string;
|
|
929
|
+
narrows?: Narrowing[];
|
|
930
|
+
usage?: LensUsage;
|
|
931
|
+
}
|
|
932
|
+
/** One participant the world allowed, and what the run did with it ([SR53]). */
|
|
933
|
+
interface ParticipantSpec {
|
|
934
|
+
address: string;
|
|
935
|
+
/** `touched` · `never touched` · `refused` · `miss` — any word the engine writes. */
|
|
936
|
+
verdict: string;
|
|
937
|
+
/** What came back, or why nothing did — `1,284 rows · step 7`. */
|
|
938
|
+
note?: string;
|
|
939
|
+
}
|
|
940
|
+
interface LensSectionSpec {
|
|
941
|
+
layer: Layer;
|
|
942
|
+
summary?: string;
|
|
943
|
+
count?: number;
|
|
944
|
+
/** Nothing narrows this layer. Drawn dim rather than dropped. */
|
|
945
|
+
dim?: boolean;
|
|
946
|
+
/**
|
|
947
|
+
* **A section carries one of two readings, and they are different questions.**
|
|
948
|
+
* `participants` is a *run's* lens — every address the world allowed, each
|
|
949
|
+
* marked with what this execution did with it. `rows` is a *world's* — the
|
|
950
|
+
* lenses that narrow this layer, as they read in the Govern drawer. A section
|
|
951
|
+
* that gives both draws both, participants first.
|
|
952
|
+
*/
|
|
953
|
+
participants?: ParticipantSpec[];
|
|
954
|
+
rows?: LensRowSpec[];
|
|
955
|
+
}
|
|
956
|
+
interface LensOptions {
|
|
957
|
+
sections: LensSectionSpec[];
|
|
958
|
+
palette?: LayerPalette;
|
|
959
|
+
/** Which lens is open elsewhere, by name. */
|
|
960
|
+
selected?: string | null;
|
|
961
|
+
/** Dispatched with `{ lens }` when a row is picked. */
|
|
962
|
+
selectAction?: string;
|
|
963
|
+
}
|
|
964
|
+
interface ClarificationOption {
|
|
965
|
+
label: string;
|
|
966
|
+
/** The one that was taken. */
|
|
967
|
+
chosen?: boolean;
|
|
968
|
+
}
|
|
969
|
+
interface ClarificationOptions {
|
|
970
|
+
/** Who asked — `the agent asks`. */
|
|
971
|
+
asker?: string;
|
|
972
|
+
question: string;
|
|
973
|
+
/** Why it had to ask, in the step's own terms. */
|
|
974
|
+
why?: string;
|
|
975
|
+
options?: ClarificationOption[];
|
|
976
|
+
answerer?: string;
|
|
977
|
+
answer?: string;
|
|
978
|
+
/** What it cost and what happened next — `after 41.2s · resumed on round 2`. */
|
|
979
|
+
answerNote?: string;
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* The six kinds, as a type argument for `BoardSpec`.
|
|
983
|
+
*
|
|
984
|
+
* A `type` and not an `interface`: `ExtraPanels` is `Record<string, unknown>`,
|
|
985
|
+
* which an interface never satisfies — it has no implicit index signature — so
|
|
986
|
+
* an interface here would compile everywhere except at the one call site that
|
|
987
|
+
* matters.
|
|
988
|
+
*/
|
|
989
|
+
type RunPanelOptions = {
|
|
990
|
+
trace: TraceOptions;
|
|
991
|
+
touched: TouchedOptions;
|
|
992
|
+
attempts: AttemptsOptions;
|
|
993
|
+
artifacts: ArtifactsOptions;
|
|
994
|
+
lens: LensOptions;
|
|
995
|
+
clarification: ClarificationOptions;
|
|
996
|
+
};
|
|
997
|
+
declare function TracePanel({ panel, options, onAction, }: PanelRendererProps<TraceOptions>): React.JSX.Element;
|
|
998
|
+
declare function TouchedPanel({ options }: PanelRendererProps<TouchedOptions>): React.JSX.Element;
|
|
999
|
+
declare function AttemptsPanel({ options }: PanelRendererProps<AttemptsOptions>): React.JSX.Element;
|
|
1000
|
+
/** Merge into a board's registry to draw a run — see the note above. */
|
|
1001
|
+
declare const RUN_PANELS: {
|
|
1002
|
+
trace: typeof TracePanel;
|
|
1003
|
+
touched: typeof TouchedPanel;
|
|
1004
|
+
attempts: typeof AttemptsPanel;
|
|
1005
|
+
artifacts: typeof ArtifactsPanel;
|
|
1006
|
+
lens: typeof LensPanel;
|
|
1007
|
+
clarification: typeof ClarificationPanel;
|
|
1008
|
+
};
|
|
1009
|
+
declare function ArtifactsPanel({ panel, options, onAction, }: PanelRendererProps<ArtifactsOptions>): React.JSX.Element;
|
|
1010
|
+
declare function LensPanel({ panel, options, onAction }: PanelRendererProps<LensOptions>): React.JSX.Element;
|
|
1011
|
+
declare function ClarificationPanel({ options, }: PanelRendererProps<ClarificationOptions>): React.JSX.Element;
|
|
1012
|
+
|
|
1013
|
+
export { type ActionContext, type ActionSpec, type AnyBoardSpec, type ArtifactSpec, type ArtifactsOptions, ArtifactsPanel, AttemptClock, type AttemptClockProps, type AttemptRow, type AttemptsOptions, AttemptsPanel, BLOCK_PANELS, BUILT_IN_PANELS, BlockPanel, type BlockPanelSpec, Board, type BoardPageSpec, BoardPages, type BoardPagesProps, type BoardPagesSpec, type BoardPatch, BoardPatchError, type BoardPatchOp, type BoardProps, type BoardSpec, type BuiltInPanelKind, type BuiltInPanelSpec, type ChipSpec, type ClarificationOption, type ClarificationOptions, ClarificationPanel, type CodeOptions, CodePanel, type CrumbMenuSpec, type CustomOptions, type EventSpec, type EventsOptions, EventsPanel, type ExchangeOptions, ExchangePanel, type ExtraPanels, type HeaderSpec, type InspectorSpec, type JsonOptions, JsonPanel, type LensOptions, LensPanel, type LensRowSpec, type LensSectionSpec, type ListOptions, ListPanel, type LogOptions, LogPanel, type PanelBase, type PanelOptions, type PanelOptionsByKind, type PanelRegistry, type PanelRenderer, type PanelRendererProps, type PanelSpec, type ParamsOptions, ParamsPanel, type ParticipantSpec, RUN_PANELS, RecordDescription, type RecordDescriptionDetail, type RecordDescriptionProps, type RegisteredPanelSpec, type RowSpec, type RunPanelOptions, SpecAction, SpecActions, SpecChip, SpecChips, StagedBar, type StagedBarItem, type StagedBarProps, type StagedSpec, type TabSpec, type TextOptions, TextPanel, type Tone, type TouchedOptions, TouchedPanel, type TraceEntry, type TraceOptions, TracePanel, applyBoardPatch, applyBoardPatches, resolveRegistry };
|