diff --git a/packages/grafana-ui/src/types/displayValue.ts b/packages/grafana-ui/src/types/displayValue.ts index f1ca32c3c9c..475465a30f1 100644 --- a/packages/grafana-ui/src/types/displayValue.ts +++ b/packages/grafana-ui/src/types/displayValue.ts @@ -6,7 +6,9 @@ export interface DisplayValue { fontSize?: string; } +export type DecimalCount = number | null | undefined; + export interface DecimalInfo { - decimals: number; - scaledDecimals: number; + decimals: DecimalCount; + scaledDecimals: DecimalCount; } diff --git a/packages/grafana-ui/src/utils/displayValue.test.ts b/packages/grafana-ui/src/utils/displayValue.test.ts index 1849daa76d7..16fc405cfa0 100644 --- a/packages/grafana-ui/src/utils/displayValue.test.ts +++ b/packages/grafana-ui/src/utils/displayValue.test.ts @@ -158,6 +158,12 @@ describe('Format value', () => { expect(instance(value).text).toEqual('0.02'); }); + it('should use override decimals', () => { + const value = 100030303; + const instance = getDisplayProcessor({ decimals: 2, unit: 'bytes' }); + expect(instance(value).text).toEqual('95.40 MiB'); + }); + it('should return mapped value if there are matching value mappings', () => { const valueMappings: ValueMapping[] = [ { id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' }, @@ -182,5 +188,6 @@ describe('getDecimalsForValue()', () => { expect(getDecimalsForValue(20000)).toEqual({ decimals: 0, scaledDecimals: -2 }); expect(getDecimalsForValue(200000)).toEqual({ decimals: 0, scaledDecimals: -3 }); expect(getDecimalsForValue(200000000)).toEqual({ decimals: 0, scaledDecimals: -6 }); + expect(getDecimalsForValue(100, 2)).toEqual({ decimals: 2, scaledDecimals: null }); }); }); diff --git a/packages/grafana-ui/src/utils/displayValue.ts b/packages/grafana-ui/src/utils/displayValue.ts index 87fd101d3a7..12208ce0429 100644 --- a/packages/grafana-ui/src/utils/displayValue.ts +++ b/packages/grafana-ui/src/utils/displayValue.ts @@ -8,8 +8,15 @@ import { getMappedValue } from './valueMappings'; import { getColorFromHexRgbOrName } from './namedColorsPalette'; // Types -import { Threshold, ValueMapping, DecimalInfo, DisplayValue, GrafanaTheme, GrafanaThemeType } from '../types'; -import { DecimalCount } from './valueFormats/valueFormats'; +import { + Threshold, + ValueMapping, + DecimalInfo, + DisplayValue, + GrafanaTheme, + GrafanaThemeType, + DecimalCount, +} from '../types'; export type DisplayProcessor = (value: any) => DisplayValue; @@ -69,18 +76,7 @@ export function getDisplayProcessor(options?: DisplayValueOptions): DisplayProce if (!isNaN(numeric)) { if (shouldFormat && !_.isBoolean(value)) { - let decimals; - let scaledDecimals = 0; - - if (!options.decimals) { - const decimalInfo = getDecimalsForValue(value); - - decimals = decimalInfo.decimals; - scaledDecimals = decimalInfo.scaledDecimals; - } else { - decimals = options.decimals; - } - + const { decimals, scaledDecimals } = getDecimalsForValue(value, options.decimals); text = formatFunc(numeric, decimals, scaledDecimals, options.isUtc); } if (thresholds && thresholds.length > 0) { @@ -159,7 +155,12 @@ export function getColorFromThreshold(value: number, thresholds: Threshold[], th return getColorFromHexRgbOrName(thresholds[0].color, themeType); } -export function getDecimalsForValue(value: number): DecimalInfo { +export function getDecimalsForValue(value: number, decimalOverride?: DecimalCount): DecimalInfo { + if (_.isNumber(decimalOverride)) { + // It's important that scaledDecimals is null here + return { decimals: decimalOverride, scaledDecimals: null }; + } + const delta = value / 2; let dec = -Math.floor(Math.log(delta) / Math.LN10); diff --git a/packages/grafana-ui/src/utils/valueFormats/arithmeticFormatters.ts b/packages/grafana-ui/src/utils/valueFormats/arithmeticFormatters.ts index 8ff5a1ff5e7..d7044782944 100644 --- a/packages/grafana-ui/src/utils/valueFormats/arithmeticFormatters.ts +++ b/packages/grafana-ui/src/utils/valueFormats/arithmeticFormatters.ts @@ -1,4 +1,5 @@ -import { toFixed, DecimalCount } from './valueFormats'; +import { toFixed } from './valueFormats'; +import { DecimalCount } from '../../types'; export function toPercent(size: number, decimals: DecimalCount) { if (size === null) { diff --git a/packages/grafana-ui/src/utils/valueFormats/dateTimeFormatters.ts b/packages/grafana-ui/src/utils/valueFormats/dateTimeFormatters.ts index 819b73586d5..bad77191fb5 100644 --- a/packages/grafana-ui/src/utils/valueFormats/dateTimeFormatters.ts +++ b/packages/grafana-ui/src/utils/valueFormats/dateTimeFormatters.ts @@ -1,4 +1,5 @@ -import { toFixed, toFixedScaled, DecimalCount } from './valueFormats'; +import { toFixed, toFixedScaled } from './valueFormats'; +import { DecimalCount } from '../../types'; import moment from 'moment'; interface IntervalsInSeconds { diff --git a/packages/grafana-ui/src/utils/valueFormats/symbolFormatters.ts b/packages/grafana-ui/src/utils/valueFormats/symbolFormatters.ts index da8198daf5a..6c1a9682c74 100644 --- a/packages/grafana-ui/src/utils/valueFormats/symbolFormatters.ts +++ b/packages/grafana-ui/src/utils/valueFormats/symbolFormatters.ts @@ -1,4 +1,5 @@ -import { scaledUnits, DecimalCount } from './valueFormats'; +import { scaledUnits } from './valueFormats'; +import { DecimalCount } from '../../types'; export function currency(symbol: string) { const units = ['', 'K', 'M', 'B', 'T']; diff --git a/packages/grafana-ui/src/utils/valueFormats/valueFormats.test.ts b/packages/grafana-ui/src/utils/valueFormats/valueFormats.test.ts new file mode 100644 index 00000000000..a7ab2b919b8 --- /dev/null +++ b/packages/grafana-ui/src/utils/valueFormats/valueFormats.test.ts @@ -0,0 +1,29 @@ +import { toFixed, getValueFormat } from './valueFormats'; + +describe('kbn.toFixed and negative decimals', () => { + it('should treat as zero decimals', () => { + const str = toFixed(186.123, -2); + expect(str).toBe('186'); + }); +}); + +describe('kbn ms format when scaled decimals is null do not use it', () => { + it('should use specified decimals', () => { + const str = getValueFormat('ms')(10000086.123, 1, null); + expect(str).toBe('2.8 hour'); + }); +}); + +describe('kbn kbytes format when scaled decimals is null do not use it', () => { + it('should use specified decimals', () => { + const str = getValueFormat('kbytes')(10000000, 3, null); + expect(str).toBe('9.537 GiB'); + }); +}); + +describe('kbn deckbytes format when scaled decimals is null do not use it', () => { + it('should use specified decimals', () => { + const str = getValueFormat('deckbytes')(10000000, 3, null); + expect(str).toBe('10.000 GB'); + }); +}); diff --git a/packages/grafana-ui/src/utils/valueFormats/valueFormats.ts b/packages/grafana-ui/src/utils/valueFormats/valueFormats.ts index d626a241a79..25e8f0ce2ac 100644 --- a/packages/grafana-ui/src/utils/valueFormats/valueFormats.ts +++ b/packages/grafana-ui/src/utils/valueFormats/valueFormats.ts @@ -1,6 +1,5 @@ import { getCategories } from './categories'; - -export type DecimalCount = number | null | undefined; +import { DecimalCount } from '../../types'; export type ValueFormatter = ( value: number,