diff --git a/webapp/src/components/PanelChart.tsx b/webapp/src/components/PanelChart.tsx index 78b34ab..315f227 100644 --- a/webapp/src/components/PanelChart.tsx +++ b/webapp/src/components/PanelChart.tsx @@ -25,6 +25,22 @@ export function seriesLabel(labels: Record): string { // Fixed, small categorical palette to avoid a colour-scale dependency; cycles if there are more series than colours. const COLORS = ['#38bdf8', '#f472b6', '#a78bfa', '#4ade80', '#fbbf24', '#fb7185', '#2dd4bf', '#f97316'] +// One less than the palette size: above this many series, keep the top MAX_KEPT_SERIES (by value) and squash the +// rest into a single "Other" bucket, so the squashed range never exceeds COLORS.length and never repeats a colour. +const MAX_KEPT_SERIES = COLORS.length - 1 + +// Sorts rows by value descending and, if there are more than MAX_KEPT_SERIES, keeps the top MAX_KEPT_SERIES and +// collapses the remainder into a single "Other" row summing their values. Below the threshold, rows are returned +// unchanged so panels with few series keep their existing bar/slice order and colour assignment. +function squashRows(rows: { name: string; value: number }[]): { name: string; value: number }[] { + if (rows.length <= MAX_KEPT_SERIES) return rows + const sorted = [...rows].sort((a, b) => b.value - a.value) + const kept = sorted.slice(0, MAX_KEPT_SERIES) + const rest = sorted.slice(MAX_KEPT_SERIES) + const otherValue = rest.reduce((sum, r) => sum + r.value, 0) + return [...kept, { name: `Other (${rest.length})`, value: otherValue }] +} + // Merges series into one row-per-timestamp dataset (recharts wants a single array keyed by series name); a timestamp missing from a series is left undefined there, which recharts skips when drawing that line. function toLineData(series: PromqlSeries[]): { rows: Record[]; keys: string[] } { const keys = series.map((s) => seriesLabel(s.labels)) @@ -101,7 +117,7 @@ export function PanelChart({ series, chartType }: { series: PromqlSeries[]; char } if (chartType === 'bar') { - const rows = series.map((s) => ({ name: seriesLabel(s.labels), value: latestValue(s) })) + const rows = squashRows(series.map((s) => ({ name: seriesLabel(s.labels), value: latestValue(s) }))) return ( @@ -119,7 +135,7 @@ export function PanelChart({ series, chartType }: { series: PromqlSeries[]; char ) } - const rows = series.map((s) => ({ name: seriesLabel(s.labels), value: sumValue(s) })) + const rows = squashRows(series.map((s) => ({ name: seriesLabel(s.labels), value: sumValue(s) }))) const total = rows.reduce((sum, r) => sum + r.value, 0) if (total === 0) { return
No non-zero values in range.