From 3a68409e5d102ca77d3c2cbf4bcfea382d2bc826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 27 May 2021 09:29:22 +0200 Subject: [PATCH] Plugins: Adds back getMappedValue to @grafana/data (#34746) * Plugins: Adds back getMappedValue to @grafana/data * Chore: fixes doc errors * Tests: fixes snapshot * Tests: dummy change to restart Drone * Tests: tries to fix snapshot --- packages/grafana-data/src/utils/index.ts | 10 + .../grafana-data/src/utils/valueMappings.ts | 205 +- .../SingleStatShared/SingleStatBaseOptions.ts | 54 +- public/app/features/explore/Wrapper.test.tsx | 1 - .../__snapshots__/Wrapper.test.tsx.snap | 3075 ----------------- 5 files changed, 225 insertions(+), 3120 deletions(-) delete mode 100644 public/app/features/explore/__snapshots__/Wrapper.test.tsx.snap diff --git a/packages/grafana-data/src/utils/index.ts b/packages/grafana-data/src/utils/index.ts index 7ae5541dcce..1c7a9f001c7 100644 --- a/packages/grafana-data/src/utils/index.ts +++ b/packages/grafana-data/src/utils/index.ts @@ -1,4 +1,5 @@ import * as arrayUtils from './arrayUtils'; + export * from './Registry'; export * from './datasource'; export * from './deprecationWarning'; @@ -21,3 +22,12 @@ export { DocsId } from './docs'; export { makeClassES5Compatible } from './makeClassES5Compatible'; export { anyToNumber } from './anyToNumber'; export { withLoadingIndicator, WithLoadingIndicatorOptions } from './withLoadingIndicator'; +export { + getMappedValue, + convertOldAngularValueMappings, + LegacyValueMapping, + LegacyValueMap, + LegacyRangeMap, + LegacyBaseMap, + LegacyMappingType, +} from './valueMappings'; diff --git a/packages/grafana-data/src/utils/valueMappings.ts b/packages/grafana-data/src/utils/valueMappings.ts index 35f56dd1f9c..61ef4403692 100644 --- a/packages/grafana-data/src/utils/valueMappings.ts +++ b/packages/grafana-data/src/utils/valueMappings.ts @@ -1,4 +1,5 @@ -import { ValueMapping, MappingType, ValueMappingResult, SpecialValueMatch } from '../types'; +import { MappingType, SpecialValueMatch, ThresholdsConfig, ValueMap, ValueMapping, ValueMappingResult } from '../types'; +import { getActiveThreshold } from '../field'; export function getValueMappingResult(valueMappings: ValueMapping[], value: any): ValueMappingResult | null { for (const vm of valueMappings) { @@ -86,3 +87,205 @@ export function getValueMappingResult(valueMappings: ValueMapping[], value: any) export function isNumeric(num: any) { return (typeof num === 'number' || (typeof num === 'string' && num.trim() !== '')) && !isNaN(num as number); } + +/** + * @deprecated use MappingType instead + * @internal + */ +export enum LegacyMappingType { + ValueToText = 1, + RangeToText = 2, +} + +/** + * @deprecated use MappingType instead + * @internal + */ +export interface LegacyBaseMap { + id: number; // this could/should just be the array index + text: string; // the final display value + type: LegacyMappingType; +} + +/** + * @deprecated use ValueMapping instead + * @internal + */ +export type LegacyValueMapping = LegacyValueMap | LegacyRangeMap; + +/** + * @deprecated use ValueMap instead + * @internal + */ +export interface LegacyValueMap extends LegacyBaseMap { + value: string; +} + +/** + * @deprecated use RangeMap instead + * @internal + */ +export interface LegacyRangeMap extends LegacyBaseMap { + from: string; + to: string; +} + +/** + * @deprecated use getValueMappingResult instead + * @internal + */ +export function getMappedValue(valueMappings: LegacyValueMapping[], value: any): LegacyValueMapping { + const emptyResult = { type: LegacyMappingType.ValueToText, value: '', text: '', from: '', to: '', id: 0 }; + if (!valueMappings?.length) { + return emptyResult; + } + + const upgraded: ValueMapping[] = []; + for (const vm of valueMappings) { + if (isValueMapping(vm)) { + upgraded.push(vm); + continue; + } + upgraded.push(upgradeOldAngularValueMapping(vm)); + } + + if (!upgraded?.length) { + return emptyResult; + } + + const result = getValueMappingResult(upgraded, value); + if (!result) { + return emptyResult; + } + + return { + type: LegacyMappingType.ValueToText, + value: result.text, + text: result.text ?? '', + from: '', + to: '', + id: result.index ?? 0, + }; +} + +/** + * @alpha + * Converts the old Angular value mappings to new react style + */ +export function convertOldAngularValueMappings(panel: any): ValueMapping[] { + const mappings: ValueMapping[] = []; + + // Guess the right type based on options + let mappingType = panel.mappingType; + if (!panel.mappingType) { + if (panel.valueMaps && panel.valueMaps.length) { + mappingType = 1; + } else if (panel.rangeMaps && panel.rangeMaps.length) { + mappingType = 2; + } + } + + if (mappingType === 1) { + for (let i = 0; i < panel.valueMaps.length; i++) { + const map = panel.valueMaps[i]; + mappings.push( + upgradeOldAngularValueMapping( + { + ...map, + id: i, // used for order + type: MappingType.ValueToText, + }, + panel.fieldConfig?.defaults?.thresholds + ) + ); + } + } else if (mappingType === 2) { + for (let i = 0; i < panel.rangeMaps.length; i++) { + const map = panel.rangeMaps[i]; + mappings.push( + upgradeOldAngularValueMapping( + { + ...map, + id: i, // used for order + type: MappingType.RangeToText, + }, + panel.fieldConfig?.defaults?.thresholds + ) + ); + } + } + + return mappings; +} + +function upgradeOldAngularValueMapping(old: any, thresholds?: ThresholdsConfig): ValueMapping { + const valueMaps: ValueMap = { type: MappingType.ValueToText, options: {} }; + const newMappings: ValueMapping[] = []; + + // Use the color we would have picked from thesholds + let color: string | undefined = undefined; + const numeric = parseFloat(old.text); + if (thresholds && !isNaN(numeric)) { + const level = getActiveThreshold(numeric, thresholds.steps); + if (level && level.color) { + color = level.color; + } + } + + switch (old.type) { + case LegacyMappingType.ValueToText: + case MappingType.ValueToText: + if (old.value != null) { + if (old.value === 'null') { + newMappings.push({ + type: MappingType.SpecialValue, + options: { + match: SpecialValueMatch.Null, + result: { text: old.text, color }, + }, + }); + } else { + valueMaps.options[String(old.value)] = { + text: old.text, + color, + }; + } + } + break; + case LegacyMappingType.RangeToText: + case MappingType.RangeToText: + if (old.from === 'null' || old.to === 'null') { + newMappings.push({ + type: MappingType.SpecialValue, + options: { + match: SpecialValueMatch.Null, + result: { text: old.text, color }, + }, + }); + } else { + newMappings.push({ + type: MappingType.RangeToText, + options: { + from: +old.from, + to: +old.to, + result: { text: old.text, color }, + }, + }); + } + break; + } + + if (Object.keys(valueMaps.options).length > 0) { + newMappings.unshift(valueMaps); + } + + return newMappings[0]; +} + +function isValueMapping(map: any): map is ValueMapping { + if (!map) { + return false; + } + + return map.hasOwnProperty('options') && typeof map.options === 'object'; +} diff --git a/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts b/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts index 039c33b9f3c..014b03ce607 100644 --- a/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts +++ b/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts @@ -1,20 +1,20 @@ import { cloneDeep, isNumber, omit } from 'lodash'; import { - fieldReducers, - Threshold, - sortThresholds, + convertOldAngularValueMappings, + FieldColorModeId, FieldConfig, - ReducerID, - ValueMapping, - MappingType, - VizOrientation, + fieldReducers, PanelModel, ReduceDataOptions, - ThresholdsMode, + ReducerID, + sortThresholds, + Threshold, ThresholdsConfig, + ThresholdsMode, validateFieldConfig, - FieldColorModeId, + ValueMapping, + VizOrientation, } from '@grafana/data'; import { OptionsWithTextFormatting } from '../../options'; @@ -325,41 +325,9 @@ export function migrateOldThresholds(thresholds?: any[]): Threshold[] | undefine } /** + * @deprecated use convertOldAngularValueMappings instead * Convert the angular single stat mapping to new react style */ export function convertOldAngularValueMapping(panel: any): ValueMapping[] { - const mappings: ValueMapping[] = []; - - // Guess the right type based on options - let mappingType = panel.mappingType; - if (!panel.mappingType) { - if (panel.valueMaps && panel.valueMaps.length) { - mappingType = 1; - } else if (panel.rangeMaps && panel.rangeMaps.length) { - mappingType = 2; - } - } - - // check value to text mappings if its enabled - if (mappingType === 1) { - for (let i = 0; i < panel.valueMaps.length; i++) { - const map = panel.valueMaps[i]; - mappings.push({ - ...map, - id: i, // used for order - type: MappingType.ValueToText, - }); - } - } else if (mappingType === 2) { - for (let i = 0; i < panel.rangeMaps.length; i++) { - const map = panel.rangeMaps[i]; - mappings.push({ - ...map, - id: i, // used for order - type: MappingType.RangeToText, - }); - } - } - - return mappings; + return convertOldAngularValueMappings(panel); } diff --git a/public/app/features/explore/Wrapper.test.tsx b/public/app/features/explore/Wrapper.test.tsx index ebf3ff2d5fd..1af45e90784 100644 --- a/public/app/features/explore/Wrapper.test.tsx +++ b/public/app/features/explore/Wrapper.test.tsx @@ -256,7 +256,6 @@ describe('Wrapper', () => { it('changes the document title of the explore page', async () => { setup({ datasources: [] }); - await waitFor(() => expect(document.querySelector('head')).toMatchSnapshot()); await waitFor(() => expect(document.title).toEqual('Explore - Grafana')); }); }); diff --git a/public/app/features/explore/__snapshots__/Wrapper.test.tsx.snap b/public/app/features/explore/__snapshots__/Wrapper.test.tsx.snap deleted file mode 100644 index ed0a561d3cf..00000000000 --- a/public/app/features/explore/__snapshots__/Wrapper.test.tsx.snap +++ /dev/null @@ -1,3075 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Wrapper changes the document title of the explore page 1`] = ` - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -`;