@ai-matrx/records-ui 0.10.3 → 0.16.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/CHANGELOG.md +181 -0
- package/dist/index.cjs +2414 -1754
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +240 -76
- package/dist/index.d.ts +240 -76
- package/dist/index.js +2160 -1496
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,186 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records-ui
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
**The grid never draws a row before it knows what the person may do.** My own
|
|
6
|
+
regression from 0.12.0's refresh fix, bisected rather than guessed: treating the
|
|
7
|
+
whole first load as "the rows have arrived" let the grid render while the
|
|
8
|
+
table's own read was still in flight, and `useTableRights` answers `NO_RIGHTS`
|
|
9
|
+
(`known: false`) then — so every cell came out as plain text with no editor and
|
|
10
|
+
a click on it did nothing and said nothing. The declaration, the columns and the
|
|
11
|
+
person's own level are answered ONCE per table, so they are a FIRST LOAD; only
|
|
12
|
+
the page re-read is a refresh, and it still never blanks rows somebody is
|
|
13
|
+
already typing in.
|
|
14
|
+
|
|
15
|
+
**A publish gate that can be believed.** This package had not published since
|
|
16
|
+
0.10.3 while five versions piled up, because `pnpm test` ran the whole live
|
|
17
|
+
component suite against a database several lanes' harnesses share behind one
|
|
18
|
+
advisory lock — each run failed a different handful of timing clauses with no
|
|
19
|
+
overlap. `pnpm test` is now a DETERMINISTIC component suite (the real components
|
|
20
|
+
against recorded real-door answers at this package's own `RecordsDataSource`
|
|
21
|
+
seam, no network, and a call the fixture never saw throws by name) plus a SHORT
|
|
22
|
+
live smoke (declare a table, take a column, write, read back, page, delete).
|
|
23
|
+
Typecheck and both suites run in 27 seconds. The full live suite is
|
|
24
|
+
`pnpm test:live` and runs in its own workflow on the tag and on a schedule,
|
|
25
|
+
reporting red loudly and blocking nothing. Nothing was deleted or loosened.
|
|
26
|
+
|
|
27
|
+
**And the two suites that could not run on a lane's own port** —
|
|
28
|
+
`system-table-shape` and `walk` pinned 127.0.0.1:3005 — now read
|
|
29
|
+
`RECORDS_UI_DEMO_PORT`.
|
|
30
|
+
|
|
31
|
+
### Consumer action
|
|
32
|
+
|
|
33
|
+
None. No API changed. `pnpm test:record` re-records the door fixture.
|
|
34
|
+
|
|
35
|
+
## 0.15.0
|
|
36
|
+
|
|
37
|
+
**`ActionInbox` reads the STORE's queue, and the package-owned one is gone.**
|
|
38
|
+
SCR-11 shipped with its own `records_ui_action` Table: agents wrote rows into it
|
|
39
|
+
and it rendered them beautifully. It was a second source of truth. An approval a
|
|
40
|
+
person filed through the store, and the wait the server's own `field_propose`
|
|
41
|
+
produces under `ask`, appeared nowhere in it — which is exactly the thing
|
|
42
|
+
PRODUCTS.md row 6 says the product must not be ("One inbox holds human approvals
|
|
43
|
+
AND the agent's field and table proposals — the same queue, the same right to
|
|
44
|
+
approve").
|
|
45
|
+
|
|
46
|
+
It now reads `custom.work_inbox` and decides through `custom.work_approval_decide`,
|
|
47
|
+
which APPLIES the change in the same transaction as the decision, as the person
|
|
48
|
+
who approved, through the store's own doors.
|
|
49
|
+
|
|
50
|
+
* **Keyboard-first**, because Linear's inbox is the bar: `j`/`k` or the arrows
|
|
51
|
+
move, `a` approves, `d` declines, `o` opens, `r` refreshes. The selected row
|
|
52
|
+
scrolls into view and the header states the keys.
|
|
53
|
+
* **Level-aware, absent rather than dead.** The door answers `actionable` — which
|
|
54
|
+
is `custom.work_approval_may_decide` asked per row — so a row this person may
|
|
55
|
+
not decide renders with NO buttons and says what it is waiting for, instead of
|
|
56
|
+
a greyed-out Approve that fails when clicked. The person who ASKED for a change
|
|
57
|
+
is refused the answer to their own request, by the store, and the row says so.
|
|
58
|
+
* The store's own outcome sentence is shown verbatim ("Rate card is now a column
|
|
59
|
+
on this table"); this component never rewrites it.
|
|
60
|
+
|
|
61
|
+
**Consumer action — BREAKING for anybody who seeded the old queue.**
|
|
62
|
+
`ACTION_TABLE`, `actionDocument`, `QueuedAction`, `QueuedActionSpec` and the
|
|
63
|
+
`seed` prop are removed. Nothing seeds an inbox any more: a person or an agent
|
|
64
|
+
files a real request through `custom.work_approval_request`
|
|
65
|
+
(`client.workApprovalRequest(...)`) and it appears. `ActionInbox` keeps
|
|
66
|
+
`tableId`, `includeSettled`, `onOpenRecord` and `className`. Requires
|
|
67
|
+
`@ai-matrx/records` 0.10.0.
|
|
68
|
+
|
|
69
|
+
## 0.12.0
|
|
70
|
+
|
|
71
|
+
**Everything 0.11.0 carried — the level-aware screens and the one refusal
|
|
72
|
+
formatter below — is in this release. 0.11.0 was tagged and never published: its
|
|
73
|
+
gate failed, and two of the four failures were real defects rather than stale
|
|
74
|
+
copy. They are what this version fixes.**
|
|
75
|
+
|
|
76
|
+
**A read the person did not ask for no longer takes the cell they are typing in
|
|
77
|
+
off the screen.** `Grid` handed `MatrxDataTable` an `isLoading` that went true on
|
|
78
|
+
every `reload()`, and a cell write reloads the page — while `isLoading` the data
|
|
79
|
+
table renders six SKELETON rows IN PLACE OF the real ones, so committing one cell
|
|
80
|
+
unmounted every cell on the page, the open editor included. In a browser that
|
|
81
|
+
costs the caret and any keystroke inside the window; in the live suite one column
|
|
82
|
+
of a tabbed row saved as nothing, a different one each run, which is what made it
|
|
83
|
+
look like the store rather than the screen. A refresh is now `isFetching` — the
|
|
84
|
+
data table's own refresh line, with the rows kept — and `isLoading` means only
|
|
85
|
+
what it says: there is nothing to show yet.
|
|
86
|
+
|
|
87
|
+
**Enter finishes a long-text cell, and Shift+Enter makes the newline.** It used
|
|
88
|
+
to be the other way round, with Ctrl/Cmd+Enter to save, printed in 10px under the
|
|
89
|
+
box: the key every grid in the world binds did nothing in the columns whose
|
|
90
|
+
values are longest. Airtable is the bar. A json cell takes its newline the same
|
|
91
|
+
way — it was not counted as multi-line at all, so Enter could not save it either.
|
|
92
|
+
|
|
93
|
+
**One version read per record, and a version only ever goes up.** Opening a cell
|
|
94
|
+
asked the store for the record's version, and tabbing on asked again before
|
|
95
|
+
either answer was back; the write between them stored the store's new version,
|
|
96
|
+
and whichever read landed last put the old one back. The next cell of that row
|
|
97
|
+
then carried a version the store had already moved past, and a person tabbing
|
|
98
|
+
through their own row was shown a conflict with themselves.
|
|
99
|
+
|
|
100
|
+
**A borrowed value and a total can be built over a Person or a File again.**
|
|
101
|
+
`ValueOnTheOtherSide` offers the columns the relation's target Table DECLARES —
|
|
102
|
+
and a Person column points at the person kernel, which has 441 records and zero
|
|
103
|
+
Field rows, so it offered nothing and said the table had no columns. The store
|
|
104
|
+
reads the far side as `custom.record_values(…) -> pick`, so a pick names a key
|
|
105
|
+
those records CARRY: when the target declares no Fields, the panel reads one of
|
|
106
|
+
its records through the ordinary read door and offers the keys it has.
|
|
107
|
+
|
|
108
|
+
### Consumer action
|
|
109
|
+
|
|
110
|
+
None beyond 0.11.0's (below): no API changed. Requires `@ai-matrx/records`
|
|
111
|
+
>= 0.7.0 for `custom.my_levels`.
|
|
112
|
+
|
|
113
|
+
## 0.11.0 — tagged, never published
|
|
114
|
+
|
|
115
|
+
**The screens never invite an action the ladder will refuse.** The 19–20
|
|
116
|
+
September verdict (sixth pass), measured against Airtable, Notion and Linear:
|
|
117
|
+
"None of these three products lets you start an action it already knows it will
|
|
118
|
+
reject."
|
|
119
|
+
|
|
120
|
+
**Every control follows the level the STORE answers.** The rights question was a
|
|
121
|
+
port with two honest answers and no third — nothing offered, or
|
|
122
|
+
`storeDecidesRights`: yes to everything for every non-kernel table, for
|
|
123
|
+
everybody, and let the door refuse afterwards. That second one is what every
|
|
124
|
+
person in the product met, and it is the defect written down. `useTableRights`
|
|
125
|
+
now asks `custom.my_levels` (a table is a record), `useRecordRights` asks for one
|
|
126
|
+
record, and `useRowRights` asks for a whole page in ONE call — and only when the
|
|
127
|
+
table's own level does not already admit editing, because a record shared at
|
|
128
|
+
Editor inside a table held at Viewer is exactly what the verdict found and the
|
|
129
|
+
grid labelled that row "viewer" while the store let its holder write to it.
|
|
130
|
+
|
|
131
|
+
`src/rights.ts` is the ONE place a level becomes a screen: six capabilities —
|
|
132
|
+
read, comment, write, remove, share, structure — each keyed to the rung the DOOR
|
|
133
|
+
itself asks for. Every `false` carries the sentence that says why, naming the
|
|
134
|
+
level it would take and who can give it: *"You are Viewer here, and it takes
|
|
135
|
+
Editor to change anything here. Ask somebody who is Admin on it to move you up."*
|
|
136
|
+
Absent AND explained. A cell a person may not write is plain text that says so
|
|
137
|
+
on hover; Tab walks PAST a row they may not write rather than opening an editor
|
|
138
|
+
in it; Delete is absent on those rows; Share is absent below Admin; the field
|
|
139
|
+
panel and the table settings say what changing the shape of a table takes.
|
|
140
|
+
|
|
141
|
+
**One formatter, and every refusal goes through it.** `src/plainWords.ts`;
|
|
142
|
+
`Refusal.tsx` renders what it returns and NOTHING else — no `error.message`, no
|
|
143
|
+
`error.hint`, no SQLSTATE where a person reads. Filtering the hint was not
|
|
144
|
+
enough, structurally: the store builds its access refusals with `format()` from
|
|
145
|
+
THE DOOR'S OWN NAME, so the machine identity is inside the sentence written for
|
|
146
|
+
the person ("You do not have access to this record, so `custom.record_update`
|
|
147
|
+
may not write to it"). The formatter drops the machine clause by SHAPE, keeps
|
|
148
|
+
the store's own words where they are a person's words, and ADDS A REMEDY keyed
|
|
149
|
+
off the refusal code — a refusal with nothing to do about it is a dead end with
|
|
150
|
+
an explanation. What it drops is kept for an engineer on the notice and in a
|
|
151
|
+
screen-reader-only line. Nine screens that had captured `error.message` into
|
|
152
|
+
their own state now go through it too.
|
|
153
|
+
|
|
154
|
+
**A borrowed value and a total no longer ask for an internal key.** "The value
|
|
155
|
+
to read" was a free-text box with the placeholder `name`; the relation already
|
|
156
|
+
says which Table it points at, so both now offer that Table's columns BY NAME.
|
|
157
|
+
|
|
158
|
+
**All sixteen column types open their own editor.** Four editor states that drew
|
|
159
|
+
a paragraph rather than a box — a choice list loading, a choice list whose Table
|
|
160
|
+
is empty, a multi-choice row, a worked-out column — carried no cell id, so the
|
|
161
|
+
cell could not identify itself. Verified keyboard-only against the live store:
|
|
162
|
+
sixteen open, nine typed kinds land, the date included.
|
|
163
|
+
|
|
164
|
+
**Internal names, swept, by a guard that reads rendered text node by node.** Gone
|
|
165
|
+
from where a person reads: the derived key under the field panel's name box; the
|
|
166
|
+
machine key as a history label and raw JSON for unknown history values; the
|
|
167
|
+
conflict line's key and two JSON blobs; the record panel's provenance rows as
|
|
168
|
+
JSON; a truncated uuid standing in for an unnamed subject's name; JSON dumps in
|
|
169
|
+
cells and in the grid's conflict line.
|
|
170
|
+
|
|
171
|
+
### Consumer action
|
|
172
|
+
|
|
173
|
+
**None for the three mount sites in matrx-frontend** — they already pass
|
|
174
|
+
`letTheStoreDecideRights`, which now means what it says: bind no `rights` port
|
|
175
|
+
and the package asks the store. `storeDecidesRights` is DEPRECATED and answers
|
|
176
|
+
"not known": it is synchronous, the honest answer needs a door call, and a port
|
|
177
|
+
bound there would OVERRIDE the store's answer. A host that binds `rights` of its
|
|
178
|
+
own still wins, and `tableRightsAt(level)` is the one way to build that answer
|
|
179
|
+
by hand — it takes the LEVEL, never six booleans, so nobody can hand a screen a
|
|
180
|
+
combination the ladder cannot produce.
|
|
181
|
+
|
|
182
|
+
Requires `@ai-matrx/records` >= 0.7.0 for `custom.my_levels`.
|
|
183
|
+
|
|
3
184
|
## 0.10.3
|
|
4
185
|
|
|
5
186
|
Reissues the unpublished 0.10.2 candidate. Its live-store release gate exposed
|