Harumi

Widgets

Every dashboard.toml widget type — required and optional keys, and a working example for each.

Every widget is a [[widgets]] entry

dashboard.toml renders one view per [[widgets]] table. Every entry, of every type below, needs the same three keys:

Prop

Type

Everything else is type-specific — covered per type below. A widget with an unknown type, or missing one of its type's required keys, is dropped from the rendered dashboard and reported by harumi dashboard validate rather than breaking the page.

Beyond widgets

dashboard.toml can also declare reusable datasets, define new KPIs as SQL, and add clock-driven playback — none of which are covered here. See Dashboard datasets, metrics, and the clock.

Layout

[layout]
columns = 2

[layout] is optional; columns (the grid's column count at the desktop breakpoint) defaults to 2 when omitted. It only affects widgets that lay out in the main grid — most types below. Three types opt out of the grid entirely and always render in a fixed position instead:

  • kpi-rail renders in a full-width strip above the grid.
  • detail and filter render in a narrow sidebar beside it, reacting to (or driving) a selection made by another widget — typically a timeline's row click.

Every other type below renders in the main grid and is full-width, except metric, which is narrow enough for two to share a row.

KPI tiles

metric

A single KPI tile — a value with an optional delta.

Prop

Type

[[widgets]]
type = "metric"
id = "revenue"
title = "Total revenue"
value_key = "totals.revenue"
format = "currency"

kpi-rail

Several KPI tiles in one horizontal row — for a handful of related numbers that read better side by side than as separate metric widgets competing for grid columns. Always renders as a full-width strip above the grid, regardless of where it appears in [[widgets]] declaration order.

Prop

Type

[[widgets]]
type = "kpi-rail"
id = "summary"
title = "Run summary"
items = [
  { label = "Total cost", value_key = "totals.cost", format = "currency" },
  { label = "Makespan", value_key = "totals.makespan", unit = "min" },
  { label = "Utilization", value_key = "totals.utilization", format = "percent" },
  { label = "Setup time", rows_key = "machines", progress_key = "progress" },
]

Table

table

A sortable data grid bound to an array of row objects.

Prop

Type

[[widgets]]
type = "table"
id = "breakdown"
title = "Breakdown"
rows_key = "breakdown"
columns = [
  { key = "name", label = "Name" },
  { key = "value", label = "Value" },
]

Charts

chart

A line or bar chart, picked by variant — folds the legacy line-chart and bar-chart types (below) into one, since they only ever differed in that.

Prop

Type

[[widgets]]
type = "chart"
id = "trend"
title = "Objective value over time"
variant = "line"
data_key = "timeseries"
x_key = "label"
series = [{ key = "value", label = "Objective value" }]

Timelines & schedules

timeline

A resource-row timeline on a numeric time axis — the current, recommended type for scheduling/job-shop solver results (one row per machine/resource, one bar per task). Supersedes gantt-chart (below): interrupted work folds into one item drawn with gaps, non-working spans render as background bands, the axis is drag-to-zoom, and a [clock] playhead (see Dashboard datasets, metrics, and the clock) shows as a now-marker.

Prop

Type

[[widgets]]
type = "timeline"
id = "schedule"
title = "Machine schedule"
items_key = "schedule"
id_key = "op"
regions_key = "breaks"
time_unit = "min"

gantt-chart

A resource-row Gantt chart on a numeric time axis — the same shape timeline covers, kept so dashboards written before timeline existed keep rendering. Prefer timeline for a new dashboard.

Prop

Type

[[widgets]]
type = "gantt-chart"
id = "schedule"
title = "Machine schedule"
tasks_key = "schedule"
time_unit = "min"

Breakdowns

treemap

A flat treemap — one rectangle per row, area proportional to value_key, labeled from name_key. Good for a breakdown where relative size matters more than exact values (e.g. cost by machine).

Prop

Type

[[widgets]]
type = "treemap"
id = "cost-breakdown"
title = "Cost by machine"
items_key = "breakdown"
value_key = "cost"
name_key = "machine"

heatmap

An entity x time-bucket grid, shaded by intensity — one row per resource, one column per bucket (e.g. hour of day). A (resource, bucket) pair with no matching row renders as a distinct unavailable cell rather than a zero.

Prop

Type

[[widgets]]
type = "heatmap"
id = "hourly-cycles"
title = "Cycles per hour"
items_key = "hourly_cycles"
resource_key = "resource"
bucket_key = "bucket"
value_key = "value"

Selection & detail

filter

A picker that sets the dashboard's selection — one option per distinct id_key value in items_key. An alternative to clicking a timeline bar, for choosing an item by name. Always renders in the sidebar.

Prop

Type

[[widgets]]
type = "filter"
id = "task-filter"
title = "Choose a task"
items_key = "schedule"
id_key = "op"
label_key = "task"

detail

Shows the fields of whichever row is currently selected (via a timeline click, a filter pick, or any other selecting view) — looked up by matching id_key against the selection id. Always renders in the sidebar.

Prop

Type

[[widgets]]
type = "detail"
id = "task-detail"
title = "Task details"
items_key = "schedule"
id_key = "op"
fields = [
  { key = "task", label = "Task" },
  { key = "resource", label = "Machine" },
]

Legacy chart types

line-chart and bar-chart predate chart (above), which folds both into one type picked by variant. Both are still fully supported — so a dashboard written before chart existed keeps rendering — but prefer chart for anything new.

line-chart

A line chart — good for a value trending over time.

Prop

Type

[[widgets]]
type = "line-chart"
id = "trend"
title = "Objective value over time"
data_key = "timeseries"
x_key = "label"
series = [{ key = "value", label = "Objective value" }]

bar-chart

A bar chart — good for comparing values across categories.

Prop

Type

[[widgets]]
type = "bar-chart"
id = "breakdown-chart"
title = "Cost by warehouse"
data_key = "breakdown"
x_key = "name"
series = [{ key = "value", label = "Cost" }]

Checking your widgets before you commit

harumi dashboard widgets prints this same reference from your terminal (optionally filtered with --type), and harumi dashboard validate checks a real dashboard.toml against it — flagging an unknown type, a missing required key, or (given --against, --run, or --latest) a dot-path that doesn't resolve against an actual output.json.

On this page