Core Guarantees
What every surface — the table, the views, the inspector, the api — promises about your records, reads, writes, refusals and history.
Wit Grid is one record engine behind many surfaces: the table, the board, the calendar, the Gantt, the gallery, charts, pivots, the inspector and your own code through the api. This page states what holds wherever a record is read or written. If a surface behaves differently from what is written here, that is a bug.
Your records
- You own the records. The grid holds them by id (
getRowId); an id must stay the same for the life of a record. - Client rows come from
rowsand change through transactions. Server and infinite rows come from yourdatasource; the grid holds the ones it has loaded. - Views show the records that match, not what the table happens to display: the filters, the search and the
sort apply to every view; the table's collapsed groups, its page and its pivot do not. A view over a server or
infinite model knows it sees only what is loaded (
completeness: 'loaded') and says so.
Reading a field
- A field reads the same everywhere. Every surface reads it through the grid: a
valueGetter, a formula, a nested path (plan.amount) give the same value in a table cell, on a card, in a chart total, in a formula that uses it, in a filter's value list, in a diff and in a pivot.
Writing a field
Every interactive cell write — an edit, a paste, a fill, a transaction, a card moved, a span
dragged, a field changed in the inspector — is prepared the same way, then committed:
- Setters run once, on a copy. Each written field's
valueSetterruns against a copy of the record as proposed so far. A setter that returns a promise is awaited by async callers (edits, pastes, gestures,transaction(…, { async: true })); a synctransactionrefuses it (needsAsync: true) instead of leaving it unawaited. Nothing runs twice. - Only what changed is written. The commit writes the fields a setter actually changed (by value), plus the plain writes as given. A field the setter left alone is not rewritten.
- The rules judge the whole proposed record. Cell rules run for every field the write changes, including fields a setter changed besides its own; row rules run against the record with every change in place. A blocking rule that throws blocks the write.
- Permissions apply to people. Edits, pastes, fills and gestures are checked against your capabilities; your
own code's
transactionis not, unless it asks (asUser: true). - All or nothing, by default. A write is atomic: if one cell cannot apply, none do. A bulk action can choose
policy: 'bestEffort', where independent cells apply and the refused ones are listed. - Prepared against the record as it commits. Writes queued before it land first; if the record changed while a setter or rule was awaited, the write is prepared again, and refused (“changed while saving”) if it changes again — it never commits over values it did not see.
A committed write is one change set (the changed event, listing exactly the fields that changed) and one
undo step.
Refusals
- A refused write changes nothing (or, with
bestEffort, nothing but the cells that could apply). - It is reported the same way from every surface: the write's result says why (
validationFailed,capabilityDenied,rejected), and thewriteBlockedevent fires with its source —edit,paste,fill, orviewfor a gesture. Trying to edit a cell the user may not is reported too. - The user is told why, in your words. In a workspace, a refused edit and a refused gesture both read “Not changed: …” with your rule's message or your capability's reason. An editor keeps its draft.
- Nothing waits forever. A gesture still awaiting a setter reports itself as pending, and is reported when it settles; a write still waiting when the grid is destroyed settles as refused.
History
- Undo reverses one write: exactly the fields it changed. A later change to other fields of the same record — a collaborator's, the server's — is left as it is.
Limits, stated
- A rule judges the proposed record it is given. What it reads through the api — this record or any other — is the committed state, not the rest of the same write. A rule across records does not see the other records proposed in the same transaction.
- Row additions and replacements (
rows.add,rows.update) are validated after they commit, not before; only cell writes are prepared and checked first. - Changes from your server or another device are authoritative: they are applied as given, without your setters or rules.
- Workflow rules belong to the record, not the view. A board's WIP prompt or a Gantt's impact preview is the view's gesture help; a rule that must hold everywhere is a validation rule, a capability or a value setter — see how the landing page's CRM declares its sales rules once and every view keeps them.
What a view never does
The built-in views are projections over the same record engine. A view never reads a field from the record's data itself, never runs a setter, and never writes a cell except through the workspace's one write — so every guarantee above holds in it. A test in the core enforces this.
Last updated on