Add field selectors for charge, load, and state metrics

Field Mapping options (new category at top of editor):
- Charge field: pick which numeric field drives the battery level
  (falls back to first number field if unset)
- Enable load metric: toggle + field picker for a load/power draw
  percentage, displayed as a themed semi-circular gauge arc beside
  the battery (green < 50%, amber 50-80%, red > 80%)
- Enable state field: toggle + field picker + user-defined values
  for charging/discharging so the panel uses an explicit data field
  rather than computing state from the rate of change

Visual integration:
- Load gauge renders in a card with the battery, scales responsively,
  and collapses to a compact text line in small panels
- State field drives the status badge, gradient direction, and
  charging animation (overrides computed rate when enabled)
- All new options use showIf for conditional visibility in the editor

Also fixed deprecation warnings by replacing .toArray() with
Array.from() for Grafana 12+ compatibility.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Andy Dixon
2026-04-24 13:15:21 +01:00
co-authored by Copilot
parent 942a390248
commit da80da71d1
3 changed files with 322 additions and 62 deletions
+69
View File
@@ -4,6 +4,75 @@ import { ChargeVizOptions } from './types';
export const plugin = new PanelPlugin<ChargeVizOptions>(ChargeVizPanel).setPanelOptions(
(builder) => {
// -- Field Mapping category (top) --
builder.addFieldNamePicker({
path: 'chargeField',
name: 'Charge field',
category: ['Field Mapping'],
description: 'Numeric field that represents battery charge (0–100%). If blank, the first number field is used.',
settings: {
filter: (f) => f.type === 'number',
noFieldsMessage: 'No numeric fields found',
},
});
builder.addBooleanSwitch({
path: 'enableLoad',
name: 'Enable load metric',
defaultValue: false,
category: ['Field Mapping'],
description: 'Show a second metric representing current load / power draw.',
});
builder.addFieldNamePicker({
path: 'loadField',
name: 'Load field',
category: ['Field Mapping'],
description: 'Numeric field for load percentage (0–100%).',
settings: {
filter: (f) => f.type === 'number',
noFieldsMessage: 'No numeric fields found',
},
showIf: (opts) => opts.enableLoad === true,
});
builder.addBooleanSwitch({
path: 'enableStateField',
name: 'Enable state field',
defaultValue: false,
category: ['Field Mapping'],
description: 'Use a field from the data to determine charging / discharging state instead of computing it from the rate.',
});
builder.addFieldNamePicker({
path: 'stateField',
name: 'State field',
category: ['Field Mapping'],
description: 'String or numeric field whose value indicates the battery state.',
settings: {
noFieldsMessage: 'No fields found',
},
showIf: (opts) => opts.enableStateField === true,
});
builder.addTextInput({
path: 'stateChargingValue',
name: 'Charging value',
defaultValue: 'charging',
category: ['Field Mapping'],
description: 'Value in the state field that means "charging" (case-insensitive).',
showIf: (opts) => opts.enableStateField === true,
});
builder.addTextInput({
path: 'stateDischargingValue',
name: 'Discharging value',
defaultValue: 'discharging',
category: ['Field Mapping'],
description: 'Value in the state field that means "discharging" (case-insensitive).',
showIf: (opts) => opts.enableStateField === true,
});
// -- Colours category --
builder.addColorPicker({
path: 'lowColour',