Skip to content

Chart panels: apply field metadata to legends, tooltips, axes, and visibility #254

Description

@BorisTyshkevich

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:

unit
decimals

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:

{
  "hidden": true
}

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:

missing/NULL
zero

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:

{
  "color": "warning"
}

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

  • Chart legends use configured display names where applicable.
  • Tooltip values use configured unit and decimals.
  • Compatible shared axes use configured unit and decimals.
  • Incompatible mixed-unit axes retain generic formatting.
  • Hidden result fields are omitted from rendered datasets.
  • Hidden fields remain in the Spec and selector options.
  • Missing Line/Area values are not silently converted to zero.
  • Workbench and Dashboard share the same behavior.
  • No chart-formatting toolbar is added.
  • Advanced formatting remains Spec-authored.
  • Existing saved charts remain valid.
  • noValue alone does not replace legacy valid-value tooltip formatting; interactive missing-point presentation is tracked in Chart panels: expose noValue for missing points #257.
  • Unit tests cover metadata resolution and rendering.
  • npm test passes.
  • npm run build succeeds.
  • No new runtime dependency is added.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions