Dashboards
Dashboards are configurable layout resources (DASHBOARD) that render an interactive grid of widgets in the Engine UI. Each dashboard stores its layout in the value field as YAML or JSON.
Use dashboards for operational overviews: pipeline status, installation health, runbooks, and links into detailed record views.
Viewing a dashboard
Open a dashboard record and choose View in the action menu, or navigate to:
/dashboard?id=<dashboard-id>&view
You can also use the record name:
/dashboard?name=<dashboard-name>&view
Kiosk / fullscreen mode
Kiosk mode hides the Console chrome — the top bar and the quick-access sidebar — so a dashboard fills the whole screen. It suits wall-boards, always-on displays and focused viewing.
-
Enter kiosk mode with the Fullscreen button in the dashboard header, or by adding the
kioskflag to the URL:/dashboard?name=<dashboard-name>&view&kiosk=1Entering from the button also requests browser fullscreen. A kiosk URL is bookmarkable and can be loaded directly on a display device; opened that way it hides the chrome even where the browser withholds fullscreen without a click.
-
Leave kiosk mode with the exit control in the top-right corner, or by pressing Escape. Leaving browser fullscreen (for example with
F11) also leaves kiosk mode.
A dashboard's live widgets keep refreshing in kiosk mode, so a display left in kiosk mode stays up to date.
Dashboard icon
Each dashboard can carry its own icon, set from the icon control in the dashboard record's page header — the same control used for projects, bundles and workspaces. Two sources are available:
- Curated icon — pick a glyph from the built-in Choose an icon set.
- Upload — supply your own image.
The icon is used in two places:
- Browser tab (favicon). While a dashboard is being viewed
(
/dashboard?name=<dashboard-name>&view), its icon is shown as the browser-tab favicon and the tab title reflects the dashboard name, so a dashboard opened in its own tab is identifiable at a glance. - Record lists. Wherever dashboards are listed — for example a
record_listwidget over theDASHBOARDrecord type — each dashboard's Name cell shows that dashboard's own icon. A dashboard with no icon set falls back to the default dashboard glyph.
Dashboards on a container
A container — a workspace, a project or a bundle — shows a built-in overview on its record screen. In addition, any number of dashboards can be associated with a container and surface there as a row of tabs, so a container carries the operational views that matter for it.
Associated dashboards appear under a Dashboards tab strip on the container screen; each tab renders that dashboard's widgets inline. The built-in overview stays in place — configured dashboards are additive.
Configuring a container's dashboards
The Configured dashboards panel on a container's record screen manages the list. Editing the list requires write access to the container.
- Add — the Add button opens a picker of the dashboards that are not yet associated; choosing one associates it and adds its tab.
- Default — one association is the container's default. Its tab opens first when the container screen loads, and it carries a Default badge in the panel. Set as default on another row moves the default to it. The first dashboard added to a container becomes its default.
- Remove — the remove control on a row drops the association and its tab.
The relation
Each association is a first-class relation record (container_dashboard) linking
one container to one dashboard, so it is discoverable from both directions: the
dashboards configured on a container, and the containers a given dashboard is used
by. An association carries an is_default flag, and a container has at most one
default dashboard.
Editing a dashboard
A dashboard's layout is edited on its record screen. The value field is
rendered as a structured form — not a raw text blob — so each widget's
options appear as labelled fields with validation, and a Widget type dropdown
per widget switches the config fields to match the chosen type.
A Form view / Code view toggle at the top of the field switches between the two editing modes:
- Form view — the structured editor. The Widgets list holds one entry per
widget; each entry's Widget type dropdown selects the widget type
(
markdown,stat_tile,record_list, …) and the fields below it adapt to the selected type's configuration. This is the no-code way to build and adjust a dashboard without hand-writing YAML. - Code view — the raw YAML/JSON editor for the same
value. Use it for bulk edits, copy-paste, or anything the form doesn't surface.
Both views edit the same underlying value; switching between them keeps your
changes. Save commits the whole value back to the record.
Form view knows the widget types the current Console build ships with. A widget
whose type this build doesn't recognise (for example one added in a newer
version) shows an unselected Widget type dropdown with no sub-fields in Form
view, but its configuration is preserved intact on save — Form view never
discards a widget it can't render. Switch to Code view to read or edit such a
widget's configuration directly.
Configuration shape
The value field describes the grid and widgets:
version: 1
grid:
columns: 12 # grid columns (default: 12)
gap: 12 # pixel gap between cells (default: 16)
rowHeight: 80 # pixel height of one grid row (default: 80)
widgets:
- uid: unique-widget-id
type: markdown # widget type — see below
title: Optional heading
layout:
col: 1 # 1-based start column
row: 1 # 1-based start row
colSpan: 6 # columns to span
rowSpan: 4 # rows to span
config: { ... } # type-specific options
Unknown widget types show a fallback message instead of breaking the whole dashboard.
Live widgets
Widgets that read records or executions accept a live flag. When live is
true the widget re-fetches on an interval and shows a footer with an
"Updated <time ago>" label reflecting the last time the data
actually changed, plus a manual refresh control.
A re-fetch that fails (network blip, gateway error such as 502, or a backend
restart during an upgrade) keeps the last successfully-rendered content on
screen rather than blanking the widget. The failure appears next to the
"Updated …" label — for example Updated 2m ago · Network error or
Updated 2m ago · responded with 502 — so the data is understood to be stale
and the reason is visible. The message clears on the next successful fetch. A
widget that has never loaded (for example a first-load failure or a
misconfiguration) still shows the full error in place of its body.
Widget types
markdown
Static markdown (notes, runbook links, documentation).
type: markdown
config:
text: |
## Runbook
See [Executions monitor](execution-live-monitor) for details.
stat_tile
Count of records matching an optional filter. Uses the list API count field only (no rows transferred). Click the tile to open Advanced search with the same record type and filter applied.
type: stat_tile
config:
record_type: FLOW
filter:
field: project_id
op: eq
value: "<project-uuid>"
live: false # optional: re-poll every 10s
single_record
Detail card for the first record matching filter and sort (limit: 1).
type: single_record
config:
record_type: FLOW
order: "-modified_at"
filter: { field: name, op: like, value: "pipeline%" }
record_list
A live, sortable table of records of one type. It renders through the same table component as Advanced Search, so every widget gets column selection, client-side sorting, search and (optionally) pagination without any extra configuration.
type: record_list
config:
record_type: CUSTOM_OBJECT
order: "-created_at"
filter: { field: provisioning_state, op: eq, value: PROVISIONED }
live: true
Row count — pagination vs. height-adaptive
The limit option decides how rows are paged:
limitset (e.g.limit: 10) — a fixed number of rows with classic pagination.limitunset — the widget is height-adaptive: it sizes the number of rows to the space available in the widget and shows them on a single, footer-less page (no pagination). A taller widget shows more rows; a shorter one shows fewer.
Columns
By default each record type shows a sensible default column set (name, location, modified/created at & by; custom objects also show their object template). Two options tailor the columns:
columns— an explicit ordered list of column keys to show by default. Exactly these columns are shown, in this order; every other column stays reachable from the column selector but is hidden by default. When unset, the automatic per-record-type default set is used. Keys are the record fields (name,location,modified_at,modified_by,created_at,created_by), the custom-objectobject_templatecolumn, and — whenobject_template_idis set — that template's attribute names (an attribute namedstatusis the column keystatus).object_template_id(custom objects only) — additionally render this object template's attributes (the COvalue.<attr>fields) as columns, the same attribute columns the object-template screen shows for its custom objects. This is a pure display hint, decoupled fromfilter: it does not restrict which rows load, so any row belonging to a different template simply shows blank attribute cells.
Attribute columns added via object_template_id are editable in place — a
writable cell can be edited directly in the widget. See Editing attributes in
list views.
A record's top-level name and description are also editable directly in a
record_list widget — for custom objects and for the other resource types
(flows, connectors, settings, schemas, roles, webhooks, …) alike. A pencil on
row hover opens a single-line name editor (commits on Enter / Save), and
the addable Description column opens a Markdown editor (add it from the column
selector or list description in columns). The affordance is hidden — the row
stays a read-only link — when the record is read-only, in a read-only project or
bundle, in the trash, or while its bundle/project holds a git
write lock.
type: record_list
title: Operator tasks
config:
record_type: CUSTOM_OBJECT
object_template_id: "<operator-task-template-uuid>"
columns: [name, status, priority, modified_at]
order: "-modified_at"
live: true
Show all → Advanced search
The widget toolbar (and its empty state) carries a Show all link that opens
Advanced Search pre-seeded with the widget's record type and
filter — so a user can drill from the compact dashboard list straight into the
full, filterable search view with the same rows.
status_strip
Compact provisioning-state list for custom objects.
type: status_strip
config:
record_type: CUSTOM_OBJECT
order: "-created_at"
limit: 10
live: true
status_tile
A single traffic-light-style status indicator: it reads one field off one record
(the first match of filter) and maps its value to a coloured dot and label. Use
it for an at-a-glance health/state tile rather than a full list.
type: status_tile
config:
record_type: CUSTOM_OBJECT
filter: { field: name, op: eq, value: my-status-record }
field: status # for CUSTOM_OBJECT, read from value.<field>
live: true
value_map:
ok: { color: primary-green, label: "Healthy" }
warn: { color: primary-yellow, label: "Degraded" }
down: { color: primary-red, label: "Down" }
default: { color: dark-grey, label: "Unknown" }
value_map colours are semantic palette tokens (primary-green,
primary-yellow, primary-red, primary-blue, dark-grey, …) rather than
ad-hoc hex, so the tile stays consistent in light and dark themes. A value_map
entry may set detail_field (optionally with detail_field_format: datetime) to
render a value from the same record as a sub-line under the label.
An optional stale block shows a fallback state once the record's freshness
timestamp plus a grace period has passed — for example a missing heartbeat:
stale:
timestamp_field: updated_at
grace_seconds: 600
skip_when_values: [paused] # value_map values for which staleness is ignored
color: primary-red
label: "No heartbeat"
latest_n_list
Last N records per distinct field value, using the list API partition_by parameter.
type: latest_n_list
config:
record_type: EXECUTION
order: name # sort partition groups (e.g. by related record name)
limit: 20 # max number of groups
partition_by:
field: type
limit: 1 # rows per group (shorthand: top-level `n`)
order: "-created_at" # newest row per group
Top-level order controls how groups are sorted in the widget. partition_by.order controls which rows are kept within each group (and their order). When partition_by.order is omitted, it falls back to the top-level order.
action_button
Runs a flow on click. With navigate_to_execution: true, the dashboard navigates to the created execution in the same tab. When navigate_to_execution is false (the default), the widget shows a link below the button to open the latest execution in a new tab, together with a live “time ago” label for when it was started.
type: action_button
config:
label: Deploy
flow_id: "<flow-uuid>"
navigate_to_execution: true
run_flow_with_inputs
Renders a flow's input_schema as a form and, on submit, starts an execution of that flow with the entered values as its input_value. Where action_button runs a flow with static inputs, this widget lets the viewer fill in the inputs first.
The form is the same schema-driven form used by the record editor and the flow Run with options dialog: it supports nested objects, arrays, datatype validation, required fields, and a raw-code (YAML/JSON) fallback for anything it can't render as fields. A plain JSON Schema input_schema (no Cloudomation element keys) is auto-rendered as a form too.
| Config | Default | Description |
|---|---|---|
flow_id | — (required) | Flow whose input_schema is rendered and which is executed on submit. |
submit_label | "Run" | Label on the submit button. |
navigate_to_execution | false | When true, open the created execution after submit (same tab). When false, a link to open it (with a “time ago” label) appears below the button. |
fixed_input | {} | Static input values merged under the form values — form values win on key collision. Use for constants the viewer should not edit. |
success_message | "Started execution." | Notification text shown on a successful run. |
reset_on_success | true | Reset the form back to its schema defaults after a successful submit. |
type: run_flow_with_inputs
title: New request
config:
flow_id: "<flow-uuid>"
submit_label: Submit
navigate_to_execution: false
fixed_input:
source: dashboard
The widget guards against losing entered data: navigating away with unsaved changes prompts for confirmation.
record_form
Renders a small form and creates a workspace record when submitted. It works for any record type; each field writes its value into the created record's payload by a dotted path, so bare paths set top-level fields (e.g. name) and value.-prefixed paths set custom-object attributes (e.g. value.ask).
| Config | Default | Description |
|---|---|---|
record_type | — (required) | Record type to create, e.g. custom_object or flow (posted to /<record_type>). |
object_template_id | — | For custom objects: the object template the created record is built on. |
fixed | {} | Static values merged into every created record (dotted paths supported), e.g. { "value.status": "new" }. |
fields | [] | The editable form fields, rendered top-to-bottom (see below). |
name_template | — | Optional name for the created record. The {timestamp} token is replaced with an ISO timestamp to keep generated names unique. When omitted, the backend assigns a name. |
submit_label | "Create" | Label on the submit button. |
success_message | "Created." | Notification text shown on a successful create. |
reset_on_success | true | Clear the form after a successful submit. |
Each entry in fields describes one input:
| Field key | Default | Description |
|---|---|---|
path | — (required) | Dotted path where the entered value is written in the payload (bare key = top-level field; value. prefix = custom-object attribute). |
label | last path segment | Label shown above the input. |
input | "text" | Control to render: text, textarea, or select. |
options | — | Options for a select input: a list of { label, value }. |
placeholder | — | Placeholder text for text/textarea inputs. |
required | false | When true, the field must be non-empty before the form can be submitted. |
default | "" | Initial value seeded into the field (and restored on reset). |
Empty optional fields are omitted from the payload, so they don't overwrite backend defaults.
type: record_form
title: New one-line ask
config:
record_type: custom_object
object_template_id: "<object-template-uuid>"
name_template: "ask {timestamp}"
submit_label: Send
fixed:
value.status: new
fields:
- path: value.ask
label: Your request
input: textarea
required: true
placeholder: Describe what you need…
- path: value.priority
label: Priority
input: select
default: normal
options:
- { label: Low, value: low }
- { label: Normal, value: normal }
- { label: High, value: high }
execution_output
Shows status and output (or recent logs) of an execution. Use execution_id for a fixed execution, or flow_id for the latest execution of that flow. When live is true, the widget polls for updates; polling stops once the execution has ended only when execution_id is used (with flow_id, polling continues so a newly started execution is picked up).
type: execution_output
config:
flow_id: "<flow-uuid>"
live: true
show: output # or "logs" or "message"
log_limit: 20
type: execution_output
config:
execution_id: "<execution-uuid>"
live: true
show: output
relation_graph
Embeds the object template / custom object relation canvas in read-only form, scoped by filters instead of loading the full workspace graph.
Two modes:
mode | Shows |
|---|---|
object_template | Object templates and reference edges between them |
custom_object | Custom objects grouped by template, with cross-reference edges |
Object-template graph (templates in a project):
type: relation_graph
title: Template references
layout: { col: 1, colSpan: 12, row: 1, rowSpan: 6 }
config:
mode: object_template
filter:
field: project_id
op: eq
value: "<project-uuid>"
Custom-object graph (latest object per template type in a bundle):
type: relation_graph
title: Latest installations by type
layout: { col: 1, colSpan: 12, row: 1, rowSpan: 8 }
config:
mode: custom_object
filter:
field: bundle_id
op: eq
value: "<bundle-uuid>"
partition_by:
field: object_template_id
limit: 1
order: "-created_at"
limit: 50 # max distinct object templates (groups)
filter uses the same JSON filter grammar as Advanced Search and the REST/GraphQL list APIs. For custom_object mode you can also set custom_object_filter (alias for filter when seeding from custom objects).
With partition_by, the widget loads the most recent custom object per distinct field value (typically object_template_id), then renders reference relationships between those objects and related templates.
Filters
Filters are comparison objects or boolean combinations:
# equality
filter: { field: bundle_id, op: eq, value: "<uuid>" }
# AND
filter:
and:
- { field: bundle_id, op: eq, value: "<uuid>" }
- { field: provisioning_state, op: eq, value: PROVISIONED }
Supported operators include eq, neq, like, notlike, lt, gt, lte, gte, set, unset, in, and notin.
Related topics
- Object templates and custom objects — data model behind
relation_graph - Bundles — bundle-scoped content and filters
- Advanced Search — filter grammar and record discovery