Commit 541981c3 by Torkel Ödegaard Committed by GitHub

Gauge/BarGauge: Rewrite of how migrations are applied (#18375)

parent 25142090
......@@ -44,7 +44,7 @@
"nullPointMode": "null",
"options-gauge": {
"baseColor": "#299c46",
"decimals": "2",
"decimals": 2,
"maxValue": 100,
"minValue": 0,
"options": {
......@@ -111,7 +111,7 @@
"nullPointMode": "null",
"options-gauge": {
"baseColor": "#299c46",
"decimals": "",
"decimals": null,
"maxValue": 100,
"minValue": 0,
"options": {
......@@ -178,7 +178,7 @@
"nullPointMode": "null",
"options-gauge": {
"baseColor": "#299c46",
"decimals": "",
"decimals": null,
"maxValue": 100,
"minValue": 0,
"options": {
......
......@@ -104,7 +104,7 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
name: 'Last (not null)',
description: 'Last non-null value',
standard: true,
alias: 'current',
aliasIds: ['current'],
reduce: calculateLastNotNull,
},
{
......@@ -124,14 +124,14 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
},
{ id: ReducerID.min, name: 'Min', description: 'Minimum Value', standard: true },
{ id: ReducerID.max, name: 'Max', description: 'Maximum Value', standard: true },
{ id: ReducerID.mean, name: 'Mean', description: 'Average Value', standard: true, alias: 'avg' },
{ id: ReducerID.mean, name: 'Mean', description: 'Average Value', standard: true, aliasIds: ['avg'] },
{
id: ReducerID.sum,
name: 'Total',
description: 'The sum of all values',
emptyInputResult: 0,
standard: true,
alias: 'total',
aliasIds: ['total'],
},
{
id: ReducerID.count,
......
import { sharedSingleStatMigrationCheck } from './SingleStatBaseOptions';
describe('sharedSingleStatMigrationCheck', () => {
it('from old valueOptions model without pluginVersion', () => {
const panel = {
options: {
valueOptions: {
unit: 'watt',
stat: 'last',
decimals: 5,
},
minValue: 10,
maxValue: 100,
valueMappings: [{ type: 1, value: '1', text: 'OK' }],
thresholds: [
{
color: 'green',
index: 0,
value: null,
},
{
color: 'orange',
index: 1,
value: 40,
},
{
color: 'red',
index: 2,
value: 80,
},
],
},
title: 'Usage',
type: 'bargauge',
};
expect(sharedSingleStatMigrationCheck(panel as any)).toMatchSnapshot();
});
});
......@@ -3,7 +3,7 @@ import omit from 'lodash/omit';
import { VizOrientation, PanelModel } from '../../types/panel';
import { FieldDisplayOptions } from '../../utils/fieldDisplay';
import { Field, fieldReducers, Threshold, sortThresholds } from '@grafana/data';
import { fieldReducers, Threshold, sortThresholds } from '@grafana/data';
export interface SingleStatBaseOptions {
fieldOptions: FieldDisplayOptions;
......@@ -25,54 +25,86 @@ export const sharedSingleStatOptionsCheck = (
return options;
};
export const sharedSingleStatMigrationCheck = (panel: PanelModel<SingleStatBaseOptions>) => {
export function sharedSingleStatMigrationCheck(panel: PanelModel<SingleStatBaseOptions>) {
if (!panel.options) {
// This happens on the first load or when migrating from angular
return {};
}
// This migration aims to keep the most recent changes up-to-date
// Plugins should explicitly migrate for known version changes and only use this
// as a backup
const old = panel.options as any;
if (old.valueOptions) {
const { valueOptions } = old;
const fieldOptions = (old.fieldOptions = {} as FieldDisplayOptions);
const field = (fieldOptions.defaults = {} as Field);
field.mappings = old.valueMappings;
field.thresholds = migrateOldThresholds(old.thresholds);
field.unit = valueOptions.unit;
field.decimals = valueOptions.decimals;
// Make sure the stats have a valid name
if (valueOptions.stat) {
const reducer = fieldReducers.get(valueOptions.stat);
if (reducer) {
fieldOptions.calcs = [reducer.id];
}
}
const previousVersion = parseFloat(panel.pluginVersion || '6.1');
let options = panel.options as any;
field.min = old.minValue;
field.max = old.maxValue;
// remove old props
return omit(old, 'valueMappings', 'thresholds', 'valueOptions', 'minValue', 'maxValue');
} else if (old.fieldOptions) {
// Move mappins & thresholds to field defautls (6.4+)
const { mappings, thresholds, ...fieldOptions } = old.fieldOptions;
fieldOptions.defaults = {
mappings,
thresholds: migrateOldThresholds(thresholds),
...fieldOptions.defaults,
};
old.fieldOptions = fieldOptions;
if (previousVersion < 6.2) {
options = migrateFromValueOptions(options);
}
if (previousVersion < 6.3) {
options = moveThresholdsAndMappingsToField(options);
}
return options as SingleStatBaseOptions;
}
export function moveThresholdsAndMappingsToField(old: any) {
const { fieldOptions } = old;
if (!fieldOptions) {
return old;
}
return panel.options;
};
const { mappings, thresholds, ...rest } = old.fieldOptions;
return {
...old,
fieldOptions: {
...rest,
defaults: {
...fieldOptions.defaults,
mappings,
thresholds: migrateOldThresholds(thresholds),
},
},
};
}
/*
* Moves valueMappings and thresholds from root to new fieldOptions object
* Renames valueOptions to to defaults and moves it under fieldOptions
*/
export function migrateFromValueOptions(old: any) {
const { valueOptions } = old;
if (!valueOptions) {
return old;
}
const fieldOptions: any = {};
const fieldDefaults: any = {};
fieldOptions.mappings = old.valueMappings;
fieldOptions.thresholds = old.thresholds;
fieldOptions.defaults = fieldDefaults;
fieldDefaults.unit = valueOptions.unit;
fieldDefaults.decimals = valueOptions.decimals;
// Make sure the stats have a valid name
if (valueOptions.stat) {
const reducer = fieldReducers.get(valueOptions.stat);
if (reducer) {
fieldOptions.calcs = [reducer.id];
}
}
fieldDefaults.min = old.minValue;
fieldDefaults.max = old.maxValue;
const newOptions = {
...old,
fieldOptions,
};
return omit(newOptions, 'valueMappings', 'thresholds', 'valueOptions', 'minValue', 'maxValue');
}
export function migrateOldThresholds(thresholds?: any[]): Threshold[] | undefined {
if (!thresholds || !thresholds.length) {
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`sharedSingleStatMigrationCheck from old valueOptions model without pluginVersion 1`] = `
Object {
"fieldOptions": Object {
"calcs": Array [
"last",
],
"defaults": Object {
"decimals": 5,
"mappings": Array [
Object {
"text": "OK",
"type": 1,
"value": "1",
},
],
"max": 100,
"min": 10,
"thresholds": Array [
Object {
"color": "green",
"value": -Infinity,
},
Object {
"color": "orange",
"value": 40,
},
Object {
"color": "red",
"value": 80,
},
],
"unit": "watt",
},
},
}
`;
......@@ -152,8 +152,6 @@ export class PanelChrome extends PureComponent<Props, State> {
onRefresh = () => {
const { panel, isInView, width } = this.props;
console.log('onRefresh', panel.id);
if (!isInView) {
console.log('Refresh when panel is visible', panel.id);
this.setState({ refreshWhenInView: true });
......
......@@ -247,8 +247,6 @@ export class PanelModel {
pluginLoaded(plugin: PanelPlugin) {
this.plugin = plugin;
this.applyPluginOptionDefaults(plugin);
if (plugin.panel && plugin.onPanelMigration) {
const version = getPluginVersion(plugin);
if (version !== this.pluginVersion) {
......@@ -256,6 +254,8 @@ export class PanelModel {
this.pluginVersion = version;
}
}
this.applyPluginOptionDefaults(plugin);
}
changePlugin(newPlugin: PanelPlugin) {
......
......@@ -40,18 +40,7 @@ describe('BarGauge Panel Migrations', () => {
orientation: 'vertical',
},
pluginVersion: '6.2.0',
targets: [
{
refId: 'A',
scenarioId: 'random_walk',
},
{
refId: 'B',
scenarioId: 'random_walk',
},
],
timeFrom: null,
timeShift: null,
targets: [],
title: 'Usage',
type: 'bargauge',
} as PanelModel;
......
import { PanelModel } from '@grafana/ui';
import {
sharedSingleStatMigrationCheck,
migrateOldThresholds,
} from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
import { sharedSingleStatMigrationCheck } from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
import { BarGaugeOptions } from './types';
export const barGaugePanelMigrationCheck = (panel: PanelModel<BarGaugeOptions>): Partial<BarGaugeOptions> => {
if (!panel.options) {
// This happens on the first load or when migrating from angular
return {};
}
// Move thresholds to field
const previousVersion = panel.pluginVersion || '';
if (previousVersion.startsWith('6.2') || previousVersion.startsWith('6.3')) {
console.log('TRANSFORM', panel.options);
const old = panel.options as any;
const { fieldOptions } = old;
if (fieldOptions) {
const { mappings, thresholds, ...rest } = fieldOptions;
rest.defaults = {
mappings,
thresholds: migrateOldThresholds(thresholds),
...rest.defaults,
};
return {
...old,
fieldOptions: rest,
};
}
}
// Default to the standard migration path
return sharedSingleStatMigrationCheck(panel);
};
import { Field, fieldReducers } from '@grafana/data';
import { PanelModel, FieldDisplayOptions } from '@grafana/ui';
import { PanelModel } from '@grafana/ui';
import { GaugeOptions } from './types';
import {
sharedSingleStatMigrationCheck,
migrateOldThresholds,
} from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
import { sharedSingleStatMigrationCheck } from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
export const gaugePanelMigrationCheck = (panel: PanelModel<GaugeOptions>): Partial<GaugeOptions> => {
if (!panel.options) {
// This happens on the first load or when migrating from angular
return {};
}
const previousVersion = panel.pluginVersion || '';
if (!previousVersion || previousVersion.startsWith('6.1')) {
const old = panel.options as any;
const { valueOptions } = old;
const options = {} as GaugeOptions;
options.showThresholdLabels = old.showThresholdLabels;
options.showThresholdMarkers = old.showThresholdMarkers;
options.orientation = old.orientation;
const fieldOptions = (options.fieldOptions = {} as FieldDisplayOptions);
const field = (fieldOptions.defaults = {} as Field);
field.mappings = old.valueMappings;
field.thresholds = migrateOldThresholds(old.thresholds);
field.unit = valueOptions.unit;
field.decimals = valueOptions.decimals;
// Make sure the stats have a valid name
if (valueOptions.stat) {
fieldOptions.calcs = [fieldReducers.get(valueOptions.stat).id];
}
field.min = old.minValue;
field.max = old.maxValue;
return options;
} else if (previousVersion.startsWith('6.2') || previousVersion.startsWith('6.3')) {
const old = panel.options as any;
const { fieldOptions } = old;
if (fieldOptions) {
const { mappings, thresholds, ...rest } = fieldOptions;
rest.default = {
mappings,
thresholds: migrateOldThresholds(thresholds),
...rest.defaults,
};
return {
...old.options,
fieldOptions: rest,
};
}
}
// Default to the standard migration path
return sharedSingleStatMigrationCheck(panel);
};
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