Overview Templates
An overview template is a JSON file describing a war-room / cross-cutting dashboard composed from MQE-driven widgets on a 12-column grid. Overviews are independent of any single layer and are designed for the operator’s “is everything OK?” pane.
Bundled templates: apps/bff/src/bundled_templates/overviews/<id>.json. Examples:
services.json— cross-layer service health + Kubernetes capacity summary.mesh.json— Istio data-plane services + pilot activity + Kubernetes.
Top-level shape
{
"id": "services",
"title": "Service Health",
"description": "Cross-layer service traffic, latency, errors, and capacity.",
"visibility": "public",
"icon": "services",
"order": 1,
"layers": ["GENERAL", "MESH", "K8S_SERVICE"],
"widgets": [
{ "type": "section-break", "title": "Service traffic", "cols": 12 },
{ ... metric widget ... },
{ ... kpi-tile ... },
{ "type": "section-break", "title": "Cluster capacity", "cols": 6 },
{ ... metric-composite ... }
]
}
Top-level fields
| Field | Type | Default | Notes |
|---|---|---|---|
id |
string | required | Stable id, used in the route /overview/:id. |
title |
string | required | Display title in the sidebar and page header. |
description |
string | — | One-line description shown under the title. |
visibility |
public | operate |
public |
Sidebar placement. operate puts the overview under the Operate group (admin-only by convention). |
icon |
string | — | Sidebar icon name (from Horizon’s icon set). |
order |
number | — | Sort order within the visibility bucket (lower = earlier). |
layers |
string[] | — | Layer enums this overview aggregates. Optional — used as a hint by the sidebar and by widgets that want a default layer for MQE evaluation. |
widgets |
array | required | Ordered widget list. The renderer iterates and lays out per the grid model. |
Widget types
Six supported type values:
| Type | Renders |
|---|---|
metric |
Single MQE scalar with optional unit. |
topology |
Service-map snapshot for the configured layer. |
section-break |
Visual row header; carries cols to override the grid column count for following widgets. |
kpi-tile |
Compound tile: optional service count + N KPI rows. |
alarms |
Active-alarm rail (60 min window). |
metric-composite |
Mixed KPI grid — number tiles + progress-bar rows. |
See Components → Overview Widgets for the per-widget detail.
Grid model
The overview renders on a CSS grid:
- Per-section column count, default 12, set by the most recent
section-break.cols. - Fixed row height 72 px.
- Per-widget
span(column width, 1–12) androwSpan(row height, 1–8). - Gap 12 px between widgets.
- Single-column responsive collapse below 1100 px viewport.
The 72 px row height is tuned for KPI tile content; widgets that need more vertical space (a small chart, a multi-row composite) use rowSpan: 2 or rowSpan: 3.
Widget shape (common fields)
| Field | Notes |
|---|---|
id |
Unique within the dashboard. |
title |
Card title (not used by section-break — uses title as the section header). |
tip |
Optional one-line hover hint next to the title. |
layer |
Layer key (UPPER_SNAKE). Used to scope MQE evaluation. Optional for section-break and alarms (alarms can scope server-side if the layer is set). |
type |
One of metric, topology, section-break, kpi-tile, alarms, or metric-composite. |
span |
Column span. Defaults vary per widget type. |
rowSpan |
Row span. Defaults vary per widget type. |
mqe, unit, aggregation |
Metric-specific fields. |
cols |
Section-break column count for following widgets. |
kpis, showCount, limit |
Type-specific fields described below. |
OverviewKpi
Used by kpi-tile and metric-composite:
| Field | Notes |
|---|---|
label |
Row label. |
mqe |
Required when source === 'mqe' (the default). |
unit |
Unit suffix. |
aggregation |
sum for throughput / count; avg for ratios and rates. |
style |
number (default) or progress-bar. |
max |
Required when style === 'progress-bar' — the 100% value. |
source |
mqe (default) or service-count — the latter reads the layer’s service count from the menu response instead of evaluating MQE. |
Worked examples
metric widget
{
"id": "total_rpm",
"title": "Total RPM",
"type": "metric",
"layer": "GENERAL",
"mqe": "sum(service_cpm)",
"unit": "rpm",
"aggregation": "sum",
"span": 3,
"rowSpan": 1
}
Single scalar tile. The MQE collapses to one number (here, sum over the time window).
kpi-tile with service count + two KPIs
{
"id": "general_summary",
"title": "General services",
"type": "kpi-tile",
"layer": "GENERAL",
"showCount": true,
"span": 4,
"rowSpan": 3,
"kpis": [
{
"label": "Apdex",
"mqe": "avg(service_apdex/10000)",
"aggregation": "avg",
"style": "progress-bar",
"max": 1
},
{
"label": "P95",
"mqe": "avg(service_percentile{p='95'})",
"unit": "ms",
"aggregation": "avg"
}
]
}
showCount: true adds a service-count header row above the KPIs.
metric-composite — mixed number + bar grid
{
"id": "k8s_summary",
"title": "Cluster capacity & utilisation",
"type": "metric-composite",
"layer": "K8S",
"span": 12,
"rowSpan": 3,
"kpis": [
{ "label": "Nodes", "mqe": "latest(k8s_cluster_node_total)", "aggregation": "avg" },
{ "label": "Pods", "mqe": "latest(k8s_cluster_pod_total)", "aggregation": "avg" },
{ "label": "CPU",
"mqe": "k8s_cluster_cpu_cores_requests / k8s_cluster_cpu_cores * 100",
"unit": "%", "aggregation": "avg",
"style": "progress-bar", "max": 100 },
{ "label": "Memory",
"mqe": "k8s_cluster_memory_requests / k8s_cluster_memory * 100",
"unit": "%", "aggregation": "avg",
"style": "progress-bar", "max": 100 }
]
}
The widget auto-splits KPIs:
number-style KPIs (Nodes, Pods) go into the count-tile row (auto-fit, min 100 px).progress-bar-style orunit === '%'KPIs go into the bar grid (auto-fit, min 180 px).
This single widget replaces what used to be three separate hand-crafted widgets (k8s-service-count, pilot, service-count) — anything compound now goes through metric-composite.
section-break to start a new row
{ "type": "section-break", "title": "Cluster capacity", "cols": 6 }
Following widgets render in a 6-column grid (rather than 12) until the next section-break. Used for paired side-by-side panes.
alarms rail
{
"id": "active_alarms",
"title": "Active alarms (60 min)",
"type": "alarms",
"layer": "GENERAL",
"limit": 10,
"span": 4,
"rowSpan": 4
}
Read-only — Horizon does not support acknowledge / close / silence operations. Alarm recovery is backend-automatic.
Admin Editor
Overview templates are editable at runtime via Dashboard setup → Overview templates (/admin/overview-templates, verb overview:write). The editor:
-
Lists all bundled overviews + any added ones, with widget count and editable flag.
-
For each overview, shows the widget array with per-widget controls.
-
Type-aware editor: per
widget.type, only the relevant fields are exposed:Type Fields shown section-breaktitle,colsmetriclayer,title,tip,mqe,unit,aggregation,span,rowSpantopologylayer,title,tip,span,rowSpanalarmslayer,title,tip,limit,span,rowSpankpi-tilelayer,title,tip,showCount, KPI rows (add / remove),span,rowSpanmetric-compositelayer,title,tip, KPI rows (mixed MQE + service-count source),span,rowSpan -
Add / remove widgets with the type picker.
-
Preview renders the in-progress template against live OAP data.
The save/publish model has two steps:
- Save locally. The edit is written to the local bundled copy and renders immediately for preview. OAP is not changed yet.
- Publish. Sync all to OAP pushes diverged overview templates to OAP behind a confirmation that lists the affected templates.
If the local copy differs from OAP, Horizon shows the template as diverged. Use Show diff to compare local and remote, Keep my local edits to preview, or Use live to discard the local copy and render the OAP version.
Hot reload
Admin editor changes apply on the next overview refresh. Bundled file changes made outside Horizon require a BFF restart.
Common patterns
A war-room single-screen view
One overview, id: war-room, with layers: [ALL_YOUR_LAYERS], and:
section-break“Health” + 4 ×kpi-tile(one per critical layer with service-count + RPS / error-rate KPIs).section-break“Alarms” + 1 ×alarmswidget (span 12) showing every firing alarm.section-break“Capacity” + 1 ×metric-composite(span 12) with cluster capacity.
Layout fits a 1440 px display above the fold; works on a wall projector at 1920 px.
A team-specific overview
visibility: operate, only granted to the team’s role via landingByRole:
landingByRole:
payments-on-call: /overview/payments
The team lands directly on their own overview after login.
Replacing the old k8s / pilot / service-count widgets
Use metric-composite with one widget per cluster summary. The old per-feature widget types are no longer rendered — metric-composite is the unified shape.