Skip to Content
This documentation is provided with the HEAT environment and describes this HEAT instance.
DevelopersDashboardsLayout reference

Layout reference

A Layout is the JSON that says how a Dimension is rendered: rows of widgets, each bound to named channels. It is separate from the data. The data service payload says what data exists, and the layout says which widget shows which channel and how.

A dashboard node publishes the layout with the dimension. On the dashboard-tools runner that node is dashboard-v2 and the layout is its layoutConfiguration key. On system-utils it is heat-system-next-dimension, which can also take the layout from its parent output when layoutFromParentOutput is true. The Next dashboard reads the stored layout, resolves each column’s channels against the realm in view and renders.

A layout is not a Legacy v1 layout. Legacy used cols[].component mount ids and fixed payload keys per widget. The v2 layout described here binds by channel id and is documented for the Next dashboard only.

Top-level document

{ "$schema": "https://heatvr.io/layout-schema.json", "version": "1.0.0", "configuration": { "enableGlobalPlaybackControls": true, "defaultRealm": "default", "showRealmFilterDropdown": false }, "realms": ["default"], "components": { "rows": [] } }
KeyRequiredMeaning
versionNoLayout schema version label. dashboard-v2 writes "1.0" when it is missing.
configurationNoPage-level settings. See below.
realmsYesThe realm names this layout knows about. A Realm is a namespace for channels within one dimension, used to compare trainees or runs side by side.
components.rowsYesThe rows of widgets. An empty array is valid and renders an empty page.
$schemaNoPoints editors at the schema. dashboard-v2 sets it on the stored layout.

Page configuration

KeyTypeMeaning
enableGlobalPlaybackControlsbooleanShow the page-level playback bar that drives every playback-aware widget through the realm clock. Default false.
enableLiveDataPollingbooleanPoll for new data while the dashboard is open.
defaultRealmstringThe realm selected when the page opens.
showRealmFilterDropdownbooleanShow the realm picker at the top of the page.
realmFilterLabelstringLabel for that picker. Defaults to “Realms”.
modalButton, modalComponentsNamestring, string[]Present in the schema. The dashboard today derives the modal button from a Modal row instead. See Modal.

Rows

Each entry in components.rows is one horizontal band of the page.

KeyTypeMeaning
colsarrayThe columns in the row. Required.
tabstringName of the tab that contains the row, when the page is tabbed.
categorystringFree grouping label.
dualComponent"None", "Dual", "Side"Whether the row renders a dual component and how. Widgets that support it are marked supportsDualColumn in the component registry.
isCollapsiblebooleanWhether the row can be folded away.
marginBottomnumberBottom margin in pixels.

Columns

Each entry in cols places one Widget.

KeyTypeMeaning
componentstringThe widget id, for example ComposableChart. Case-sensitive. The full list is on the components index.
colspannumberWidth as a proportion of the row. Two columns with 6 and 6 share the row equally, as do 1 and 1.
visiblebooleanHide the column without removing it.
marginBottomnumberBottom margin in pixels.
configurationobjectThe widget’s binding and options. See below.

Column configuration

Three keys are common to every widget and are required by the component registry.

KeyMeaning
nameThe widget instance name. Unique within the layout, so two charts of the same type can coexist.
titleContentThe panel title.
channelsChannel ids this widget reads, resolved in the realm in view. Some widgets also bind channels inside their own configuration object and leave this list short or empty.

Optional presentation keys apply across widgets.

KeyMeaning
shouldRenderTitle, titleIconWhether to show the title and an icon before it
tooltipContent, shouldRenderTooltipTooltip text and whether to show it
defaultRealm, showRealmFilterDropdownPer-widget realm selection for widgets marked supportsRealmFilter
enablePlaybackControlsShow a playback bar on this widget for widgets marked supportsPlaybackControls
showOpenModalButtonShow a button that opens the page modal
chartHeight, truncateXAxisLabelsBarChart presentation

Per-widget configuration key

Most widgets take their options under one named object. The key is fixed per widget and recorded as widgetConfigKey in the component registry (ui/dashboard/src/dashboard-manifest/registry.ts). The registry also records requiredConfigurationKeys, which is always titleContent, channels and name plus the widget key where one exists.

