|
| 1 | +# Instance views — template-defined rendering |
| 2 | + |
| 3 | +By default the portal renders an instance's `My instances` row as |
| 4 | +Name / Template / Status / Age, and its detail page as a raw-JSON dump of the |
| 5 | +instance's `spec`. A template can override both by declaring a **view**, so each |
| 6 | +template controls how its own instances look — add an `Endpoint` column, turn a |
| 7 | +computed URL into a clickable link, group fields under headings, etc. |
| 8 | + |
| 9 | +The view is authored **on the template** (`spec.view` on the `Template` CRD, or |
| 10 | +the `kedge.faros.sh/view` annotation on a kro RGD). It is opaque to the |
| 11 | +controller and interpreted entirely by the portal's view resolver |
| 12 | +(`portal/src/view.ts`). |
| 13 | + |
| 14 | +## Shape |
| 15 | + |
| 16 | +```yaml |
| 17 | +spec: |
| 18 | + view: |
| 19 | + columns: # extra instance-list columns (after Name/Template) |
| 20 | + - header: URL |
| 21 | + value: "${status.url}" # interpolated string |
| 22 | + type: link |
| 23 | + - header: Auth |
| 24 | + path: spec.oidc.mode # single dot-path |
| 25 | + type: badge |
| 26 | + detail: # detail-page field groups (replace the raw dump) |
| 27 | + - title: Access |
| 28 | + fields: |
| 29 | + - label: URL |
| 30 | + value: "${status.url}" |
| 31 | + type: link |
| 32 | + - label: Hostname |
| 33 | + path: status.host |
| 34 | + type: code |
| 35 | +``` |
| 36 | +
|
| 37 | +A template with no `view` keeps the default rendering. `columns` and `detail` |
| 38 | +are independent — define either or both. |
| 39 | + |
| 40 | +## Field values |
| 41 | + |
| 42 | +Each column/field resolves a single value two ways (use one): |
| 43 | + |
| 44 | +- `path:` — a dot-path, e.g. `status.host` or `spec.database.version`. |
| 45 | +- `value:` — a string with `${…}` tokens, e.g. `"https://${spec.expose.fqdn}/app"`. |
| 46 | + A token that doesn't resolve becomes empty, so partial templates degrade |
| 47 | + gracefully. |
| 48 | + |
| 49 | +Three namespaces are available, matching the CR's own shape: |
| 50 | + |
| 51 | +| Namespace | Source | Example | |
| 52 | +|-----------|--------|---------| |
| 53 | +| `spec.*` | the instance's input values | `spec.database.version` | |
| 54 | +| `status.*` | controller-computed outputs | `status.url`, `status.host` | |
| 55 | +| `meta.*` | `name`, `namespace`, `phase`, `template`, `createdAt` | `meta.phase` | |
| 56 | + |
| 57 | +An **unqualified** first segment resolves against `spec`, so `expose.fqdn` is the |
| 58 | +same as `spec.expose.fqdn`. |
| 59 | + |
| 60 | +> `status.*` only carries values your template's `status` mapping actually |
| 61 | +> projects onto the instance (the `conditions` and `children` arrays are excluded — |
| 62 | +> they have their own sections on the detail page). If a column referencing |
| 63 | +> `status.*`/`spec.*` shows `—`, the field isn't populated yet (still |
| 64 | +> provisioning) or isn't in the status mapping. |
| 65 | + |
| 66 | +## Renderers (`type`) |
| 67 | + |
| 68 | +| `type` | Renders as | |
| 69 | +|--------|------------| |
| 70 | +| `text` (default) | plain text | |
| 71 | +| `link` | clickable anchor opening in a new tab. The href is `href:` if set, else the resolved value; a bare host gets `https://` prepended. | |
| 72 | +| `code` | monospace pill with a copy button (good for secret names, hostnames) | |
| 73 | +| `badge` | neutral pill (good for enums like an auth mode or version) | |
| 74 | + |
| 75 | +## Worked example |
| 76 | + |
| 77 | +See [`install/templates/application.yaml`](../install/templates/application.yaml) |
| 78 | +for a full `spec.view` driving the URL column, an auth badge, and Access / |
| 79 | +Configuration / Readiness detail groups. |
| 80 | + |
| 81 | +## Notes for authors |
| 82 | + |
| 83 | +- Different templates may define different columns; the instance list shows the |
| 84 | + ordered union of all present templates' headers, and a row only fills the |
| 85 | + headers its own template defines. |
| 86 | +- When a template's columns reference `spec.*`/`status.*`, the portal fetches the |
| 87 | + full instance object per row to populate them — keep the column count modest. |
| 88 | +- Keep `spec.view` in lockstep with the embedded CRD: after editing the |
| 89 | + `Template` CRD's Go type, run `make codegen-infrastructure-provider` so the |
| 90 | + generated + embedded CRDs carry the `view` field (otherwise kcp prunes it). |
0 commit comments