You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 1a3f686
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: content/docs/references/ui/page.mdx
+12-12Lines changed: 12 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,22 +24,22 @@ const result = ElementApiDataSourceSchema.parse(data);
24
24
25
25
## ElementApiDataSource
26
26
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.
28
28
29
29
### Properties
30
30
31
31
| Property | Type | Required | Description |
32
32
| :--- | :--- | :--- | :--- |
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 |
36
36
37
37
### Nested Shape: `ElementApiDataSource.read`
38
38
39
39
| Property | Type | Required | Description |
40
40
| :--- | :--- | :--- | :--- |
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 |
43
43
44
44
45
45
---
@@ -311,7 +311,7 @@ View filter rule
311
311
|**style**|`Record<string, string>`| optional | Inline styles or utility classes |
312
312
|**className**|`string`| optional | CSS class names |
| **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 != ''" |
315
315
|**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`. |
316
316
|**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 |
317
317
|**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. |
[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.
342
342
343
343
| Property | Type | Required | Description |
344
344
| :--- | :--- | :--- | :--- |
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 |
348
348
349
349
### Nested Shape: `PageComponent.aria`
350
350
@@ -483,7 +483,7 @@ Sort field and direction pair
483
483
|**style**|`Record<string, string>`| optional | Inline styles or utility classes |
484
484
|**className**|`string`| optional | CSS class names |
| **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 != ''" |
487
487
|**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`. |
488
488
|**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 |
489
489
|**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