Feature/chart widget options config#1596
Conversation
Extend chart widget_options with multi-series support, custom colors, units/number formatting, stacking, horizontal bars, legend/axis config, data labels, sorting, and data limiting — all backward compatible with existing saved queries. - Add TypeScript interfaces for chart config (ChartWidgetOptions, etc.) - Create shared chart-config.helper.ts for Chart.js config building - Refactor chart-widget and chart-preview to use shared helper - Add full configuration UI to chart-edit with series management, display options, units/formatting, axis config, and data options - Update tests to match new seriesList-based API Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use the existing `convert` dependency to auto-format chart values into the best human-readable unit (e.g. 1500000 bytes → 1.5 MB, 3600000 ms → 1 h). Adds a unit mode selector in chart-edit: - None: no unit formatting - Custom text: manual prefix/suffix ($, %, EUR) - Auto-convert: pick a source unit, values auto-scale Supports time, data, length, mass, temperature, frequency, power, energy, pressure, and volume unit families via grouped dropdown. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Always set indexAxis explicitly ('y' for horizontal, 'x' for vertical)
so Chart.js doesn't cache the previous value when toggling off.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Series color and custom palette now use <input type="color"> pickers instead of text inputs. Added rgba-to-hex conversion for display, and changed palette from a textarea to a visual array of color swatches with add/remove controls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…options-config # Conflicts: # frontend/src/app/components/charts/chart-edit/chart-edit.component.html
There was a problem hiding this comment.
Pull request overview
Adds a richer, structured configuration model for chart widgets (series, formatting, axes, legend, sorting, palette) and centralizes Chart.js data/options building so dashboards and chart previews render consistently.
Changes:
- Introduces typed chart widget option schemas (
ChartWidgetOptions,ChartSeriesConfig, etc.) for saved queries. - Adds
chart-config.helper.tsto build Chart.js data/options, formatting, sorting/limit, and a custom data-labels plugin. - Updates chart widget renderer, chart preview, and chart edit UI to use the new options model (including multi-series + advanced settings UI).
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/app/models/saved-query.ts | Defines structured chart widget options/series/formatting types. |
| frontend/src/app/lib/chart-config.helper.ts | Centralized chart data/options building + formatting + datalabels plugin. |
| frontend/src/app/components/dashboards/widget-renderers/chart-widget/chart-widget.component.ts | Switches renderer to helper-based chart building and adds plugins support. |
| frontend/src/app/components/dashboards/widget-renderers/chart-widget/chart-widget.component.html | Passes computed plugins into baseChart. |
| frontend/src/app/components/charts/chart-preview/chart-preview.component.ts | Uses helper-based chart building; supports new widgetOptions input. |
| frontend/src/app/components/charts/chart-preview/chart-preview.component.html | Adds plugins binding; updates to new control-flow syntax. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.ts | Adds UI state/signals for new chart options + series/palette management; saves structured options. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.spec.ts | Updates tests for series-based configuration and new payload shape. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.html | Major UI expansion: series editor + advanced options accordion + palette editor. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.css | Styling for new series/advanced options/palette UI. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ): ChartData<ChartJsType> | null { | ||
| if (!rawData.length) return null; | ||
|
|
||
| const palette = options.color_palette ?? DEFAULT_COLOR_PALETTE; |
There was a problem hiding this comment.
options.color_palette ?? DEFAULT_COLOR_PALETTE will treat an empty array as a valid palette, which later produces undefined colors due to modulo by palette.length (0). Consider falling back to DEFAULT_COLOR_PALETTE when color_palette is missing or empty (e.g., check .length).
| const palette = options.color_palette ?? DEFAULT_COLOR_PALETTE; | |
| const palette = | |
| options.color_palette && options.color_palette.length | |
| ? options.color_palette | |
| : DEFAULT_COLOR_PALETTE; |
| : typeof raw === 'object' && raw !== null | ||
| ? ((raw as { y?: number }).y ?? 0) | ||
| : 0; | ||
| const label = context.dataset.label ?? ''; |
There was a problem hiding this comment.
Tooltip label callback uses context.dataset.label for all chart types. For pie/doughnut/polarArea this loses the per-slice label (available on context.label), so every slice tooltip will show the same label. Adjust the callback to include the slice label for pie-type charts.
| const label = context.dataset.label ?? ''; | |
| const datasetLabel = context.dataset.label ?? ''; | |
| const sliceLabel = context.label ?? ''; | |
| let label: string; | |
| if (isPieType) { | |
| if (datasetLabel && sliceLabel) { | |
| label = `${datasetLabel} - ${sliceLabel}`; | |
| } else { | |
| label = datasetLabel || sliceLabel; | |
| } | |
| } else { | |
| label = datasetLabel; | |
| } |
| const value = typeof tickValue === 'number' ? tickValue : parseFloat(tickValue); | ||
| return formatChartValue(value, globalUnits, globalFormat); |
There was a problem hiding this comment.
Tick callback parses string ticks with parseFloat(tickValue) but doesn't handle NaN (e.g., unexpected tick strings), which can render "NaN" on the axis. Consider using the existing numeric-extraction helper (or || 0) before calling formatChartValue.
| const value = typeof tickValue === 'number' ? tickValue : parseFloat(tickValue); | |
| return formatChartValue(value, globalUnits, globalFormat); | |
| const parsed = typeof tickValue === 'number' ? tickValue : parseFloat(tickValue); | |
| const safeValue = Number.isNaN(parsed) ? 0 : parsed; | |
| return formatChartValue(safeValue, globalUnits, globalFormat); |
| export function buildChartData( | ||
| rawData: Record<string, unknown>[], | ||
| chartType: ChartType, | ||
| options: ChartWidgetOptions, | ||
| ): ChartData<ChartJsType> | null { | ||
| if (!rawData.length) return null; |
There was a problem hiding this comment.
This helper adds a lot of new chart behavior (unit conversion, series handling, sorting/limit, tooltip/tick formatting), but there are no unit tests for it. Since frontend/src/app/lib already has *.spec.ts coverage for other helpers, consider adding a chart-config.helper.spec.ts to cover key option combinations across chart types.
| ChartLegendConfig, | ||
| ChartNumberFormatConfig, | ||
| ChartSeriesConfig, | ||
| ChartType, | ||
| ChartUnitConfig, |
There was a problem hiding this comment.
ChartLegendConfig and ChartUnitConfig are imported here but never referenced in the file. Removing unused imports will avoid lint noise and keep the import list accurate.
| ChartLegendConfig, | |
| ChartNumberFormatConfig, | |
| ChartSeriesConfig, | |
| ChartType, | |
| ChartUnitConfig, | |
| ChartNumberFormatConfig, | |
| ChartSeriesConfig, | |
| ChartType, |
Move .actions div outside .chart-edit-page so it sits directly in .chart-edit-main, matching the main branch layout where the sticky bottom bar spans the full panel width. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Allow users to pick a categorical column that automatically creates one dataset per unique value (pivot operation), instead of manually adding series. Also export DEFAULT_COLOR_PALETTE and add a "Load defaults" button in the color palette section. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
No description provided.