Skip to content

Commit 1a3f686

Browse files
committed
docs(spec): regenerate the page reference after merging main's visibleWhen describe
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AQxxbsMRiqgkrsU3Xd54yE
1 parent 7020a76 commit 1a3f686

1 file changed

Lines changed: 12 additions & 12 deletions

File tree

‎content/docs/references/ui/page.mdx‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,22 @@ const result = ElementApiDataSourceSchema.parse(data);
2424

2525
## ElementApiDataSource
2626

27-
[PLANNED — not yet rendered] API binding of a page element: `{ provider: 'api', read: { url }, path? }` reads one same-origin endpoint with the console's signed-in fetch and binds the selected value, which the element reads as `data` in its expression holes and its `visibleWhen`. The console's generic stat, usage-bar and checklist blocks are the planned readers; until they ship, the binding parses and no block reads it.
27+
API binding of a page element: `{ provider: 'api', read: { url }, path? }` reads one same-origin endpoint with the console's signed-in fetch and binds the selected value, which the element reads as `data` in its expression holes and its `visibleWhen`. The console renders it on every page element: the value is `data` on that element and on every element nested inside it, the element's `visibleWhen` is decided once the read answers, and while the read is in flight, or when the binding is refused or the read fails, the element draws a loading or error panel instead. The console's generic `stat`, `usage-bar` and `checklist` blocks are built to take it.
2828

2929
### Properties
3030

3131
| Property | Type | Required | Description |
3232
| :--- | :--- | :--- | :--- |
33-
| **provider** | `'api'` | ✅ | Binds the element to one same-origin API endpoint instead of an object |
34-
| **read** | `{ url: string; method?: 'GET' }` | ✅ | The read request — the same-origin endpoint the element binds |
35-
| **path** | `string` | optional | Dotted path selecting the sub-tree of the response the element binds, e.g. `data.environments` in a `{ success, data }` envelope; omitted, the element binds the whole response |
33+
| **provider** | `'api'` | ✅ | Binds one same-origin API endpoint — the discriminator of an `api` data source |
34+
| **read** | `{ url: string; method?: 'GET' }` | ✅ | The read request — the same-origin endpoint the binding reads |
35+
| **path** | `string` | optional | Dotted path selecting the sub-tree of the response the binding takes, e.g. `data.environments` in a `{ success, data }` envelope; omitted, the binding takes the whole response |
3636

3737
### Nested Shape: `ElementApiDataSource.read`
3838

3939
| Property | Type | Required | Description |
4040
| :--- | :--- | :--- | :--- |
41-
| **url** | `string` | ✅ | Same-origin API path the element reads — it opens with a single `/`, e.g. `/api/v1/cloud/home`. An absolute URL of any scheme, a protocol-relative `//host`, a backslash read as a slash, a space or control character, and a relative path are refused at parse. No credential is written here: the console reads the endpoint with its own signed-in fetch. |
42-
| **method** | `'GET'` | optional | HTTP method of the read — `GET`, the only method a page element's read is sent with |
41+
| **url** | `string` | ✅ | Same-origin API path the binding reads — it opens with a single `/`, e.g. `/api/v1/cloud/home`. An absolute URL of any scheme, a protocol-relative `//host`, a backslash read as a slash, a space or control character, and a relative path are refused at parse. No credential is written here: the console reads the endpoint with its own signed-in fetch. |
42+
| **method** | `'GET'` | optional | HTTP method of the read — `GET`, the only method the read of an `api` data source is sent with |
4343

4444

