@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 ADDED
@@ -0,0 +1,130 @@
1
+ # @invana/boards
2
+
3
+ A board is **data**. This package takes a JSON-serialisable `BoardSpec` and renders it
4
+ from blocks (`@invana/blocks`) and a few panels only a board has — so one component covers
5
+ many screens, and a spec can be fetched from an API, stored beside a plan as `board.yml`, and
6
+ diffed between two runs. A panel of a block kind is drawn from the same JSON a conversation turn
7
+ is.
8
+
9
+ ```bash
10
+ pnpm add @invana/boards
11
+ ```
12
+
13
+ ## Peer dependencies
14
+
15
+ ```bash
16
+ pnpm add @invana/blocks @invana/ui @invana/charts @invana/tables @invana/styling @invana/forms @invana/editor react-hook-form react react-dom
17
+ ```
18
+
19
+ Styles come from `@invana/styling` — see [its README](../styling/README.md) for the Tailwind v4
20
+ import order.
21
+
22
+ ## Usage
23
+
24
+ The spec says what bands exist, what kind each is and what data it carries. The component decides
25
+ layout and nothing else.
26
+
27
+ ```tsx
28
+ import { Board, type BoardSpec } from '@invana/boards';
29
+
30
+ const spec: BoardSpec = {
31
+ header: {
32
+ tone: 'success',
33
+ crumbs: ['orders.csv → Brokerage.Order', 'import_dataset'],
34
+ chips: [{ label: 'succeeded', tone: 'success' }],
35
+ actions: [{ id: 'more', icon: 'more', variant: 'ghost' }],
36
+ },
37
+ rows: [
38
+ {
39
+ panels: [
40
+ {
41
+ kind: 'grid',
42
+ options: {
43
+ tiles: [
44
+ { label: 'Status', value: 'ok', delta: 'first attempt', tone: 'good' },
45
+ { label: 'Duration', value: '3.4s', delta: '72% of the run' },
46
+ ],
47
+ },
48
+ },
49
+ ],
50
+ },
51
+ {
52
+ panels: [
53
+ {
54
+ kind: 'json',
55
+ title: 'result.json',
56
+ options: { value: { written: 1204, dataset_id: 'ds_9f2c' } },
57
+ },
58
+ ],
59
+ },
60
+ ],
61
+ };
62
+
63
+ <Board spec={spec} onAction={(id, ctx) => console.log(id, ctx)} />;
64
+ ```
65
+
66
+ ### Behaviour is not in the spec
67
+
68
+ A function is not JSON, so actions carry an `id` and come back through a single
69
+ `onAction(actionId, ctx)`. `ctx` tells you which panel it came from and, where the panel has a
70
+ selection, what was selected (`taskKey`, `itemId`, `param`, `option`). A block panel sends the
71
+ block's own action with what it carries as `value` — a `table` row picked is
72
+ `onAction('select', { panelId, value: <rowKey value> })`, a `form` submitted is `reply`.
73
+
74
+ Icons are passed in by name via the `icons` prop — the spec only ever carries the string. Unknown
75
+ names render nothing, so this package pulls in no icon set of its own.
76
+
77
+ ## Panel kinds
78
+
79
+ - **Every block kind** (`BLOCKS` in `@invana/blocks`): `options` are the block's options,
80
+ checked against `BlockOptionsByKind`. The block draws bare; the panel's `title`, `aside` and
81
+ `absent` frame it. A kind with no renderer yet is a labelled placeholder.
82
+ - **Panels only a board has:** `json` · `code` · `exchange` · `log` · `list` · `params` ·
83
+ `text`.
84
+
85
+ Every panel is drawn in a `PanelBox`, as an answer card frames every block, so one spec draws the
86
+ same in a board and a conversation. `title` adds the label bar; `flush` drops the padding.
87
+
88
+ ### From the old panels
89
+
90
+ | Was | Now | Changes |
91
+ | --- | --- | --- |
92
+ | `metrics` | `grid` | `caption` → `delta`; `meter: n` → `gauge: { value: n, max: 1 }`; `tone` is `good`/`bad`/`warn`/`neutral` and colours the `delta` (`running`, `info` are gone; `flag` marks the tile to look at) |
93
+ | `properties` | `record` | `mono` defaults to `true` as before; `labelWidth` is gone |
94
+ | `table` | `table` | Columns set `mono: true` (the default is now off); `selectAction` is gone — a pick is `select` with `{ panelId, value }` |
95
+ | `gantt` | `gantt` (a block) | A conversation draws it too, so it is a block. `selectedKey` → `selected`; `selectAction` is gone — a pick is `select` with `{ panelId, value }` (the task's key, which was `taskKey`); a task's `subtasks` nest under it |
96
+
97
+ ## Extra panel kinds
98
+
99
+ A board's type is **parametrised by its registry**, which is how the built-in kinds stay
100
+ type-checked. Register a kind by saying what its options are:
101
+
102
+ ```tsx
103
+ import { Board, type BoardSpec } from '@invana/boards';
104
+
105
+ type Extra = { canvas: { nodes: MyFlowNode[] } };
106
+
107
+ const spec: BoardSpec<Extra> = { rows: [{ panels: [{ kind: 'canvas', options: { nodes } }] }] };
108
+
109
+ <Board<Extra> spec={spec} registry={{ canvas: MyFlowPanel }} />;
110
+ ```
111
+
112
+ `@invana/canvas` arrives this way rather than as an import, so PixiJS stays out of the bundle of
113
+ every consumer that only wanted tiles and a log.
114
+
115
+ A registered kind wins over a block of the same name, at runtime and in the types: `RUN_PANELS`
116
+ registers its own `trace`, which replaces the `trace` block on that board.
117
+
118
+ For a spec arriving off the wire, where nothing can be checked anyway, use `AnyBoardSpec`.
119
+
120
+ ## Exports
121
+
122
+ `Board`, `BlockPanel` and `BLOCK_PANELS`, the panel components (`JsonPanel`, `CodePanel`,
123
+ `ExchangePanel`, `LogPanel`, `ListPanel`, `ParamsPanel`, `TextPanel`), `RUN_PANELS`,
124
+ `SpecChip(s)` / `SpecAction(s)`, `BUILT_IN_PANELS`, `resolveRegistry`, the spec types, and the
125
+ parts only a board draws: `RecordDescription` (the line under the header), `StagedBar` (`spec.staged`)
126
+ and `AttemptClock` (the `attempts` run panel). They moved here from `@invana/ui`.
127
+
128
+ ## License
129
+
130
+ MIT © Ravi Raja Merugu