@ai-matrx/records-ui 0.85.8 → 0.85.10
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 +85 -0
- package/dist/index.cjs +6202 -5849
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +300 -245
- package/dist/index.d.ts +300 -245
- package/dist/index.js +7927 -7574
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, ComponentType, RefObject } from 'react';
|
|
3
3
|
import * as _ai_matrx_records from '@ai-matrx/records';
|
|
4
|
-
import { PermissionLevel, Table, RecordScopeContext, EnrichCell, RecordsError, Uuid as Uuid$1, StoreFilter, AggregateFilter, Field, RecordDocument, ReadRow, RelationDisplay, WriteConflict, RecordsErrorCode, TableDecorations, DeclarableFieldKind, ParityFieldType, NewFieldDeclaration,
|
|
4
|
+
import { PermissionLevel, Table, RecordScopeContext, EnrichCell, RecordsError, Uuid as Uuid$1, StoreFilter, AggregateFilter, Field, RecordDocument, ReadRow, RelationDisplay, WriteConflict, RecordsErrorCode, TableDecorations, RecordFilter, RuleExpression, RecordsResult, SavedViewRow, DeclarableFieldKind, ParityFieldType, NewFieldDeclaration, HiddenFieldNotice, ValueEnvelope, ChecklistRequirementKind, ContextPolicy, WorkDueState, FieldSensitivity, StageRuleOnFail, SubscriptionCadence, WorkApprovalState, WorkInboxKind, FieldKind, ArchiveLane, ArchivedRow, WorkInboxView, WorkInboxItem, FormSummary, PortalCard, PortalPrincipal, PortalPreviewRow, MySubscription, DashboardBlockKind, AggregateBucket, AggregateMeasure, AggregateCompare, DashboardTarget, DashboardBlock, DashboardSummary, DocTemplateRow, DocRenderRow, QuietHours, DashboardBlockResult, ChecklistRunStep, BookingSummary, CaptureSheetFace, CaptureField, AnonTokenBinding, RecordsConfig, RecordsActor, RecordsDataSource, HistoryActor, FieldHistoryEntry } from '@ai-matrx/records';
|
|
5
5
|
import { Uuid, StoreFilter as StoreFilter$1, Field as Field$1, ReadRow as ReadRow$1 } from '@ai-matrx/records/react';
|
|
6
6
|
import { RecordsClient } from '@ai-matrx/records/core';
|
|
7
7
|
export { DEFAULT_FIELDS, DeclareResult, NewFieldSpec, NewTableSpec, addFields, declareTable, fieldDeclarationFor, tokenFor } from '@ai-matrx/records/core';
|
|
@@ -650,6 +650,7 @@ declare function useRowRights(rowIds: Uuid$1[], enabled: boolean): (rowId: Uuid$
|
|
|
650
650
|
* `retention_days` a document key, snake_case
|
|
651
651
|
* `8f2c1b0a-…` a uuid
|
|
652
652
|
* `23514` / `PT409` a SQLSTATE
|
|
653
|
+
* `STORE-TAILS-3:` / `UI-FIX-19:` a build lane's tag (UI-FIX-19)
|
|
653
654
|
*/
|
|
654
655
|
declare const MACHINE_IDENTITY: RegExp[];
|
|
655
656
|
/** Whether any shape above appears in this text. */
|
|
@@ -1227,12 +1228,292 @@ declare function styleFromDecorations(decorations: TableDecorations | null | und
|
|
|
1227
1228
|
*/
|
|
1228
1229
|
declare function resolveTableStyle(decorations: TableDecorations | null | undefined, fields: readonly Field[], viewStyle: TableStyle | undefined): TableStyle;
|
|
1229
1230
|
|
|
1231
|
+
/** The four ways one saved view can be looked at (SCR-6). */
|
|
1232
|
+
declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery"];
|
|
1233
|
+
type ViewLayout = (typeof VIEW_LAYOUTS)[number];
|
|
1234
|
+
declare const LAYOUT_LABEL: Record<ViewLayout, string>;
|
|
1235
|
+
/**
|
|
1236
|
+
* What each layout needs before it can draw anything, in one sentence a screen
|
|
1237
|
+
* prints. A layout that is missing its Field says so instead of rendering an
|
|
1238
|
+
* empty board that looks like "no records".
|
|
1239
|
+
*/
|
|
1240
|
+
declare const LAYOUT_NEEDS: Record<ViewLayout, string | null>;
|
|
1241
|
+
/** One sort clause. The Field's key and a direction; nothing else is a sort. */
|
|
1242
|
+
interface ViewSort {
|
|
1243
|
+
field: string;
|
|
1244
|
+
direction: "asc" | "desc";
|
|
1245
|
+
}
|
|
1246
|
+
/** How a saved view is ordered: by hand, by its sort, or it never said (the same as sorted). */
|
|
1247
|
+
type ViewOrder = "manual" | "sorted" | null;
|
|
1248
|
+
/**
|
|
1249
|
+
* THE DECLARATIVE SPEC. An agent writes this whole object; a person tweaks it.
|
|
1250
|
+
* Every builder component in this package takes one of these as a prop.
|
|
1251
|
+
*/
|
|
1252
|
+
interface SavedViewSpec {
|
|
1253
|
+
name: string;
|
|
1254
|
+
/** The Table this view looks at. */
|
|
1255
|
+
subject: Uuid$1;
|
|
1256
|
+
layout: ViewLayout;
|
|
1257
|
+
/** Kanban: the Field whose value becomes a column. */
|
|
1258
|
+
groupField?: string | null;
|
|
1259
|
+
/**
|
|
1260
|
+
* Kanban: a number Field to TOTAL under each column heading. It lives on the VIEW for
|
|
1261
|
+
* the same reason the colours do — two people read one board two ways and neither
|
|
1262
|
+
* reading is a fact about the records.
|
|
1263
|
+
*/
|
|
1264
|
+
measure?: string | null;
|
|
1265
|
+
/**
|
|
1266
|
+
* Kanban: the Field whose values cut the board into SWIMLANES across the columns — a
|
|
1267
|
+
* dispatcher's board by Status, one lane per Technician (S1-PRIME VIEW-KEYS). Never the
|
|
1268
|
+
* column Field itself; the store refuses that.
|
|
1269
|
+
*/
|
|
1270
|
+
swimlaneField?: string | null;
|
|
1271
|
+
/** Kanban: the columns this view keeps shut to a strip, by the column's stored value. */
|
|
1272
|
+
collapsedColumns?: string[];
|
|
1273
|
+
/** Calendar: the Field that places a record in the month. */
|
|
1274
|
+
dateField?: string | null;
|
|
1275
|
+
/** Gallery: the Field shown large on the card. */
|
|
1276
|
+
imageField?: string | null;
|
|
1277
|
+
sorts?: ViewSort[];
|
|
1278
|
+
/**
|
|
1279
|
+
* HOW THE VIEW IS ORDERED (ORDER-FIX): `"manual"` — the positions a person set by hand ARE the
|
|
1280
|
+
* view's sort, and it carries no `sorts`; `"sorted"` or null — by `sorts`. READ ONLY: the store
|
|
1281
|
+
* writes "manual" only when the rows are placed (`custom.view_record_order_set`) and turns it
|
|
1282
|
+
* off itself when a sort is saved, so no patch ever sends it (`viewSettingsPatch` does not).
|
|
1283
|
+
*/
|
|
1284
|
+
order?: ViewOrder;
|
|
1285
|
+
/**
|
|
1286
|
+
* The membership Rule. The STORE decides who is in this view; this is a
|
|
1287
|
+
* reference to its Rule record, never a predicate this package evaluates.
|
|
1288
|
+
*/
|
|
1289
|
+
ruleId?: Uuid$1 | null;
|
|
1290
|
+
/**
|
|
1291
|
+
* THE FLAT FILTER a digest or a notify rule wrote the view with — the one shape
|
|
1292
|
+
* `custom.record_filter_sql` compiles, by Field KEY. A view saved in the bar has
|
|
1293
|
+
* none; a view saved by `DigestScheduler` ("where Status is Open") does, and the
|
|
1294
|
+
* grid and the board show exactly the records it names.
|
|
1295
|
+
*/
|
|
1296
|
+
filters?: RecordFilter;
|
|
1297
|
+
/**
|
|
1298
|
+
* S2-PRIME — THE VIEW'S OWN QUESTION, as the condition builder writes it: the store's Rule
|
|
1299
|
+
* shape `{op, args}`, ALL / ANY / NOT groups nested to any depth, Fields by id. Kept in the
|
|
1300
|
+
* definition as `where` and asked of the store unchanged — the grid's list door, the board's
|
|
1301
|
+
* headings and the dashboard's numbers compile it into the one WHERE clause
|
|
1302
|
+
* (`custom.record_filter_sql`). Never stored under `filters`: that key is the flat map the
|
|
1303
|
+
* digests and the notifier read, and they would refuse it by name.
|
|
1304
|
+
*/
|
|
1305
|
+
where?: RuleExpression | null;
|
|
1306
|
+
isDefault?: boolean;
|
|
1307
|
+
/**
|
|
1308
|
+
* HOW THIS VIEW LOOKS — its colors, its per-column formats and its frozen
|
|
1309
|
+
* column (`presentation.ts`).
|
|
1310
|
+
*
|
|
1311
|
+
* It lives on the VIEW and not on the Fields because two people read one
|
|
1312
|
+
* table two ways and neither reading is a fact about the records; it lives on
|
|
1313
|
+
* a RECORD, not a new column, because that is what makes it something an
|
|
1314
|
+
* agent writes with the same `records` tool as everything else.
|
|
1315
|
+
*/
|
|
1316
|
+
presentation?: GridPresentation;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* A saved view as it comes back out of the store, with its row's own id.
|
|
1320
|
+
*
|
|
1321
|
+
* It carries no version: `custom.view_declare` MERGES one key at a time, so two
|
|
1322
|
+
* tabs pressing two different controls on one view both stand, and one control
|
|
1323
|
+
* pressed in both keeps the latest — how Airtable and Notion keep a view change.
|
|
1324
|
+
*/
|
|
1325
|
+
interface SavedView extends SavedViewSpec {
|
|
1326
|
+
id: Uuid$1;
|
|
1327
|
+
/** Where the view came from when it was moved in (the mover, the S0 repair), else null. */
|
|
1328
|
+
movedFrom: Record<string, unknown> | null;
|
|
1329
|
+
/**
|
|
1330
|
+
* THE WAY THIS TABLE IS MEANT TO BE LOOKED AT, when somebody decided one — a layout id the
|
|
1331
|
+
* host draws (`sheet`), read off the stored kind before `layout` folds it to the four the
|
|
1332
|
+
* package draws. Null when nobody designated one. See `designatedLayoutOf`.
|
|
1333
|
+
*/
|
|
1334
|
+
designatedLayout?: string | null;
|
|
1335
|
+
}
|
|
1336
|
+
/**
|
|
1337
|
+
* WHICH LAYOUT A VIEW WAS DESIGNATED, OR NULL (lane DATA-V2-FACE, owner 2026-09-24).
|
|
1338
|
+
*
|
|
1339
|
+
* "For something like my data tables, which are predetermined with a default view of 'Sheet'
|
|
1340
|
+
* I want to see … it just shows them the way it should in the default view. That's how you take
|
|
1341
|
+
* custom systems and fake like they're hard-coded builtin systems."
|
|
1342
|
+
*
|
|
1343
|
+
* A designation is a DELIBERATE write, never a click: a view whose stored kind is a layout the
|
|
1344
|
+
* HOST draws (`sheet` — a layout the store's view-keys registry declares, and one the layout
|
|
1345
|
+
* buttons never write onto a view). That is the ONE way a table is designated (lane
|
|
1346
|
+
* VIEW-KEYS-SHEET): the mover and the repair write `layout: "sheet"` on a copied older table's
|
|
1347
|
+
* default view; `moved_from` says only where a view came from and designates nothing. A package
|
|
1348
|
+
* kind (`grid`, `kanban`, …) is not a designation: picking Kanban writes `layout: "kanban"` onto
|
|
1349
|
+
* the view, and a click must never take the layout chooser away.
|
|
1350
|
+
*/
|
|
1351
|
+
declare function designatedLayoutOf(definition: Record<string, unknown> | null | undefined): string | null;
|
|
1352
|
+
/**
|
|
1353
|
+
* HOW THE TABLE OPENS, decided once from its default view and the layouts the host draws.
|
|
1354
|
+
*
|
|
1355
|
+
* · `designated` — the default view names a host layout this host registered: the page opens
|
|
1356
|
+
* IN it and offers no other layout by default (the others sit in the page's one menu);
|
|
1357
|
+
* · `chooser` — nothing designated (or the host does not draw what was designated): the
|
|
1358
|
+
* page opens on the view's own layout and shows the layout chooser.
|
|
1359
|
+
*
|
|
1360
|
+
* Only the DEFAULT view designates: a person who opens another saved view is choosing, and the
|
|
1361
|
+
* chooser is theirs.
|
|
1362
|
+
*/
|
|
1363
|
+
type TableOpening = {
|
|
1364
|
+
kind: "designated";
|
|
1365
|
+
hostLayout: string;
|
|
1366
|
+
} | {
|
|
1367
|
+
kind: "chooser";
|
|
1368
|
+
};
|
|
1369
|
+
declare function tableOpening(view: Pick<SavedView, "isDefault" | "designatedLayout"> | null | undefined, hostLayoutIds: readonly string[]): TableOpening;
|
|
1370
|
+
/**
|
|
1371
|
+
* THE TABLE'S DEFAULT VIEW WHEN MORE THAN ONE SAYS IT IS (lane DATA-V2-FACE-2).
|
|
1372
|
+
*
|
|
1373
|
+
* Two views can both claim the default: the mover's designated one (the older table's own, the
|
|
1374
|
+
* Sheet) and a page seed that a later move of the view bar's older store brings in beside it —
|
|
1375
|
+
* both named "All records", so the store's name order cannot tell them apart. A designation is a
|
|
1376
|
+
* deliberate write and a seed is not, so the designated default wins; then the first default.
|
|
1377
|
+
*/
|
|
1378
|
+
declare function defaultViewOf<V extends Pick<SavedView, "isDefault" | "designatedLayout">>(views: readonly V[]): V | undefined;
|
|
1379
|
+
/**
|
|
1380
|
+
* WHICH FIELD EACH LAYOUT CAN BE DRAWN FROM, decided from the FIELD'S OWN
|
|
1381
|
+
* DECLARATION and never from the values it happens to hold.
|
|
1382
|
+
*
|
|
1383
|
+
* A kanban makes columns from a choice: the Field whose value is one of a
|
|
1384
|
+
* closed set (FLD-5 / FLD-6 — a pick-list is a Table, and a select stores the
|
|
1385
|
+
* id of one of its records). Grouping by a free-text Field produces one column
|
|
1386
|
+
* per record, which is not a board. A calendar places a record in time, so it
|
|
1387
|
+
* needs a Field that holds a date.
|
|
1388
|
+
*
|
|
1389
|
+
* These two answers are here, beside the layouts, because the picker on the
|
|
1390
|
+
* screen and any agent writing a view spec must agree about what is offerable.
|
|
1391
|
+
*/
|
|
1392
|
+
declare const LAYOUT_FIELD_KIND: Record<ViewLayout, "choice" | "date" | null>;
|
|
1393
|
+
/**
|
|
1394
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
1395
|
+
* WHICH VIEW A LINK NAMES — the address bar as a first-class control.
|
|
1396
|
+
*
|
|
1397
|
+
* 🚨 THE DEFECT THIS CLOSES (lane FRONT-DOOR, 2026-09-21; VERIFIER-8 HIGH-2).
|
|
1398
|
+
* `/data-v2/<table>?view=kanban` returned 200 and rendered THE GRID. The
|
|
1399
|
+
* switcher was there, the four buttons worked, and the parameter was read by
|
|
1400
|
+
* nobody — so a person who bookmarked a board, or sent one to a colleague, got
|
|
1401
|
+
* a grid, and nothing on the screen said the view had been dropped. A link that
|
|
1402
|
+
* does not land is the inbox-link defect (`activeRecordId`) and the dashboard
|
|
1403
|
+
* defect (`activeDashboardId`) for the third time, so this is the same shape of
|
|
1404
|
+
* fix: the URL names it, the page opens on it, and the URL FOLLOWS the person
|
|
1405
|
+
* when they pick another.
|
|
1406
|
+
*
|
|
1407
|
+
* The dashboards are a fifth value and not a special case: to the person, "the
|
|
1408
|
+
* dashboard" is one of the ways to look at this table, and a link to it has to
|
|
1409
|
+
* work like a link to the board.
|
|
1410
|
+
*/
|
|
1411
|
+
/**
|
|
1412
|
+
* 🚨 `archived` IS THE SIXTH VALUE, AND IT IS NOT A SPECIAL CASE EITHER (lane
|
|
1413
|
+
* FIX-10A-ARCHIVE, 2026-09-22; VERIFIER-10 F4).
|
|
1414
|
+
*
|
|
1415
|
+
* Archiving a record used to be a ONE-WAY DOOR: the grid's row action soft-
|
|
1416
|
+
* deletes correctly — `deleted_at` set, version bumped, nothing removed — and
|
|
1417
|
+
* then no screen anywhere in the platform could bring it back. The store's
|
|
1418
|
+
* `custom.record_restore` was there the whole time and did exactly the right
|
|
1419
|
+
* thing; nothing reached it, because every read door answers live rows only.
|
|
1420
|
+
*
|
|
1421
|
+
* So the archive is a WAY OF LOOKING AT THIS TABLE, like the board and the
|
|
1422
|
+
* dashboards, reached by the same row of buttons and named by the same
|
|
1423
|
+
* `?view=` parameter — never a Trash area of the app somebody has to know
|
|
1424
|
+
* exists, and never a per-table screen. Every Table inherits it the moment it
|
|
1425
|
+
* is in this list.
|
|
1426
|
+
*/
|
|
1427
|
+
declare const PAGE_VIEWS: readonly ["grid", "kanban", "calendar", "gallery", "dashboards", "archived"];
|
|
1428
|
+
type PageView = (typeof PAGE_VIEWS)[number];
|
|
1429
|
+
declare const PAGE_VIEW_LABEL: Record<PageView, string>;
|
|
1430
|
+
/**
|
|
1431
|
+
* What a `?view=` value means, or `null` when it means nothing here.
|
|
1432
|
+
*
|
|
1433
|
+
* `null` is NOT "show the grid": the caller is expected to say that the link
|
|
1434
|
+
* named something this table has no view for, because silently substituting a
|
|
1435
|
+
* different view is exactly the defect above wearing a parser.
|
|
1436
|
+
*/
|
|
1437
|
+
declare function pageViewFromParam(raw: string | null | undefined): PageView | null;
|
|
1438
|
+
/** The sentence a link that named a view nobody has says. Never silent. */
|
|
1439
|
+
declare function unknownViewLine(raw: string): string;
|
|
1440
|
+
/** The one sentence a layout says when the table holds no Field it could use. */
|
|
1441
|
+
declare const LAYOUT_NO_FIELD: Record<ViewLayout, string>;
|
|
1442
|
+
/**
|
|
1443
|
+
* THE SPEC AS THE ONE DEFINITION `platform.saved_view` HOLDS — the keys
|
|
1444
|
+
* `custom.view_declare` documents, by Field KEY. `subject` is not in it: the door
|
|
1445
|
+
* takes the Table as its own argument and writes `table_id` itself.
|
|
1446
|
+
*/
|
|
1447
|
+
declare function viewDocument(spec: SavedViewSpec): Record<string, unknown>;
|
|
1448
|
+
/**
|
|
1449
|
+
* One row of `custom.views` back into the spec a screen and an agent both read — THROUGH THE ONE
|
|
1450
|
+
* ACCESSOR (`viewSettings`, viewKeys.ts), so every layout sees every declared key the same way.
|
|
1451
|
+
*/
|
|
1452
|
+
declare function viewFromRow(row: SavedViewRow): SavedView;
|
|
1453
|
+
/**
|
|
1454
|
+
* SAVE ONE NEW VIEW of a Table — the bar's "New view" and an agent's seed spec.
|
|
1455
|
+
* One `view_declare` with no `view_id`; the answer is the new view's id.
|
|
1456
|
+
*/
|
|
1457
|
+
declare function declareView(client: Pick<RecordsClient, "viewDeclare">, spec: SavedViewSpec): Promise<RecordsResult<Uuid$1>>;
|
|
1458
|
+
/**
|
|
1459
|
+
* WRITE A CHANGE ONTO A SAVED VIEW, AND KEEP IT.
|
|
1460
|
+
*
|
|
1461
|
+
* `custom.view_declare` with the view's id MERGES: only the keys in `patch` are
|
|
1462
|
+
* written, a key cleared to null is removed, and everything the patch did not
|
|
1463
|
+
* name — the grid's own choices, a hand-set order, where the view was moved from,
|
|
1464
|
+
* a colour set in another tab — stays exactly as it was (S0, 2026-09-23: the door
|
|
1465
|
+
* used to rebuild the whole definition from what one press sent).
|
|
1466
|
+
*
|
|
1467
|
+
* There is no version to be stale against (VERIFIER-15 M4 is closed by the shape,
|
|
1468
|
+
* not by a retry): a saved view is a person's own arrangement of a table, and
|
|
1469
|
+
* their latest press on a control is the one that stands. A refusal — the view
|
|
1470
|
+
* was removed, or belongs to a table this person cannot open — is handed back for
|
|
1471
|
+
* the page to say through the one notice.
|
|
1472
|
+
*/
|
|
1473
|
+
declare function saveViewPatch(client: Pick<RecordsClient, "viewDeclare">, tableId: Uuid$1, viewId: Uuid$1, patch: Partial<SavedViewSpec>): Promise<RecordsResult<Uuid$1>>;
|
|
1474
|
+
/**
|
|
1475
|
+
* A PARTIAL change to a saved view, as the definition keys the door merges. Only
|
|
1476
|
+
* the keys the caller actually changed are sent; a Field cleared (a board with no
|
|
1477
|
+
* "Group by") is sent as `null`, which the door removes.
|
|
1478
|
+
*/
|
|
1479
|
+
declare function viewPatchDocument(patch: Partial<SavedViewSpec>): Record<string, unknown>;
|
|
1480
|
+
|
|
1481
|
+
/** A column sort as the grid holds it: the Field key and a direction. */
|
|
1482
|
+
interface ColumnSort {
|
|
1483
|
+
field: string;
|
|
1484
|
+
direction: "asc" | "desc";
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1230
1487
|
/**
|
|
1231
1488
|
* WHAT A TABLE WITH NO COLUMNS SAYS. Named here because the gate asserts on it:
|
|
1232
1489
|
* the state it describes is what a first-time person met for two days.
|
|
1233
1490
|
*/
|
|
1234
1491
|
declare const NO_COLUMNS_YET = "This table has no columns yet";
|
|
1235
1492
|
declare const NO_COLUMNS_WHY: string;
|
|
1493
|
+
/**
|
|
1494
|
+
* THE OPEN VIEW'S ORDER (lane GRID-MANUAL). A saved view is ordered by its sort OR by hand, never
|
|
1495
|
+
* both (the store's rule, ORDER-FIX). The grid is told which view it is drawing only for this: the
|
|
1496
|
+
* hand order lives on the view's row and is read and written through the view's own doors
|
|
1497
|
+
* (`custom.read_records_in_view_order`, `custom.view_record_order_set`). Left out, the grid is
|
|
1498
|
+
* ordered by the table's own sort exactly as before, and offers no Reorder.
|
|
1499
|
+
*/
|
|
1500
|
+
interface GridViewOrder {
|
|
1501
|
+
viewId: Uuid;
|
|
1502
|
+
/** The view's own order word (`definition.order`). */
|
|
1503
|
+
order: ViewOrder;
|
|
1504
|
+
/** The view's own sort (`definition.sorts`) — where a sorted view OPENS, over the table's. */
|
|
1505
|
+
sorts?: readonly ViewSort[] | undefined;
|
|
1506
|
+
/**
|
|
1507
|
+
* The rows were placed by hand (Reorder → Save): the store made the view manual and removed its
|
|
1508
|
+
* sort. The host updates the view it holds. Unbound, Reorder is ABSENT — never a dead button.
|
|
1509
|
+
*/
|
|
1510
|
+
onPlaced?: (() => void) | undefined;
|
|
1511
|
+
/**
|
|
1512
|
+
* "Use this sort instead": the host writes the sort onto the view (`custom.view_declare` with
|
|
1513
|
+
* `sorts`), which turns the hand order off in the store. Unbound, the control is ABSENT.
|
|
1514
|
+
*/
|
|
1515
|
+
onUseSort?: ((sort: ColumnSort) => void) | undefined;
|
|
1516
|
+
}
|
|
1236
1517
|
interface GridProps {
|
|
1237
1518
|
tableId: Uuid;
|
|
1238
1519
|
/** Rows per page. The table's own pagination handles the rest. */
|
|
@@ -1301,9 +1582,11 @@ interface GridProps {
|
|
|
1301
1582
|
* state — they are simply not remembered.
|
|
1302
1583
|
*/
|
|
1303
1584
|
onPresentationChange?: ((next: GridPresentation) => void) | undefined;
|
|
1585
|
+
/** The open view's order — its hand-set order or its sort (`GridViewOrder`). */
|
|
1586
|
+
viewOrder?: GridViewOrder | undefined;
|
|
1304
1587
|
className?: string | undefined;
|
|
1305
1588
|
}
|
|
1306
|
-
declare function Grid({ tableId, pageSize, filter, onOpenRecord, onAddField, onNewRecordForm, toolbarActions, editable, presentation, onPresentationChange, className, onAskWhoChanged, }: GridProps): react.JSX.Element;
|
|
1589
|
+
declare function Grid({ tableId, pageSize, filter, onOpenRecord, onAddField, onNewRecordForm, toolbarActions, editable, presentation, onPresentationChange, viewOrder, className, onAskWhoChanged, }: GridProps): react.JSX.Element;
|
|
1307
1590
|
/**
|
|
1308
1591
|
* One Field becomes one column. The header is the Field's own NAME — never its
|
|
1309
1592
|
* key (`names.ts`) — and the cell is the value, rendered by its parity type and
|
|
@@ -2042,247 +2325,6 @@ interface TrackedVersion {
|
|
|
2042
2325
|
note: (version: number) => void;
|
|
2043
2326
|
}
|
|
2044
2327
|
|
|
2045
|
-
/** The four ways one saved view can be looked at (SCR-6). */
|
|
2046
|
-
declare const VIEW_LAYOUTS: readonly ["grid", "kanban", "calendar", "gallery"];
|
|
2047
|
-
type ViewLayout = (typeof VIEW_LAYOUTS)[number];
|
|
2048
|
-
declare const LAYOUT_LABEL: Record<ViewLayout, string>;
|
|
2049
|
-
/**
|
|
2050
|
-
* What each layout needs before it can draw anything, in one sentence a screen
|
|
2051
|
-
* prints. A layout that is missing its Field says so instead of rendering an
|
|
2052
|
-
* empty board that looks like "no records".
|
|
2053
|
-
*/
|
|
2054
|
-
declare const LAYOUT_NEEDS: Record<ViewLayout, string | null>;
|
|
2055
|
-
/** One sort clause. The Field's key and a direction; nothing else is a sort. */
|
|
2056
|
-
interface ViewSort {
|
|
2057
|
-
field: string;
|
|
2058
|
-
direction: "asc" | "desc";
|
|
2059
|
-
}
|
|
2060
|
-
/**
|
|
2061
|
-
* THE DECLARATIVE SPEC. An agent writes this whole object; a person tweaks it.
|
|
2062
|
-
* Every builder component in this package takes one of these as a prop.
|
|
2063
|
-
*/
|
|
2064
|
-
interface SavedViewSpec {
|
|
2065
|
-
name: string;
|
|
2066
|
-
/** The Table this view looks at. */
|
|
2067
|
-
subject: Uuid$1;
|
|
2068
|
-
layout: ViewLayout;
|
|
2069
|
-
/** Kanban: the Field whose value becomes a column. */
|
|
2070
|
-
groupField?: string | null;
|
|
2071
|
-
/**
|
|
2072
|
-
* Kanban: a number Field to TOTAL under each column heading. It lives on the VIEW for
|
|
2073
|
-
* the same reason the colours do — two people read one board two ways and neither
|
|
2074
|
-
* reading is a fact about the records.
|
|
2075
|
-
*/
|
|
2076
|
-
measure?: string | null;
|
|
2077
|
-
/**
|
|
2078
|
-
* Kanban: the Field whose values cut the board into SWIMLANES across the columns — a
|
|
2079
|
-
* dispatcher's board by Status, one lane per Technician (S1-PRIME VIEW-KEYS). Never the
|
|
2080
|
-
* column Field itself; the store refuses that.
|
|
2081
|
-
*/
|
|
2082
|
-
swimlaneField?: string | null;
|
|
2083
|
-
/** Kanban: the columns this view keeps shut to a strip, by the column's stored value. */
|
|
2084
|
-
collapsedColumns?: string[];
|
|
2085
|
-
/** Calendar: the Field that places a record in the month. */
|
|
2086
|
-
dateField?: string | null;
|
|
2087
|
-
/** Gallery: the Field shown large on the card. */
|
|
2088
|
-
imageField?: string | null;
|
|
2089
|
-
sorts?: ViewSort[];
|
|
2090
|
-
/**
|
|
2091
|
-
* The membership Rule. The STORE decides who is in this view; this is a
|
|
2092
|
-
* reference to its Rule record, never a predicate this package evaluates.
|
|
2093
|
-
*/
|
|
2094
|
-
ruleId?: Uuid$1 | null;
|
|
2095
|
-
/**
|
|
2096
|
-
* THE FLAT FILTER a digest or a notify rule wrote the view with — the one shape
|
|
2097
|
-
* `custom.record_filter_sql` compiles, by Field KEY. A view saved in the bar has
|
|
2098
|
-
* none; a view saved by `DigestScheduler` ("where Status is Open") does, and the
|
|
2099
|
-
* grid and the board show exactly the records it names.
|
|
2100
|
-
*/
|
|
2101
|
-
filters?: RecordFilter;
|
|
2102
|
-
/**
|
|
2103
|
-
* S2-PRIME — THE VIEW'S OWN QUESTION, as the condition builder writes it: the store's Rule
|
|
2104
|
-
* shape `{op, args}`, ALL / ANY / NOT groups nested to any depth, Fields by id. Kept in the
|
|
2105
|
-
* definition as `where` and asked of the store unchanged — the grid's list door, the board's
|
|
2106
|
-
* headings and the dashboard's numbers compile it into the one WHERE clause
|
|
2107
|
-
* (`custom.record_filter_sql`). Never stored under `filters`: that key is the flat map the
|
|
2108
|
-
* digests and the notifier read, and they would refuse it by name.
|
|
2109
|
-
*/
|
|
2110
|
-
where?: RuleExpression | null;
|
|
2111
|
-
isDefault?: boolean;
|
|
2112
|
-
/**
|
|
2113
|
-
* HOW THIS VIEW LOOKS — its colors, its per-column formats and its frozen
|
|
2114
|
-
* column (`presentation.ts`).
|
|
2115
|
-
*
|
|
2116
|
-
* It lives on the VIEW and not on the Fields because two people read one
|
|
2117
|
-
* table two ways and neither reading is a fact about the records; it lives on
|
|
2118
|
-
* a RECORD, not a new column, because that is what makes it something an
|
|
2119
|
-
* agent writes with the same `records` tool as everything else.
|
|
2120
|
-
*/
|
|
2121
|
-
presentation?: GridPresentation;
|
|
2122
|
-
}
|
|
2123
|
-
/**
|
|
2124
|
-
* A saved view as it comes back out of the store, with its row's own id.
|
|
2125
|
-
*
|
|
2126
|
-
* It carries no version: `custom.view_declare` MERGES one key at a time, so two
|
|
2127
|
-
* tabs pressing two different controls on one view both stand, and one control
|
|
2128
|
-
* pressed in both keeps the latest — how Airtable and Notion keep a view change.
|
|
2129
|
-
*/
|
|
2130
|
-
interface SavedView extends SavedViewSpec {
|
|
2131
|
-
id: Uuid$1;
|
|
2132
|
-
/** Where the view came from when it was moved in (the mover, the S0 repair), else null. */
|
|
2133
|
-
movedFrom: Record<string, unknown> | null;
|
|
2134
|
-
/**
|
|
2135
|
-
* THE WAY THIS TABLE IS MEANT TO BE LOOKED AT, when somebody decided one — a layout id the
|
|
2136
|
-
* host draws (`sheet`), read off the stored kind before `layout` folds it to the four the
|
|
2137
|
-
* package draws. Null when nobody designated one. See `designatedLayoutOf`.
|
|
2138
|
-
*/
|
|
2139
|
-
designatedLayout?: string | null;
|
|
2140
|
-
}
|
|
2141
|
-
/**
|
|
2142
|
-
* WHICH LAYOUT A VIEW WAS DESIGNATED, OR NULL (lane DATA-V2-FACE, owner 2026-09-24).
|
|
2143
|
-
*
|
|
2144
|
-
* "For something like my data tables, which are predetermined with a default view of 'Sheet'
|
|
2145
|
-
* I want to see … it just shows them the way it should in the default view. That's how you take
|
|
2146
|
-
* custom systems and fake like they're hard-coded builtin systems."
|
|
2147
|
-
*
|
|
2148
|
-
* A designation is a DELIBERATE write, never a click: a view whose stored kind is a layout the
|
|
2149
|
-
* HOST draws (`sheet` — a layout the store's view-keys registry declares, and one the layout
|
|
2150
|
-
* buttons never write onto a view). That is the ONE way a table is designated (lane
|
|
2151
|
-
* VIEW-KEYS-SHEET): the mover and the repair write `layout: "sheet"` on a copied older table's
|
|
2152
|
-
* default view; `moved_from` says only where a view came from and designates nothing. A package
|
|
2153
|
-
* kind (`grid`, `kanban`, …) is not a designation: picking Kanban writes `layout: "kanban"` onto
|
|
2154
|
-
* the view, and a click must never take the layout chooser away.
|
|
2155
|
-
*/
|
|
2156
|
-
declare function designatedLayoutOf(definition: Record<string, unknown> | null | undefined): string | null;
|
|
2157
|
-
/**
|
|
2158
|
-
* HOW THE TABLE OPENS, decided once from its default view and the layouts the host draws.
|
|
2159
|
-
*
|
|
2160
|
-
* · `designated` — the default view names a host layout this host registered: the page opens
|
|
2161
|
-
* IN it and offers no other layout by default (the others sit in the page's one menu);
|
|
2162
|
-
* · `chooser` — nothing designated (or the host does not draw what was designated): the
|
|
2163
|
-
* page opens on the view's own layout and shows the layout chooser.
|
|
2164
|
-
*
|
|
2165
|
-
* Only the DEFAULT view designates: a person who opens another saved view is choosing, and the
|
|
2166
|
-
* chooser is theirs.
|
|
2167
|
-
*/
|
|
2168
|
-
type TableOpening = {
|
|
2169
|
-
kind: "designated";
|
|
2170
|
-
hostLayout: string;
|
|
2171
|
-
} | {
|
|
2172
|
-
kind: "chooser";
|
|
2173
|
-
};
|
|
2174
|
-
declare function tableOpening(view: Pick<SavedView, "isDefault" | "designatedLayout"> | null | undefined, hostLayoutIds: readonly string[]): TableOpening;
|
|
2175
|
-
/**
|
|
2176
|
-
* THE TABLE'S DEFAULT VIEW WHEN MORE THAN ONE SAYS IT IS (lane DATA-V2-FACE-2).
|
|
2177
|
-
*
|
|
2178
|
-
* Two views can both claim the default: the mover's designated one (the older table's own, the
|
|
2179
|
-
* Sheet) and a page seed that a later move of the view bar's older store brings in beside it —
|
|
2180
|
-
* both named "All records", so the store's name order cannot tell them apart. A designation is a
|
|
2181
|
-
* deliberate write and a seed is not, so the designated default wins; then the first default.
|
|
2182
|
-
*/
|
|
2183
|
-
declare function defaultViewOf<V extends Pick<SavedView, "isDefault" | "designatedLayout">>(views: readonly V[]): V | undefined;
|
|
2184
|
-
/**
|
|
2185
|
-
* WHICH FIELD EACH LAYOUT CAN BE DRAWN FROM, decided from the FIELD'S OWN
|
|
2186
|
-
* DECLARATION and never from the values it happens to hold.
|
|
2187
|
-
*
|
|
2188
|
-
* A kanban makes columns from a choice: the Field whose value is one of a
|
|
2189
|
-
* closed set (FLD-5 / FLD-6 — a pick-list is a Table, and a select stores the
|
|
2190
|
-
* id of one of its records). Grouping by a free-text Field produces one column
|
|
2191
|
-
* per record, which is not a board. A calendar places a record in time, so it
|
|
2192
|
-
* needs a Field that holds a date.
|
|
2193
|
-
*
|
|
2194
|
-
* These two answers are here, beside the layouts, because the picker on the
|
|
2195
|
-
* screen and any agent writing a view spec must agree about what is offerable.
|
|
2196
|
-
*/
|
|
2197
|
-
declare const LAYOUT_FIELD_KIND: Record<ViewLayout, "choice" | "date" | null>;
|
|
2198
|
-
/**
|
|
2199
|
-
* ─────────────────────────────────────────────────────────────────────────────
|
|
2200
|
-
* WHICH VIEW A LINK NAMES — the address bar as a first-class control.
|
|
2201
|
-
*
|
|
2202
|
-
* 🚨 THE DEFECT THIS CLOSES (lane FRONT-DOOR, 2026-09-21; VERIFIER-8 HIGH-2).
|
|
2203
|
-
* `/data-v2/<table>?view=kanban` returned 200 and rendered THE GRID. The
|
|
2204
|
-
* switcher was there, the four buttons worked, and the parameter was read by
|
|
2205
|
-
* nobody — so a person who bookmarked a board, or sent one to a colleague, got
|
|
2206
|
-
* a grid, and nothing on the screen said the view had been dropped. A link that
|
|
2207
|
-
* does not land is the inbox-link defect (`activeRecordId`) and the dashboard
|
|
2208
|
-
* defect (`activeDashboardId`) for the third time, so this is the same shape of
|
|
2209
|
-
* fix: the URL names it, the page opens on it, and the URL FOLLOWS the person
|
|
2210
|
-
* when they pick another.
|
|
2211
|
-
*
|
|
2212
|
-
* The dashboards are a fifth value and not a special case: to the person, "the
|
|
2213
|
-
* dashboard" is one of the ways to look at this table, and a link to it has to
|
|
2214
|
-
* work like a link to the board.
|
|
2215
|
-
*/
|
|
2216
|
-
/**
|
|
2217
|
-
* 🚨 `archived` IS THE SIXTH VALUE, AND IT IS NOT A SPECIAL CASE EITHER (lane
|
|
2218
|
-
* FIX-10A-ARCHIVE, 2026-09-22; VERIFIER-10 F4).
|
|
2219
|
-
*
|
|
2220
|
-
* Archiving a record used to be a ONE-WAY DOOR: the grid's row action soft-
|
|
2221
|
-
* deletes correctly — `deleted_at` set, version bumped, nothing removed — and
|
|
2222
|
-
* then no screen anywhere in the platform could bring it back. The store's
|
|
2223
|
-
* `custom.record_restore` was there the whole time and did exactly the right
|
|
2224
|
-
* thing; nothing reached it, because every read door answers live rows only.
|
|
2225
|
-
*
|
|
2226
|
-
* So the archive is a WAY OF LOOKING AT THIS TABLE, like the board and the
|
|
2227
|
-
* dashboards, reached by the same row of buttons and named by the same
|
|
2228
|
-
* `?view=` parameter — never a Trash area of the app somebody has to know
|
|
2229
|
-
* exists, and never a per-table screen. Every Table inherits it the moment it
|
|
2230
|
-
* is in this list.
|
|
2231
|
-
*/
|
|
2232
|
-
declare const PAGE_VIEWS: readonly ["grid", "kanban", "calendar", "gallery", "dashboards", "archived"];
|
|
2233
|
-
type PageView = (typeof PAGE_VIEWS)[number];
|
|
2234
|
-
declare const PAGE_VIEW_LABEL: Record<PageView, string>;
|
|
2235
|
-
/**
|
|
2236
|
-
* What a `?view=` value means, or `null` when it means nothing here.
|
|
2237
|
-
*
|
|
2238
|
-
* `null` is NOT "show the grid": the caller is expected to say that the link
|
|
2239
|
-
* named something this table has no view for, because silently substituting a
|
|
2240
|
-
* different view is exactly the defect above wearing a parser.
|
|
2241
|
-
*/
|
|
2242
|
-
declare function pageViewFromParam(raw: string | null | undefined): PageView | null;
|
|
2243
|
-
/** The sentence a link that named a view nobody has says. Never silent. */
|
|
2244
|
-
declare function unknownViewLine(raw: string): string;
|
|
2245
|
-
/** The one sentence a layout says when the table holds no Field it could use. */
|
|
2246
|
-
declare const LAYOUT_NO_FIELD: Record<ViewLayout, string>;
|
|
2247
|
-
/**
|
|
2248
|
-
* THE SPEC AS THE ONE DEFINITION `platform.saved_view` HOLDS — the keys
|
|
2249
|
-
* `custom.view_declare` documents, by Field KEY. `subject` is not in it: the door
|
|
2250
|
-
* takes the Table as its own argument and writes `table_id` itself.
|
|
2251
|
-
*/
|
|
2252
|
-
declare function viewDocument(spec: SavedViewSpec): Record<string, unknown>;
|
|
2253
|
-
/**
|
|
2254
|
-
* One row of `custom.views` back into the spec a screen and an agent both read — THROUGH THE ONE
|
|
2255
|
-
* ACCESSOR (`viewSettings`, viewKeys.ts), so every layout sees every declared key the same way.
|
|
2256
|
-
*/
|
|
2257
|
-
declare function viewFromRow(row: SavedViewRow): SavedView;
|
|
2258
|
-
/**
|
|
2259
|
-
* SAVE ONE NEW VIEW of a Table — the bar's "New view" and an agent's seed spec.
|
|
2260
|
-
* One `view_declare` with no `view_id`; the answer is the new view's id.
|
|
2261
|
-
*/
|
|
2262
|
-
declare function declareView(client: Pick<RecordsClient, "viewDeclare">, spec: SavedViewSpec): Promise<RecordsResult<Uuid$1>>;
|
|
2263
|
-
/**
|
|
2264
|
-
* WRITE A CHANGE ONTO A SAVED VIEW, AND KEEP IT.
|
|
2265
|
-
*
|
|
2266
|
-
* `custom.view_declare` with the view's id MERGES: only the keys in `patch` are
|
|
2267
|
-
* written, a key cleared to null is removed, and everything the patch did not
|
|
2268
|
-
* name — the grid's own choices, a hand-set order, where the view was moved from,
|
|
2269
|
-
* a colour set in another tab — stays exactly as it was (S0, 2026-09-23: the door
|
|
2270
|
-
* used to rebuild the whole definition from what one press sent).
|
|
2271
|
-
*
|
|
2272
|
-
* There is no version to be stale against (VERIFIER-15 M4 is closed by the shape,
|
|
2273
|
-
* not by a retry): a saved view is a person's own arrangement of a table, and
|
|
2274
|
-
* their latest press on a control is the one that stands. A refusal — the view
|
|
2275
|
-
* was removed, or belongs to a table this person cannot open — is handed back for
|
|
2276
|
-
* the page to say through the one notice.
|
|
2277
|
-
*/
|
|
2278
|
-
declare function saveViewPatch(client: Pick<RecordsClient, "viewDeclare">, tableId: Uuid$1, viewId: Uuid$1, patch: Partial<SavedViewSpec>): Promise<RecordsResult<Uuid$1>>;
|
|
2279
|
-
/**
|
|
2280
|
-
* A PARTIAL change to a saved view, as the definition keys the door merges. Only
|
|
2281
|
-
* the keys the caller actually changed are sent; a Field cleared (a board with no
|
|
2282
|
-
* "Group by") is sent as `null`, which the door removes.
|
|
2283
|
-
*/
|
|
2284
|
-
declare function viewPatchDocument(patch: Partial<SavedViewSpec>): Record<string, unknown>;
|
|
2285
|
-
|
|
2286
2328
|
/** Every surface a saved view is drawn by. `sheet` is the spreadsheet surface (G-lanes). */
|
|
2287
2329
|
type ViewKeyLayout = "grid" | "kanban" | "calendar" | "gallery" | "sheet";
|
|
2288
2330
|
/** Who may write a key: anyone who may save the view, an input the door rewrites, or the server only. */
|
|
@@ -2405,11 +2447,24 @@ interface ViewSwitcherProps {
|
|
|
2405
2447
|
chooser?: boolean | undefined;
|
|
2406
2448
|
/** Handed to a host layout's `render` — the page's own export. */
|
|
2407
2449
|
openExport?: (() => void) | undefined;
|
|
2450
|
+
/**
|
|
2451
|
+
* THE SAVED VIEW'S OWN ID, when the view is a stored one (lane GRID-MANUAL). A hand-set order
|
|
2452
|
+
* lives on the view's row, so the grid reads it (`custom.read_records_in_view_order`) and writes
|
|
2453
|
+
* it (`custom.view_record_order_set`, Reorder → Save) through it. Left out — a literal spec —
|
|
2454
|
+
* the view has no hand order and the grid offers no Reorder.
|
|
2455
|
+
*/
|
|
2456
|
+
viewId?: Uuid | null | undefined;
|
|
2457
|
+
/**
|
|
2458
|
+
* The rows were placed by hand: the store made this view manual and removed its sort. The host
|
|
2459
|
+
* updates the view it holds (nothing is written — the store already did).
|
|
2460
|
+
*/
|
|
2461
|
+
onOrderPlaced?: (() => void) | undefined;
|
|
2408
2462
|
className?: string | undefined;
|
|
2409
2463
|
}
|
|
2410
2464
|
/** The records this view holds: its Rule's members when it names one, the table otherwise. */
|
|
2411
|
-
declare function useViewRecords(view: SavedViewSpec, pageSize?: number, filter?: StoreFilter): {
|
|
2465
|
+
declare function useViewRecords(view: SavedViewSpec, pageSize?: number, filter?: StoreFilter, viewId?: Uuid | null): {
|
|
2412
2466
|
rows: ReadRow$1[];
|
|
2467
|
+
manual: boolean;
|
|
2413
2468
|
loading: boolean;
|
|
2414
2469
|
error: RecordsError | null;
|
|
2415
2470
|
/**
|
|
@@ -2426,7 +2481,7 @@ declare function useViewRecords(view: SavedViewSpec, pageSize?: number, filter?:
|
|
|
2426
2481
|
*/
|
|
2427
2482
|
membership: string;
|
|
2428
2483
|
};
|
|
2429
|
-
declare function ViewSwitcher({ view, onLayoutChange, onViewChange, onOpenRecord, onMoved, onNewRecordForm, onAskWhoChanged, pageSize, titleField, filter, hostLayout, onHostLayoutChange, chooser, openExport, className, }: ViewSwitcherProps): react.JSX.Element;
|
|
2484
|
+
declare function ViewSwitcher({ view, onLayoutChange, onViewChange, onOpenRecord, onMoved, onNewRecordForm, onAskWhoChanged, pageSize, titleField, filter, hostLayout, onHostLayoutChange, chooser, openExport, viewId, onOrderPlaced, className, }: ViewSwitcherProps): react.JSX.Element;
|
|
2430
2485
|
|
|
2431
2486
|
/** What the screen says above the list, so nobody has to be told twice that nothing was destroyed. */
|
|
2432
2487
|
declare const ARCHIVE_MEANS = "Archiving never destroys anything. A record you remove from the grid waits here until somebody brings it back.";
|