Alerting: Improve displaying small numbers in query preview (#103439)

* Improve rendering of small numbers in the query preview

* Use getSeriesValue in Expression component
This commit is contained in:
Konrad Lalik
2025-04-04 15:30:24 +02:00
committed by GitHub
parent 06c83f7d4d
commit 9d82186885
3 changed files with 51 additions and 16 deletions
@@ -35,7 +35,7 @@ import { Spacer } from '../Spacer';
import { AlertStateTag } from '../rules/AlertStateTag';
import { ExpressionStatusIndicator } from './ExpressionStatusIndicator';
import { formatLabels, getSeriesLabels, getSeriesName, getSeriesValue, isEmptySeries } from './util';
import { formatLabels, formatSeriesValue, getSeriesLabels, getSeriesName, getSeriesValue, isEmptySeries } from './util';
interface ExpressionProps {
isAlertCondition?: boolean;
@@ -438,7 +438,7 @@ function FrameRow({ frame, index, isAlertCondition, isRecordingRule }: FrameProp
)}
</Text>
</div>
<div className={styles.expression.resultValue}>{value}</div>
<div className={styles.expression.resultValue}>{formatSeriesValue(value)}</div>
{shouldRenderSumary && (
<>
{showFiring && <AlertStateTag state={PromAlertingRuleState.Firing} size="sm" />}
@@ -8,6 +8,7 @@ import {
decodeGrafanaNamespace,
encodeGrafanaNamespace,
formatLabels,
formatSeriesValue,
getSeriesLabels,
getSeriesName,
getSeriesValue,
@@ -24,10 +25,6 @@ const DATA_FRAME: DataFrame = toDataFrame({
fields: [{ name: 'value', type: FieldType.number, values: [1, 2, 3] }],
});
const DATA_FRAME_LARGE_DECIMAL: DataFrame = toDataFrame({
fields: [{ name: 'value', type: FieldType.number, values: [1.23456789] }],
});
const DATA_FRAME_WITH_LABELS: DataFrame = toDataFrame({
fields: [{ name: 'value', type: FieldType.number, values: [1, 2, 3], labels: { __name__: 'my-series', foo: 'bar' } }],
});
@@ -222,10 +219,6 @@ describe('getSeriesValue', () => {
const name = getSeriesValue(DATA_FRAME);
expect(name).toBe(1);
});
it('should round values', () => {
expect(getSeriesValue(DATA_FRAME_LARGE_DECIMAL)).toBe(1.23457);
});
});
describe('getSeriesLabels', () => {
@@ -237,3 +230,35 @@ describe('getSeriesLabels', () => {
expect(getSeriesLabels(EMPTY_FRAME)).toStrictEqual({});
});
});
describe('formatSeriesValue', () => {
it('should convert non-numeric values to strings', () => {
expect(formatSeriesValue('string value')).toBe('string value');
expect(formatSeriesValue(null)).toBe('null');
expect(formatSeriesValue(undefined)).toBe('undefined');
expect(formatSeriesValue({})).toBe('[object Object]');
});
it('should return 5 significant digits in absolutely smaller than 1', () => {
expect(formatSeriesValue(0.00005123)).toBe('0.00005123');
expect(formatSeriesValue(0.7894)).toBe('0.7894');
expect(formatSeriesValue(-0.000051237676767)).toBe('-0.000051238');
expect(formatSeriesValue(-0.25)).toBe('-0.25');
});
it('should use standard notation for numbers absolutely larger than 1', () => {
expect(formatSeriesValue(1.0001)).toBe('1.0001');
expect(formatSeriesValue(1.234)).toBe('1.234');
expect(formatSeriesValue(76767345.9876)).toBe('76767345.9876');
});
it('should round regular numbers to 5 decimal places', () => {
expect(formatSeriesValue(1.23456789)).toBe('1.23457');
expect(formatSeriesValue(0.10000001)).toBe('0.1');
expect(formatSeriesValue(-42.98765432)).toBe('-42.98765');
});
it('should handle zero correctly', () => {
expect(formatSeriesValue(0)).toBe('0');
});
});
@@ -15,20 +15,29 @@ import { isCloudRulesSource } from '../../utils/datasource';
*/
const getSeriesName = (frame: DataFrame): string | undefined => {
const firstField = frame.fields[0];
const firstField = frame.fields.at(0);
const displayNameFromDS = firstField?.config?.displayNameFromDS;
return displayNameFromDS ?? frame.name ?? firstField?.labels?.__name__;
};
const getSeriesValue = (frame: DataFrame) => {
const value = frame.fields[0]?.values[0];
return frame.fields.at(0)?.values.at(0);
};
if (Number.isFinite(value)) {
return roundDecimals(value, 5);
const smallNumberFormatter = new Intl.NumberFormat(undefined, {
maximumSignificantDigits: 5,
});
const formatSeriesValue = (value: unknown): string => {
if (Number.isFinite(value) && typeof value === 'number') {
const absValue = Math.abs(value);
if (absValue < 1) {
return smallNumberFormatter.format(value);
}
return roundDecimals(value, 5).toString(10);
}
return value;
return String(value);
};
const getSeriesLabels = (frame: DataFrame): Record<string, string> => {
@@ -103,5 +112,6 @@ export {
getSeriesLabels,
getSeriesName,
getSeriesValue,
formatSeriesValue,
isEmptySeries,
};