Commit f47b7230 by Dominik Prokop Committed by GitHub

Make value mappings correctly interpret numeric-like strings (#30893)

* Make value mappings corectly interprete numeric-like strings

* More tests

* Update packages/grafana-data/src/utils/valueMappings.ts

* Update packages/grafana-data/src/utils/valueMappings.ts

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>

* Fix issue detected by singlestat test

Co-authored-by: Hugo Häggmark <hugo.haggmark@grafana.com>
parent 32eb0019
import { getMappedValue } from './valueMappings'; import { getMappedValue, isNumeric } from './valueMappings';
import { ValueMapping, MappingType } from '../types'; import { ValueMapping, MappingType } from '../types';
describe('Format value with value mappings', () => { describe('Format value with value mappings', () => {
...@@ -79,6 +79,7 @@ describe('Format value with value mappings', () => { ...@@ -79,6 +79,7 @@ describe('Format value with value mappings', () => {
expect(getMappedValue(valueMappings, value).text).toEqual('1-20'); expect(getMappedValue(valueMappings, value).text).toEqual('1-20');
}); });
describe('text mapping', () => {
it('should map value text to mapping', () => { it('should map value text to mapping', () => {
const valueMappings: ValueMapping[] = [ const valueMappings: ValueMapping[] = [
{ id: 0, text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' }, { id: 0, text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
...@@ -89,4 +90,64 @@ describe('Format value with value mappings', () => { ...@@ -89,4 +90,64 @@ describe('Format value with value mappings', () => {
expect(getMappedValue(valueMappings, value).text).toEqual('ELVA'); expect(getMappedValue(valueMappings, value).text).toEqual('ELVA');
}); });
it.each`
value | expected
${'2/0/12'} | ${{ id: 1, text: 'mapped value 1', type: MappingType.ValueToText, value: '2/0/12' }}
${'2/1/12'} | ${undefined}
${'2:0'} | ${{ id: 3, text: 'mapped value 3', type: MappingType.ValueToText, value: '2:0' }}
${'2:1'} | ${undefined}
${'20whatever'} | ${{ id: 2, text: 'mapped value 2', type: MappingType.ValueToText, value: '20whatever' }}
${'20whateve'} | ${undefined}
${'20'} | ${undefined}
${'00020.4'} | ${undefined}
${'192.168.1.1'} | ${{ id: 4, text: 'mapped value ip', type: MappingType.ValueToText, value: '192.168.1.1' }}
${'192'} | ${undefined}
${'192.168'} | ${undefined}
${'192.168.1'} | ${undefined}
${'9.90'} | ${{ id: 5, text: 'OK', type: MappingType.ValueToText, value: '9.9' }}
`('numeric-like text mapping, value:${value', ({ value, expected }) => {
const valueMappings: ValueMapping[] = [
{ id: 1, text: 'mapped value 1', type: MappingType.ValueToText, value: '2/0/12' },
{ id: 2, text: 'mapped value 2', type: MappingType.ValueToText, value: '20whatever' },
{ id: 3, text: 'mapped value 3', type: MappingType.ValueToText, value: '2:0' },
{ id: 4, text: 'mapped value ip', type: MappingType.ValueToText, value: '192.168.1.1' },
{ id: 5, text: 'OK', type: MappingType.ValueToText, value: '9.9' },
];
expect(getMappedValue(valueMappings, value)).toEqual(expected);
});
});
});
describe('isNumeric', () => {
it.each`
value | expected
${123} | ${true}
${'123'} | ${true}
${' 123'} | ${true}
${' 123 '} | ${true}
${-123.4} | ${true}
${'-123.4'} | ${true}
${0.41} | ${true}
${'.41'} | ${true}
${0x12} | ${true}
${'0x12'} | ${true}
${'000123.4'} | ${true}
${2e64} | ${true}
${'2e64'} | ${true}
${1e10000} | ${true}
${'1e10000'} | ${true}
${Infinity} | ${true}
${'abc'} | ${false}
${' '} | ${false}
${null} | ${false}
${undefined} | ${false}
${NaN} | ${false}
${''} | ${false}
${{}} | ${false}
${true} | ${false}
${[]} | ${false}
`('detects numeric values', ({ value, expected }) => {
expect(isNumeric(value)).toEqual(expected);
});
}); });
...@@ -15,20 +15,23 @@ const addValueToTextMappingText = ( ...@@ -15,20 +15,23 @@ const addValueToTextMappingText = (
return allValueMappings.concat(valueToTextMapping); return allValueMappings.concat(valueToTextMapping);
} }
const valueAsNumber = parseFloat(value as string); let valueAsNumber, valueToTextMappingAsNumber;
const valueToTextMappingAsNumber = parseFloat(valueToTextMapping.value as string);
if (isNaN(valueAsNumber) || isNaN(valueToTextMappingAsNumber)) { if (isNumeric(value as string) && isNumeric(valueToTextMapping.value)) {
if (value === valueToTextMapping.value) { valueAsNumber = parseFloat(value as string);
valueToTextMappingAsNumber = parseFloat(valueToTextMapping.value as string);
if (valueAsNumber === valueToTextMappingAsNumber) {
return allValueMappings.concat(valueToTextMapping); return allValueMappings.concat(valueToTextMapping);
} }
}
if (valueAsNumber !== valueToTextMappingAsNumber) {
return allValueMappings; return allValueMappings;
} }
if (value === valueToTextMapping.value) {
return allValueMappings.concat(valueToTextMapping); return allValueMappings.concat(valueToTextMapping);
}
return allValueMappings;
}; };
const addRangeToTextMappingText = ( const addRangeToTextMappingText = (
...@@ -93,3 +96,12 @@ const isNullValueMap = (mapping: ValueMap): boolean => { ...@@ -93,3 +96,12 @@ const isNullValueMap = (mapping: ValueMap): boolean => {
} }
return mapping.value.toLowerCase() === 'null'; return mapping.value.toLowerCase() === 'null';
}; };
// Ref https://stackoverflow.com/a/42356340
export function isNumeric(num: any) {
if (num === true) {
return false;
}
return Boolean(Number(num));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment