From 31a806281e5235dc286b5a054fd097313ffb4256 Mon Sep 17 00:00:00 2001 From: Paul Marbach Date: Thu, 8 Jan 2026 11:00:24 -0500 Subject: [PATCH] fix off-by-one, update tests --- .../components/RadialGauge/RadialGauge.tsx | 4 +-- .../src/components/RadialGauge/utils.test.ts | 32 ++++++++++++++++++- .../src/components/RadialGauge/utils.ts | 4 ++- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx index 7fc3ae4a383..b6518048c27 100644 --- a/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx +++ b/packages/grafana-ui/src/components/RadialGauge/RadialGauge.tsx @@ -96,7 +96,7 @@ export function RadialGauge(props: RadialGaugeProps) { roundedBars = true, thresholdsBar = false, showScaleLabels = false, - neutral: rawNeutral, + neutral, endpointMarker, onClick, values, @@ -119,8 +119,6 @@ export function RadialGauge(props: RadialGaugeProps) { for (let barIndex = 0; barIndex < values.length; barIndex++) { const displayValue = values[barIndex]; - const [min, max] = getFieldConfigMinMax(displayValue); - const neutral = typeof rawNeutral === 'number' ? Math.min(Math.max(min, rawNeutral), max) : undefined; const { startValueAngle, endValueAngle, angleRange } = getValueAngleForValue( displayValue, startAngle, diff --git a/packages/grafana-ui/src/components/RadialGauge/utils.test.ts b/packages/grafana-ui/src/components/RadialGauge/utils.test.ts index ccb15ca63ca..90def005d3f 100644 --- a/packages/grafana-ui/src/components/RadialGauge/utils.test.ts +++ b/packages/grafana-ui/src/components/RadialGauge/utils.test.ts @@ -283,7 +283,37 @@ describe('RadialGauge utils', () => { expect(result.endValueAngle).toBe(240); }); - // TODO add tests for neutral handling once implemented + it('should handle neutral values', () => { + const fieldDisplay = createFieldDisplay(75, 0, 100); + const result = getValueAngleForValue(fieldDisplay, 0, 360, 50); + + expect(result.startValueAngle).toBe(180); // Neutral at 50% of 360° + expect(result.endValueAngle).toBe(90); // 75% - 50% = 25% of 360° + }); + + it('should handle neutral values equal to value', () => { + const fieldDisplay = createFieldDisplay(50, 0, 100); + const result = getValueAngleForValue(fieldDisplay, 0, 360, 50); + + expect(result.startValueAngle).toBe(180); // Neutral at 50% of 360° + expect(result.endValueAngle).toBe(0); // No difference + }); + + it('should handle neutral values greater than value', () => { + const fieldDisplay = createFieldDisplay(25, 0, 100); + const result = getValueAngleForValue(fieldDisplay, 0, 360, 150); + + expect(result.startValueAngle).toBe(90); + expect(result.endValueAngle).toBe(270); // remaining angle to 360 + }); + + it('should handle neutral values below range', () => { + const fieldDisplay = createFieldDisplay(25, 0, 100); + const result = getValueAngleForValue(fieldDisplay, 0, 360, -50); + + expect(result.startValueAngle).toBe(0); + expect(result.endValueAngle).toBe(90); + }); }); describe('drawRadialArcPath', () => { diff --git a/packages/grafana-ui/src/components/RadialGauge/utils.ts b/packages/grafana-ui/src/components/RadialGauge/utils.ts index b2cef2b21ba..54a15d3fae4 100644 --- a/packages/grafana-ui/src/components/RadialGauge/utils.ts +++ b/packages/grafana-ui/src/components/RadialGauge/utils.ts @@ -39,7 +39,9 @@ export function getValueAngleForValue( let startValueAngle = 0; if (typeof neutral === 'number') { - const neutralAngle = getValuePercentageForValue(fieldDisplay, neutral) * angleRange; + const [min, max] = getFieldConfigMinMax(fieldDisplay); + const clampedNeutral = Math.min(Math.max(min, neutral), max); + const neutralAngle = getValuePercentageForValue(fieldDisplay, clampedNeutral) * angleRange; if (neutralAngle <= valueAngle) { startValueAngle = neutralAngle; endValueAngle = valueAngle - neutralAngle;