Problem
Chart panels currently render result-column names and numeric values with generic formatting.
The saved-query Spec already has a first-class field metadata contract:
{
"panel": {
"fieldConfig": {
"defaults": {
"decimals": 1
},
"columns": {
"cpu_usage": {
"displayName": "CPU usage",
"unit": "%",
"decimals": 1
},
"memory_bytes": {
"displayName": "Memory",
"unit": " B",
"decimals": 0
}
}
}
}
}
KPI rendering consumes much of this metadata, but chart rendering still uses:
- raw result-column names in legends;
- one generic
K/M formatter;
- no configured unit;
- no configured decimal precision;
- no field-level hidden state.
This makes imported Grafana-style monitoring panels look unfinished even when the query Spec already contains the information required for a better presentation.
Goal
Apply existing panel.fieldConfig metadata consistently to chart panels without adding a large chart-formatting toolbar.
The workbench remains simple:
Type | Style | X | Y | Series
Detailed formatting stays in the Spec editor.
This issue must support:
- display names;
- units;
- decimal precision;
- hidden fields;
- field descriptions in tooltips where practical;
- compatible axis formatting;
- identical workbench and Dashboard rendering.
No new panel type is required.
noValue remains preserved as field metadata, but interactive missing-point
text is deferred to #257: Chart.js excludes null/skipped points from normal
tooltip selection, and configuring only noValue must not alter valid values'
existing localized tooltip formatting.
UX contract
Do not add per-series formatting controls to the chart toolbar.
The visible chart UX remains compact.
Authors who need advanced formatting use the Spec editor, which is a first-class authoring surface with schema-driven completion.
The rendered chart should immediately reflect Spec edits after the normal panel repaint.
Spec contract
Reuse the existing field metadata shape.
{
"panel": {
"fieldConfig": {
"defaults": {
"unit": "",
"decimals": 2,
"noValue": "—"
},
"columns": {
"latency_p95": {
"displayName": "p95 latency",
"description": "95th percentile query latency.",
"unit": " ms",
"decimals": 1,
"hidden": false
}
}
}
}
}
Precedence:
column override
→ defaults
→ renderer fallback
Unknown metadata fields remain preserved and ignored.
Field resolution
Add or reuse a pure helper that resolves effective field metadata:
resolveFieldConfig(fieldConfig, columnName)
Suggested output:
{
displayName: "p95 latency",
description: "95th percentile query latency.",
unit: " ms",
decimals: 1,
color: null,
noValue: "—",
hidden: false
}
Requirements:
- no DOM;
- no Chart.js import;
- no mutation;
- exact column-name matching;
- defaults merged before column overrides;
- invalid optional values fall back safely;
- unknown values remain stored.
Legend labels
For each dataset derived from a result column:
fieldConfig.columns.<column>.displayName
→ raw result-column name
For a Series-pivoted chart, preserve the Series value as the dataset identity.
Recommended label behavior:
no Series pivot:
dataset label = field displayName
Series pivot:
dataset label = series value
Do not prepend the measure name to every Series value by default.
For multi-measure and Series combinations that are not currently supported, retain existing behavior.
Tooltip formatting
Tooltip values must use the effective field metadata for the measure that produced the dataset.
Suggested formatting:
formatChartValue(value, {
decimals,
unit
})
Rules:
- numeric values use configured decimals when present;
- unit is appended exactly as authored;
- no implicit scaling is performed by
unit;
- values remain unchanged in data;
- raw category/Series labels are not reformatted as measures.
Examples:
68.234 with decimals=1, unit="%"
→ 68.2%
1048576 with decimals=0, unit=" B"
→ 1048576 B
This issue does not introduce automatic byte, duration, or percentage conversion.
Axis formatting
A shared value axis can use field-specific formatting only when all visible measures on that axis are compatible.
Two measures are compatible when their effective metadata has the same:
When compatible:
- use the shared configured decimals;
- append the shared unit;
- retain compact magnitude formatting only when it does not conflict with exact decimals.
When incompatible:
- keep the generic numeric axis formatter;
- format each tooltip with its own field metadata.
Examples:
CPU user %, CPU system %
→ axis may show %
bytes read, rows read
→ generic shared axis; tooltips remain field-specific
Do not add dual axes in this issue.
Hidden fields
A result measure with:
must not render as a chart dataset.
Requirements:
- preserve it in the SQL result;
- preserve it in the saved Spec;
- omit it from legends and tooltips;
- keep it available in the Y selector so the user can explicitly choose it;
- when every selected Y field is hidden, show a clear empty-state message;
- do not silently rewrite
cfg.y.
Suggested message:
All selected chart fields are hidden by panel.fieldConfig.
A Series value cannot currently be hidden through fieldConfig because it is runtime data rather than a top-level result column.
Missing-value geometry
Current chart data construction coerces empty and invalid values to zero.
For presentation fidelity, distinguish:
Do not plot missing numeric values as zero for Line and Area charts.
Recommended behavior:
- Line/Area: use
null so Chart.js creates a gap;
- Bar/Column: use
null or zero only according to existing documented behavior; prefer null;
- Pie: omit or treat as zero consistently and document it.
Interactive noValue presentation is deferred to #257; null points are not
reachable through Chart.js's normal tooltip callbacks.
This issue may require a focused change in buildChartData() so missing values survive until rendering.
Field color
The existing Spec supports:
Initial support in this issue is optional.
If implemented:
- resolve supported theme tokens and CSS colors;
- fall back to the normal palette for invalid values;
- do not add a color picker;
- preserve existing palette behavior when no color is configured.
If color support materially expands scope, keep it out and track it separately.
Rendering API
Extend the shared chart renderer to receive field metadata:
chartJsConfig(
columns,
rows,
cfg,
colors,
{
fieldConfig,
hideGrid
}
)
or an equivalent resolved metadata map.
Do not let the renderer read application state directly.
Workbench, detached view, and Dashboard must call the same path.
Files
Expected areas:
src/core/chart-data.js
src/core/field-config.js or existing equivalent
src/ui/chart-render.js
src/ui/panels.js
schemas/query-spec-v1.schema.json only if documentation needs correction
tests/unit/chart-data.test.js
tests/unit/chart-render.test.js
tests/unit/panels.test.js
tests/unit/dashboard.test.js
No new runtime dependency.
No saved-query migration.
Tests
Cover:
- displayName replaces raw measure name;
- Series-pivoted labels remain Series values;
- default metadata applies;
- column override wins;
- units and decimals format tooltips;
- compatible measures format the axis;
- incompatible measures keep generic axis formatting;
- hidden measure is not rendered;
- all hidden measures show a useful empty state;
- hidden state does not rewrite
cfg.y;
- NULL is not silently rendered as zero for Line/Area;
- noValue-only metadata preserves existing valid-value tooltip formatting;
- unknown field metadata is preserved;
- Dashboard and workbench produce the same dataset labels and tooltip callbacks;
- legacy charts without fieldConfig render as before except for intentional NULL behavior.
Non-goals
Do not include:
- a chart formatting dialog;
- per-series UI editors;
- dual Y axes;
- automatic unit conversion;
- Grafana unit catalogs;
- regex field matchers;
- runtime threshold coloring;
- data calculations;
- query rewriting;
- new chart types.
Acceptance criteria
Definition of done
A chart authored with panel.fieldConfig renders polished labels and values without adding UI complexity.
Simple chart structure remains configurable through compact controls, while display names, units, precision, hidden fields, and related presentation details remain available in the Spec editor.
Problem
Chart panels currently render result-column names and numeric values with generic formatting.
The saved-query Spec already has a first-class field metadata contract:
{ "panel": { "fieldConfig": { "defaults": { "decimals": 1 }, "columns": { "cpu_usage": { "displayName": "CPU usage", "unit": "%", "decimals": 1 }, "memory_bytes": { "displayName": "Memory", "unit": " B", "decimals": 0 } } } } }KPI rendering consumes much of this metadata, but chart rendering still uses:
K/Mformatter;This makes imported Grafana-style monitoring panels look unfinished even when the query Spec already contains the information required for a better presentation.
Goal
Apply existing
panel.fieldConfigmetadata consistently to chart panels without adding a large chart-formatting toolbar.The workbench remains simple:
Detailed formatting stays in the Spec editor.
This issue must support:
No new panel type is required.
noValueremains preserved as field metadata, but interactive missing-pointtext is deferred to #257: Chart.js excludes null/skipped points from normal
tooltip selection, and configuring only
noValuemust not alter valid values'existing localized tooltip formatting.
UX contract
Do not add per-series formatting controls to the chart toolbar.
The visible chart UX remains compact.
Authors who need advanced formatting use the Spec editor, which is a first-class authoring surface with schema-driven completion.
The rendered chart should immediately reflect Spec edits after the normal panel repaint.
Spec contract
Reuse the existing field metadata shape.
{ "panel": { "fieldConfig": { "defaults": { "unit": "", "decimals": 2, "noValue": "—" }, "columns": { "latency_p95": { "displayName": "p95 latency", "description": "95th percentile query latency.", "unit": " ms", "decimals": 1, "hidden": false } } } } }Precedence:
Unknown metadata fields remain preserved and ignored.
Field resolution
Add or reuse a pure helper that resolves effective field metadata:
Suggested output:
Requirements:
Legend labels
For each dataset derived from a result column:
For a Series-pivoted chart, preserve the Series value as the dataset identity.
Recommended label behavior:
Do not prepend the measure name to every Series value by default.
For multi-measure and Series combinations that are not currently supported, retain existing behavior.
Tooltip formatting
Tooltip values must use the effective field metadata for the measure that produced the dataset.
Suggested formatting:
Rules:
unit;Examples:
This issue does not introduce automatic byte, duration, or percentage conversion.
Axis formatting
A shared value axis can use field-specific formatting only when all visible measures on that axis are compatible.
Two measures are compatible when their effective metadata has the same:
When compatible:
When incompatible:
Examples:
Do not add dual axes in this issue.
Hidden fields
A result measure with:
{ "hidden": true }must not render as a chart dataset.
Requirements:
cfg.y.Suggested message:
A Series value cannot currently be hidden through fieldConfig because it is runtime data rather than a top-level result column.
Missing-value geometry
Current chart data construction coerces empty and invalid values to zero.
For presentation fidelity, distinguish:
Do not plot missing numeric values as zero for Line and Area charts.
Recommended behavior:
nullso Chart.js creates a gap;nullor zero only according to existing documented behavior; prefernull;Interactive
noValuepresentation is deferred to #257; null points are notreachable through Chart.js's normal tooltip callbacks.
This issue may require a focused change in
buildChartData()so missing values survive until rendering.Field color
The existing Spec supports:
{ "color": "warning" }Initial support in this issue is optional.
If implemented:
If color support materially expands scope, keep it out and track it separately.
Rendering API
Extend the shared chart renderer to receive field metadata:
or an equivalent resolved metadata map.
Do not let the renderer read application state directly.
Workbench, detached view, and Dashboard must call the same path.
Files
Expected areas:
No new runtime dependency.
No saved-query migration.
Tests
Cover:
cfg.y;Non-goals
Do not include:
Acceptance criteria
noValuealone does not replace legacy valid-value tooltip formatting; interactive missing-point presentation is tracked in Chart panels: expose noValue for missing points #257.npm testpasses.npm run buildsucceeds.Definition of done
A chart authored with
panel.fieldConfigrenders polished labels and values without adding UI complexity.Simple chart structure remains configurable through compact controls, while display names, units, precision, hidden fields, and related presentation details remain available in the Spec editor.