ComponentWidget config keyPlaybackRealm filterDual column
BarChartbarChartItemNoNoNo
CircuitStatscircuitStatsItemsNoNoNo
CognitiveLoadcognitiveItemYesNoYes
CognitiveLoadBreakdowncognitiveLoadBreakdownItemNoNoNo
CommscommsItemYesNoNo
ComposableChartcomposableChartItemYesYesYes
CustomRenderercustomRendererItemNoNoNo
EyeTrackingNoneNoNoYes
EyeTrackingContainereyeTrackingItemNoNoNo
FlightPathflightPathItemYesNoYes
ImpactHeatmapNoneNoNoNo
LeaderBoardleaderBoardItemNoNoYes
MapDisplaymapDisplayItemYesYesYes
ModalmodalItemYesYesYes
ProgressScoreprogressScoreItemsNoNoNo
ResponseTimeresponseTimeItemNoNoYes
StatsSummarystatsItemsNoNoNo
TacticalMapNoneYesNoNo
TimelineCharttimelineItemsYesNoYes
VideoPlaybackvideoPlaybackItemYesNoNo

TimelineChart is only partially migrated to the data service. Use ComposableChart for new layouts. CustomRenderer binds no channels and is documented as layout only.

The JSON schema

The schema lives in the dashboard source at ui/dashboard/src/lib/data-service/data-lib/heat-client/docs/heat-layout-schema.json (view on GitHub ). Its $id is https://heatvr.io/layout-schema.json, which is the value the presets put in $schema. Each widget’s configuration object has its own definition under $defs, for example #/$defs/CommsItemSchema and #/$defs/StatsSummarySchema.

This is the schema trimmed to its skeleton. The component enum and the list of widget keys are the parts that change when a widget is added.

{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://heatvr.io/layout-schema.json", "title": "LayoutSchema", "type": "object", "required": ["components", "realms"], "properties": { "configuration": { "type": "object", "properties": { "enableGlobalPlaybackControls": { "type": "boolean", "default": false }, "enableLiveDataPolling": { "type": "boolean" }, "defaultRealm": { "type": "string" }, "showRealmFilterDropdown": { "type": "boolean" }, "realmFilterLabel": { "type": "string" } } }, "realms": { "type": "array" }, "components": { "type": "object", "properties": { "rows": { "type": "array", "items": { "type": "object", "properties": { "tab": { "type": "string" }, "dualComponent": { "type": "string", "enum": ["None", "Dual", "Side"] }, "isCollapsible": { "type": "boolean" }, "marginBottom": { "type": "number", "minimum": 0 }, "cols": { "type": "array", "items": { "type": "object", "properties": { "component": { "type": "string", "enum": ["BarChart", "ComposableChart", "StatsSummary", "..."] }, "visible": { "type": "boolean" }, "colspan": { "type": "number", "minimum": 1 }, "marginBottom": { "type": "number", "minimum": 0 }, "configuration": { "type": "object", "properties": { "titleContent": { "type": "string" }, "channels": { "type": "array", "items": { "type": "string" } }, "name": { "type": "string" }, "composableChartItem": { "$ref": "#/$defs/ComposableChartItemSchema" }, "statsItems": { "$ref": "#/$defs/StatsSummarySchema" } } } } } } } } } } } }, "$defs": { "ComposableChartItemSchema": { "type": "object" }, "StatsSummarySchema": { "type": "object" } } }

The "..." entry stands in for the remaining component ids. The $defs bodies are omitted here. Read the file for the full field lists.

How dashboard-v2 merges realms

The dashboard-v2 node stores the layout you configure, with realm hints filled in from the data it received. The steps below are taken from the runner’s _merge_layout_with_realms routine.

  1. It sets $schema to https://heatvr.io/layout-schema.json and version to "1.0" when absent.
  2. It appends every realm name found in the $heat-dataservice payload to realms, keeping the order you wrote and adding new names at the end.
  3. When more than one realm results, it sets configuration.showRealmFilterDropdown to true unless you set it.
  4. When at least one realm exists, it sets configuration.defaultRealm to the first realm unless you set it.

Nothing else in the layout is touched. Values you set always win. This means a template can ship a layout that names no realms at all and still open on the right one, and a template that names ["pilot-a", "pilot-b"] opens on pilot-a with the picker shown.

heat-system-next-dimension on system-utils applies the same four steps before it persists the layout, so a template behaves the same whichever publisher it ends in.

Opens your browser's print dialog. Choose "Save as PDF" as the destination.