mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Moved ValueMapping logic and tests to separate files
This commit is contained in:
parent
bbb7596113
commit
a9c33ab658
@ -98,109 +98,6 @@ describe('Get thresholds formatted', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Format value with value mappings', () => {
|
|
||||||
it('should return undefined with no valuemappings', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [];
|
|
||||||
const value = '10';
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return undefined with no matching valuemappings', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
|
||||||
{ id: 1, operator: '', text: '1-9', type: MappingType.RangeToText, from: '1', to: '9' },
|
|
||||||
];
|
|
||||||
const value = '10';
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return first matching mapping with lowest id', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
|
|
||||||
{ id: 1, operator: '', text: 'tio', type: MappingType.ValueToText, value: '10' },
|
|
||||||
];
|
|
||||||
const value = '10';
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result.text).toEqual('1-20');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return if value is null and value to text mapping value is null', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
|
|
||||||
{ id: 1, operator: '', text: '<NULL>', type: MappingType.ValueToText, value: 'null' },
|
|
||||||
];
|
|
||||||
const value = null;
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result.text).toEqual('<NULL>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return if value is null and range to text mapping from and to is null', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: '<NULL>', type: MappingType.RangeToText, from: 'null', to: 'null' },
|
|
||||||
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
|
||||||
];
|
|
||||||
const value = null;
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result.text).toEqual('<NULL>');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return rangeToText mapping where value equals to', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: '1-10', type: MappingType.RangeToText, from: '1', to: '10' },
|
|
||||||
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
|
||||||
];
|
|
||||||
const value = '10';
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result.text).toEqual('1-10');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return rangeToText mapping where value equals from', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: '10-20', type: MappingType.RangeToText, from: '10', to: '20' },
|
|
||||||
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
|
||||||
];
|
|
||||||
const value = '10';
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result.text).toEqual('10-20');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return rangeToText mapping where value is between from and to', () => {
|
|
||||||
const valueMappings: ValueMapping[] = [
|
|
||||||
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
|
|
||||||
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
|
||||||
];
|
|
||||||
const value = '10';
|
|
||||||
const { instance } = setup({ valueMappings });
|
|
||||||
|
|
||||||
const result = instance.getFirstFormattedValueMapping(valueMappings, value);
|
|
||||||
|
|
||||||
expect(result.text).toEqual('1-20');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Format value', () => {
|
describe('Format value', () => {
|
||||||
it('should return if value isNaN', () => {
|
it('should return if value isNaN', () => {
|
||||||
const valueMappings: ValueMapping[] = [];
|
const valueMappings: ValueMapping[] = [];
|
||||||
|
@ -1,20 +1,10 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
import {
|
import { ValueMapping, Threshold, ThemeName, BasicGaugeColor, ThemeNames } from '../../types/panel';
|
||||||
ValueMapping,
|
|
||||||
Threshold,
|
|
||||||
ThemeName,
|
|
||||||
MappingType,
|
|
||||||
BasicGaugeColor,
|
|
||||||
ThemeNames,
|
|
||||||
ValueMap,
|
|
||||||
RangeMap,
|
|
||||||
} from '../../types/panel';
|
|
||||||
import { TimeSeriesVMs } from '../../types/series';
|
import { TimeSeriesVMs } from '../../types/series';
|
||||||
import { getValueFormat } from '../../utils/valueFormats/valueFormats';
|
import { getValueFormat } from '../../utils/valueFormats/valueFormats';
|
||||||
|
import { TimeSeriesValue, getMappedValue } from '../../utils/valueMappings';
|
||||||
type TimeSeriesValue = string | number | null;
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
decimals: number;
|
decimals: number;
|
||||||
@ -59,84 +49,6 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
addValueToTextMappingText(allValueMappings: ValueMapping[], valueToTextMapping: ValueMap, value: TimeSeriesValue) {
|
|
||||||
if (valueToTextMapping.value === undefined) {
|
|
||||||
return allValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value === null && valueToTextMapping.value && valueToTextMapping.value.toLowerCase() === 'null') {
|
|
||||||
return allValueMappings.concat(valueToTextMapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueAsNumber = parseFloat(value as string);
|
|
||||||
const valueToTextMappingAsNumber = parseFloat(valueToTextMapping.value as string);
|
|
||||||
|
|
||||||
if (isNaN(valueAsNumber) || isNaN(valueToTextMappingAsNumber)) {
|
|
||||||
return allValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valueAsNumber !== valueToTextMappingAsNumber) {
|
|
||||||
return allValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
return allValueMappings.concat(valueToTextMapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
addRangeToTextMappingText(allValueMappings: ValueMapping[], rangeToTextMapping: RangeMap, value: TimeSeriesValue) {
|
|
||||||
if (rangeToTextMapping.from === undefined || rangeToTextMapping.to === undefined || value === undefined) {
|
|
||||||
return allValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
value === null &&
|
|
||||||
rangeToTextMapping.from &&
|
|
||||||
rangeToTextMapping.to &&
|
|
||||||
rangeToTextMapping.from.toLowerCase() === 'null' &&
|
|
||||||
rangeToTextMapping.to.toLowerCase() === 'null'
|
|
||||||
) {
|
|
||||||
return allValueMappings.concat(rangeToTextMapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
const valueAsNumber = parseFloat(value as string);
|
|
||||||
const fromAsNumber = parseFloat(rangeToTextMapping.from as string);
|
|
||||||
const toAsNumber = parseFloat(rangeToTextMapping.to as string);
|
|
||||||
|
|
||||||
if (isNaN(valueAsNumber) || isNaN(fromAsNumber) || isNaN(toAsNumber)) {
|
|
||||||
return allValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valueAsNumber >= fromAsNumber && valueAsNumber <= toAsNumber) {
|
|
||||||
return allValueMappings.concat(rangeToTextMapping);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllFormattedValueMappings(valueMappings: ValueMapping[], value: TimeSeriesValue) {
|
|
||||||
const allFormattedValueMappings = valueMappings.reduce(
|
|
||||||
(allValueMappings, valueMapping) => {
|
|
||||||
if (valueMapping.type === MappingType.ValueToText) {
|
|
||||||
allValueMappings = this.addValueToTextMappingText(allValueMappings, valueMapping as ValueMap, value);
|
|
||||||
} else if (valueMapping.type === MappingType.RangeToText) {
|
|
||||||
allValueMappings = this.addRangeToTextMappingText(allValueMappings, valueMapping as RangeMap, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return allValueMappings;
|
|
||||||
},
|
|
||||||
[] as ValueMapping[]
|
|
||||||
);
|
|
||||||
|
|
||||||
allFormattedValueMappings.sort((t1, t2) => {
|
|
||||||
return t1.id - t2.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
return allFormattedValueMappings;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFirstFormattedValueMapping(valueMappings: ValueMapping[], value: TimeSeriesValue) {
|
|
||||||
return this.getAllFormattedValueMappings(valueMappings, value)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
formatValue(value: TimeSeriesValue) {
|
formatValue(value: TimeSeriesValue) {
|
||||||
const { decimals, valueMappings, prefix, suffix, unit } = this.props;
|
const { decimals, valueMappings, prefix, suffix, unit } = this.props;
|
||||||
|
|
||||||
@ -145,7 +57,7 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (valueMappings.length > 0) {
|
if (valueMappings.length > 0) {
|
||||||
const valueMappedValue = this.getFirstFormattedValueMapping(valueMappings, value);
|
const valueMappedValue = getMappedValue(valueMappings, value);
|
||||||
if (valueMappedValue) {
|
if (valueMappedValue) {
|
||||||
return `${prefix} ${valueMappedValue.text} ${suffix}`;
|
return `${prefix} ${valueMappedValue.text} ${suffix}`;
|
||||||
}
|
}
|
||||||
|
81
packages/grafana-ui/src/utils/valueMappings.test.ts
Normal file
81
packages/grafana-ui/src/utils/valueMappings.test.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { getMappedValue } from './valueMappings';
|
||||||
|
import { ValueMapping, MappingType } from '../types/panel';
|
||||||
|
|
||||||
|
describe('Format value with value mappings', () => {
|
||||||
|
it('should return undefined with no valuemappings', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [];
|
||||||
|
const value = '10';
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined with no matching valuemappings', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
||||||
|
{ id: 1, operator: '', text: '1-9', type: MappingType.RangeToText, from: '1', to: '9' },
|
||||||
|
];
|
||||||
|
const value = '10';
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return first matching mapping with lowest id', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
|
||||||
|
{ id: 1, operator: '', text: 'tio', type: MappingType.ValueToText, value: '10' },
|
||||||
|
];
|
||||||
|
const value = '10';
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value).text).toEqual('1-20');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return if value is null and value to text mapping value is null', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
|
||||||
|
{ id: 1, operator: '', text: '<NULL>', type: MappingType.ValueToText, value: 'null' },
|
||||||
|
];
|
||||||
|
const value = null;
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value).text).toEqual('<NULL>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return if value is null and range to text mapping from and to is null', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: '<NULL>', type: MappingType.RangeToText, from: 'null', to: 'null' },
|
||||||
|
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
||||||
|
];
|
||||||
|
const value = null;
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value).text).toEqual('<NULL>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return rangeToText mapping where value equals to', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: '1-10', type: MappingType.RangeToText, from: '1', to: '10' },
|
||||||
|
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
||||||
|
];
|
||||||
|
const value = '10';
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value).text).toEqual('1-10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return rangeToText mapping where value equals from', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: '10-20', type: MappingType.RangeToText, from: '10', to: '20' },
|
||||||
|
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
||||||
|
];
|
||||||
|
const value = '10';
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value).text).toEqual('10-20');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return rangeToText mapping where value is between from and to', () => {
|
||||||
|
const valueMappings: ValueMapping[] = [
|
||||||
|
{ id: 0, operator: '', text: '1-20', type: MappingType.RangeToText, from: '1', to: '20' },
|
||||||
|
{ id: 1, operator: '', text: 'elva', type: MappingType.ValueToText, value: '11' },
|
||||||
|
];
|
||||||
|
const value = '10';
|
||||||
|
|
||||||
|
expect(getMappedValue(valueMappings, value).text).toEqual('1-20');
|
||||||
|
});
|
||||||
|
});
|
89
packages/grafana-ui/src/utils/valueMappings.ts
Normal file
89
packages/grafana-ui/src/utils/valueMappings.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { ValueMapping, MappingType, ValueMap, RangeMap } from '../types';
|
||||||
|
|
||||||
|
export type TimeSeriesValue = string | number | null;
|
||||||
|
|
||||||
|
const addValueToTextMappingText = (
|
||||||
|
allValueMappings: ValueMapping[],
|
||||||
|
valueToTextMapping: ValueMap,
|
||||||
|
value: TimeSeriesValue
|
||||||
|
) => {
|
||||||
|
if (valueToTextMapping.value === undefined) {
|
||||||
|
return allValueMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === null && valueToTextMapping.value && valueToTextMapping.value.toLowerCase() === 'null') {
|
||||||
|
return allValueMappings.concat(valueToTextMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueAsNumber = parseFloat(value as string);
|
||||||
|
const valueToTextMappingAsNumber = parseFloat(valueToTextMapping.value as string);
|
||||||
|
|
||||||
|
if (isNaN(valueAsNumber) || isNaN(valueToTextMappingAsNumber)) {
|
||||||
|
return allValueMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueAsNumber !== valueToTextMappingAsNumber) {
|
||||||
|
return allValueMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allValueMappings.concat(valueToTextMapping);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addRangeToTextMappingText = (
|
||||||
|
allValueMappings: ValueMapping[],
|
||||||
|
rangeToTextMapping: RangeMap,
|
||||||
|
value: TimeSeriesValue
|
||||||
|
) => {
|
||||||
|
if (rangeToTextMapping.from === undefined || rangeToTextMapping.to === undefined || value === undefined) {
|
||||||
|
return allValueMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
value === null &&
|
||||||
|
rangeToTextMapping.from &&
|
||||||
|
rangeToTextMapping.to &&
|
||||||
|
rangeToTextMapping.from.toLowerCase() === 'null' &&
|
||||||
|
rangeToTextMapping.to.toLowerCase() === 'null'
|
||||||
|
) {
|
||||||
|
return allValueMappings.concat(rangeToTextMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueAsNumber = parseFloat(value as string);
|
||||||
|
const fromAsNumber = parseFloat(rangeToTextMapping.from as string);
|
||||||
|
const toAsNumber = parseFloat(rangeToTextMapping.to as string);
|
||||||
|
|
||||||
|
if (isNaN(valueAsNumber) || isNaN(fromAsNumber) || isNaN(toAsNumber)) {
|
||||||
|
return allValueMappings;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueAsNumber >= fromAsNumber && valueAsNumber <= toAsNumber) {
|
||||||
|
return allValueMappings.concat(rangeToTextMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allValueMappings;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAllFormattedValueMappings = (valueMappings: ValueMapping[], value: TimeSeriesValue) => {
|
||||||
|
const allFormattedValueMappings = valueMappings.reduce(
|
||||||
|
(allValueMappings, valueMapping) => {
|
||||||
|
if (valueMapping.type === MappingType.ValueToText) {
|
||||||
|
allValueMappings = addValueToTextMappingText(allValueMappings, valueMapping as ValueMap, value);
|
||||||
|
} else if (valueMapping.type === MappingType.RangeToText) {
|
||||||
|
allValueMappings = addRangeToTextMappingText(allValueMappings, valueMapping as RangeMap, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return allValueMappings;
|
||||||
|
},
|
||||||
|
[] as ValueMapping[]
|
||||||
|
);
|
||||||
|
|
||||||
|
allFormattedValueMappings.sort((t1, t2) => {
|
||||||
|
return t1.id - t2.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
return allFormattedValueMappings;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getMappedValue = (valueMappings: ValueMapping[], value: TimeSeriesValue): ValueMapping => {
|
||||||
|
return getAllFormattedValueMappings(valueMappings, value)[0];
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user