4545
---
@@ -311,7 +311,7 @@ View filter rule
311311
| **style** | `Record<string, string>` | optional | Inline styles or utility classes |
312312
| **className** | `string` | optional | CSS class names |
313313
| **responsiveStyles** | `{ large?: Record<string, string \| number>; medium?: Record<string, string \| number>; small?: Record<string, string \| number>; xsmall?: Record<string, string \| number> }` | optional | Per-breakpoint scoped style maps (ADR-0065) |
314-
| **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate (CEL) — component rendered only when TRUE. Contract-bound roots: `record`, `current_user` (ADR-0068 aliases `user` / `ctx.user` — one object, three spellings), and page state as `page.<var>`. The shipping renderer additionally mounts `features` and `os.user` — renderer behaviour, NOT contract-guaranteed (ADR-0068 rules the user object only). It mounts NO `data` root here: a `data.*` read faults and a faulting predicate renders the component, so such a gate never gates; the page's row is `record` — the record a record page opens, or the row an app page's `record` binding reads (none without one; a block's own `dataSource` binds no `record` for its siblings). A count or a plan is a field on that row (a `summary` roll-up: `record.environment_count > 1`; `record.plan != 'free'`), never `features.*`, which are the deployment's public auth flags, the same for every organisation. `data` is declared only for an element whose `dataSource` is the PLANNED API binding (`provider: 'api'`), which reads its bound value as `data` once that binding's renderer ships. To gate a component on a system capability, write `current_user.hasCapability('<name>')` with the name the gated action's `requiredPermissions` declares — it answers from the viewer's `systemPermissions`, the list the action gate reads, never a proxy such as `current_user.can('<object>', 'edit')`; a host that binds no capability list makes it fault, and a faulting predicate renders the component. ADR-0066 D4: `visibleWhen` hides, `requiredPermissions` refuses. ⚠️ A `page:tabs` item `visibleWhen` is a different evaluator: it binds `data` to the record ROW. e.g. "page.selectedProjectId != ''" |
314+
| **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate (CEL) — component rendered only when TRUE. Contract-bound roots: `record`, `current_user` (ADR-0068 aliases `user` / `ctx.user` — one object, three spellings), and page state as `page.<var>`. The shipping renderer additionally mounts `features` and `os.user` — renderer behaviour, NOT contract-guaranteed (ADR-0068 rules the user object only). It mounts NO `data` root on an element that no `api` data source binds: there a `data.*` read faults and a faulting predicate renders the component, so such a gate never gates; the page's row is `record` — the record a record page opens, or the row an app page's `record` binding reads (none without one; a block's own `dataSource` binds no `record` for its siblings). A count or a plan is a field on that row (a `summary` roll-up: `record.environment_count > 1`; `record.plan != 'free'`), never `features.*`, which are the deployment's public auth flags, the same for every organisation. `data` is mounted only on an element whose `dataSource` is an `api` data source (`provider: 'api'`): there, and on every element nested inside it, `data` is the value the binding selects, and the element's `visibleWhen` is decided once the read answers. To gate a component on a system capability, write `current_user.hasCapability('<name>')` with the name the gated action's `requiredPermissions` declares — it answers from the viewer's `systemPermissions`, the list the action gate reads, never a proxy such as `current_user.can('<object>', 'edit')`; a host that binds no capability list makes it fault, and a faulting predicate renders the component. ADR-0066 D4: `visibleWhen` hides, `requiredPermissions` refuses. ⚠️ A `page:tabs` item `visibleWhen` is a different evaluator: it binds `data` to the record ROW. e.g. "page.selectedProjectId != ''" |
315315
| **visibility** | `never` | optional | [REMOVED] `page.components[].visibility` was removed in @objectstack/spec 18 (ADR-0089 D2) — it was the page component's deprecated spelling of the conditional-visibility predicate, which the parse folded into `visibleWhen` until this release. Use `visibleWhen`. Rename the key; the value (a CEL predicate) is unchanged. Where a component writes both, `visibleWhen` is the one that was in effect: delete `visibility`. |
316316
| **dataSource** | `{ object: string; view?: string; filter?: object[]; sort?: object[]; … } \| { provider: 'api'; read: object; path?: string }` | optional | Per-element data binding: an object binding `{ object, view?, filter?, sort?, limit? }` that overrides the page object, or an API binding `{ provider: 'api', read: { url }, path? }` that reads one same-origin endpoint |
317317
| **responsive** | `never` | optional | [REMOVED] `page.components[].responsive` was removed in @objectstack/spec 17 (ADR-0049 D2) — no renderer ever read it, so per-breakpoint layout overrides (columns/order/visibility) parsed, validated, and then did nothing. Delete the key. For breakpoint behaviour that IS applied, use the sibling `responsiveStyles` (ADR-0065) — per-breakpoint CSS maps compiled to id-scoped CSS at render, e.g. `responsiveStyles: { xsmall: { display: 'none' } }` to hide a component on the narrowest screens. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; `--write` applies the ones it can prove, and you apply the rest by hand. |
@@ -338,13 +338,13 @@ View filter rule
338338

339339
### Nested Shape: `PageComponent.dataSource[option 2]`
340340

341-
[PLANNED — not yet rendered] API binding of a page element: `{ provider: 'api', read: { url }, path? }` reads one same-origin endpoint with the console's signed-in fetch and binds the selected value, which the element reads as `data` in its expression holes and its `visibleWhen`. The console's generic stat, usage-bar and checklist blocks are the planned readers; until they ship, the binding parses and no block reads it.
341+
API binding of a page element: `{ provider: 'api', read: { url }, path? }` reads one same-origin endpoint with the console's signed-in fetch and binds the selected value, which the element reads as `data` in its expression holes and its `visibleWhen`. The console renders it on every page element: the value is `data` on that element and on every element nested inside it, the element's `visibleWhen` is decided once the read answers, and while the read is in flight, or when the binding is refused or the read fails, the element draws a loading or error panel instead. The console's generic `stat`, `usage-bar` and `checklist` blocks are built to take it.
342342

343343
| Property | Type | Required | Description |
344344
| :--- | :--- | :--- | :--- |
345-
| **provider** | `'api'` | ✅ | Binds the element to one same-origin API endpoint instead of an object |
346-
| **read** | `{ url: string; method?: 'GET' }` | ✅ | The read request — the same-origin endpoint the element binds |
347-
| **path** | `string` | optional | Dotted path selecting the sub-tree of the response the element binds, e.g. `data.environments` in a `{ success, data }` envelope; omitted, the element binds the whole response |
345+
| **provider** | `'api'` | ✅ | Binds one same-origin API endpoint — the discriminator of an `api` data source |
346+
| **read** | `{ url: string; method?: 'GET' }` | ✅ | The read request — the same-origin endpoint the binding reads |
347+
| **path** | `string` | optional | Dotted path selecting the sub-tree of the response the binding takes, e.g. `data.environments` in a `{ success, data }` envelope; omitted, the binding takes the whole response |
348348

349349
### Nested Shape: `PageComponent.aria`
350350

@@ -483,7 +483,7 @@ Sort field and direction pair
483483
| **style** | `Record<string, string>` | optional | Inline styles or utility classes |
484484
| **className** | `string` | optional | CSS class names |
485485
| **responsiveStyles** | `{ large?: Record<string, string \| number>; medium?: Record<string, string \| number>; small?: Record<string, string \| number>; xsmall?: Record<string, string \| number> }` | optional | Per-breakpoint scoped style maps (ADR-0065) |
486-
| **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate (CEL) — component rendered only when TRUE. Contract-bound roots: `record`, `current_user` (ADR-0068 aliases `user` / `ctx.user` — one object, three spellings), and page state as `page.<var>`. The shipping renderer additionally mounts `features` and `os.user` — renderer behaviour, NOT contract-guaranteed (ADR-0068 rules the user object only). It mounts NO `data` root here: a `data.*` read faults and a faulting predicate renders the component, so such a gate never gates; the page's row is `record` — the record a record page opens, or the row an app page's `record` binding reads (none without one; a block's own `dataSource` binds no `record` for its siblings). A count or a plan is a field on that row (a `summary` roll-up: `record.environment_count > 1`; `record.plan != 'free'`), never `features.*`, which are the deployment's public auth flags, the same for every organisation. `data` is declared only for an element whose `dataSource` is the PLANNED API binding (`provider: 'api'`), which reads its bound value as `data` once that binding's renderer ships. To gate a component on a system capability, write `current_user.hasCapability('<name>')` with the name the gated action's `requiredPermissions` declares — it answers from the viewer's `systemPermissions`, the list the action gate reads, never a proxy such as `current_user.can('<object>', 'edit')`; a host that binds no capability list makes it fault, and a faulting predicate renders the component. ADR-0066 D4: `visibleWhen` hides, `requiredPermissions` refuses. ⚠️ A `page:tabs` item `visibleWhen` is a different evaluator: it binds `data` to the record ROW. e.g. "page.selectedProjectId != ''" |
486+
| **visibleWhen** | `string \| { dialect: Enum<'cel' \| 'cron' \| 'template'>; source: string; ast?: any; meta?: object }` | optional | Visibility predicate (CEL) — component rendered only when TRUE. Contract-bound roots: `record`, `current_user` (ADR-0068 aliases `user` / `ctx.user` — one object, three spellings), and page state as `page.<var>`. The shipping renderer additionally mounts `features` and `os.user` — renderer behaviour, NOT contract-guaranteed (ADR-0068 rules the user object only). It mounts NO `data` root on an element that no `api` data source binds: there a `data.*` read faults and a faulting predicate renders the component, so such a gate never gates; the page's row is `record` — the record a record page opens, or the row an app page's `record` binding reads (none without one; a block's own `dataSource` binds no `record` for its siblings). A count or a plan is a field on that row (a `summary` roll-up: `record.environment_count > 1`; `record.plan != 'free'`), never `features.*`, which are the deployment's public auth flags, the same for every organisation. `data` is mounted only on an element whose `dataSource` is an `api` data source (`provider: 'api'`): there, and on every element nested inside it, `data` is the value the binding selects, and the element's `visibleWhen` is decided once the read answers. To gate a component on a system capability, write `current_user.hasCapability('<name>')` with the name the gated action's `requiredPermissions` declares — it answers from the viewer's `systemPermissions`, the list the action gate reads, never a proxy such as `current_user.can('<object>', 'edit')`; a host that binds no capability list makes it fault, and a faulting predicate renders the component. ADR-0066 D4: `visibleWhen` hides, `requiredPermissions` refuses. ⚠️ A `page:tabs` item `visibleWhen` is a different evaluator: it binds `data` to the record ROW. e.g. "page.selectedProjectId != ''" |
487487
| **visibility** | `never` | optional | [REMOVED] `page.components[].visibility` was removed in @objectstack/spec 18 (ADR-0089 D2) — it was the page component's deprecated spelling of the conditional-visibility predicate, which the parse folded into `visibleWhen` until this release. Use `visibleWhen`. Rename the key; the value (a CEL predicate) is unchanged. Where a component writes both, `visibleWhen` is the one that was in effect: delete `visibility`. |
488488
| **dataSource** | `{ object: string; view?: string; filter?: object[]; sort?: object[]; … } \| { provider: 'api'; read: object; path?: string }` | optional | Per-element data binding: an object binding `{ object, view?, filter?, sort?, limit? }` that overrides the page object, or an API binding `{ provider: 'api', read: { url }, path? }` that reads one same-origin endpoint |
489489
| **responsive** | `never` | optional | [REMOVED] `page.components[].responsive` was removed in @objectstack/spec 17 (ADR-0049 D2) — no renderer ever read it, so per-breakpoint layout overrides (columns/order/visibility) parsed, validated, and then did nothing. Delete the key. For breakpoint behaviour that IS applied, use the sibling `responsiveStyles` (ADR-0065) — per-breakpoint CSS maps compiled to id-scoped CSS at render, e.g. `responsiveStyles: { xsmall: { display: 'none' } }` to hide a component on the narrowest screens. Run `os migrate meta --from 17` to list the mechanical edits for existing sources; `--write` applies the ones it can prove, and you apply the rest by hand. |

0 commit comments

Comments
 (0)