Skip to content

Record pages

A page is one record with everything around it, keyed in pages by id and opened wherever a record of its base table is. A good one has one shape:

pages: {
opportunity: page('Opportunity', 'opportunity', [
header({ status: 'stage', facts: ['account_id', 'amount', 'close_date'] }),
summary(['lines', 'units'], { workflow: workflow('stage', ['prospecting', 'proposal', 'closed_won'], { ordered: true }) }),
related('Quote lines', 'opportunity_line', 'opportunity_id', { show: ['product_id', 'qty', 'unit_price'] }),
related('Tasks', 'task', 'opportunity_id', { query: 'status = open', create: 'Add task' }),
fields(['account_id', 'account_id.city'], { title: 'Account', presentation: 'card', region: 'aside' }),
current('Next task', 'task', 'opportunity_id', { query: 'status = open', sort: 'due_on', region: 'aside' }),
fields(['owner_id', 'probability', 'created_on'], { title: 'Deal', presentation: 'properties', region: 'aside' }),
history('History', { region: 'aside' }),
], { listTabs: true }),
},
  • The head: header({ status, facts, eyebrow, primary, destructive }) is drawn in the record’s head wherever it stands: the status column’s tone beside the name, up to six facts under it (units from display rules; { column, label } says a word after a value, “3 beds”, and position: 'before' ahead of it, “Born Apr 24, 2017”), and the verbs: one filled, primary: 'Renew' or else the first that is not destructive, and the destructive ones — named, confirming, or setting a value toned bad — last and quiet.
  • The figures: a summary of 3–4 rollups, with a workflow for a real pipeline.
  • The children: related lists of at most 4 columns, as tabs (listTabs: true).
  • The aside: a card for the parent, current(...) for the one child that matters now (the active lease, the latest visit), a properties rail edited in place, then history() (the record history store must be provisioned). On a phone the aside follows the main flow; only a headline (the key figure and its actions) comes up after the first section.

A resource with no page opens on this anatomy, chosen from the catalog, and the scaffold writes it.

Section Says
{ kind: 'fields' }, fields(show, opts) The record’s own fields, label paths welcome (account_id.city).
header(opts), summary(show, opts) The head’s status and facts; compact properties.
related(title, from, whose, opts) Rows that point at the record: show, query, sort, limit, create, totals, empty.
current(title, from, whose, opts) One of those rows, the first query and sort choose, as a card titled by its name without the page’s own, its show the facts; empty says what none means.
timeline(title, streams) Rows of several tables in date order: stream(from, whose, at, show, { detail }).
metric, breakdown, chart The dashboard helpers, narrowed by whose to rows about this record; about for another record.
history() The record’s own changes.

whose and about follow foreign keys only: relationships.

listTabs: true draws each run of adjacent related lists (none with a width) as one tab strip; the open tab rides the address (/{app}/accounts/13/opportunities) and unopened tabs are never fetched. Sections sharing a tab: 'Name' share one panel. With two pages over one table, the resource’s page says which opens; a section’s when: 'status = converted' shows it only while the record matches.

Every section’s keys: Lists, pages & forms.