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

pull/18398/head
Torkel Ödegaard 6 years ago committed by GitHub
parent 2514209083
commit 541981c341
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      devenv/dev-dashboards/panel-gauge/gauge_tests.json
  2. 6
      packages/grafana-data/src/utils/fieldReducer.ts
  3. 39
      packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.test.ts
  4. 90
      packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts
  5. 38
      packages/grafana-ui/src/components/SingleStatShared/__snapshots__/SingleStatBaseOptions.test.ts.snap
  6. 2
      public/app/features/dashboard/dashgrid/PanelChrome.tsx
  7. 4
      public/app/features/dashboard/state/PanelModel.ts
  8. 13
      public/app/plugins/panel/bargauge/BarGaugeMigrations.test.ts
  9. 31
      public/app/plugins/panel/bargauge/BarGaugeMigrations.ts
  10. 57
      public/app/plugins/panel/gauge/GaugeMigrations.ts

@ -44,7 +44,7 @@
"nullPointMode": "null", "nullPointMode": "null",
"options-gauge": { "options-gauge": {
"baseColor": "#299c46", "baseColor": "#299c46",
"decimals": "2", "decimals": 2,
"maxValue": 100, "maxValue": 100,
"minValue": 0, "minValue": 0,
"options": { "options": {
@ -111,7 +111,7 @@
"nullPointMode": "null", "nullPointMode": "null",
"options-gauge": { "options-gauge": {
"baseColor": "#299c46", "baseColor": "#299c46",
"decimals": "", "decimals": null,
"maxValue": 100, "maxValue": 100,
"minValue": 0, "minValue": 0,
"options": { "options": {
@ -178,7 +178,7 @@
"nullPointMode": "null", "nullPointMode": "null",
"options-gauge": { "options-gauge": {
"baseColor": "#299c46", "baseColor": "#299c46",
"decimals": "", "decimals": null,
"maxValue": 100, "maxValue": 100,
"minValue": 0, "minValue": 0,
"options": { "options": {

@ -104,7 +104,7 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
name: 'Last (not null)', name: 'Last (not null)',
description: 'Last non-null value', description: 'Last non-null value',
standard: true, standard: true,
alias: 'current', aliasIds: ['current'],
reduce: calculateLastNotNull, reduce: calculateLastNotNull,
}, },
{ {
@ -124,14 +124,14 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
}, },
{ id: ReducerID.min, name: 'Min', description: 'Minimum Value', standard: true }, { id: ReducerID.min, name: 'Min', description: 'Minimum Value', standard: true },
{ id: ReducerID.max, name: 'Max', description: 'Maximum 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, id: ReducerID.sum,
name: 'Total', name: 'Total',
description: 'The sum of all values', description: 'The sum of all values',
emptyInputResult: 0, emptyInputResult: 0,
standard: true, standard: true,
alias: 'total', aliasIds: ['total'],
}, },
{ {
id: ReducerID.count, id: ReducerID.count,

@ -0,0 +1,39 @@
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 { VizOrientation, PanelModel } from '../../types/panel';
import { FieldDisplayOptions } from '../../utils/fieldDisplay'; import { FieldDisplayOptions } from '../../utils/fieldDisplay';
import { Field, fieldReducers, Threshold, sortThresholds } from '@grafana/data'; import { fieldReducers, Threshold, sortThresholds } from '@grafana/data';
export interface SingleStatBaseOptions { export interface SingleStatBaseOptions {
fieldOptions: FieldDisplayOptions; fieldOptions: FieldDisplayOptions;
@ -25,26 +25,67 @@ export const sharedSingleStatOptionsCheck = (
return options; return options;
}; };
export const sharedSingleStatMigrationCheck = (panel: PanelModel<SingleStatBaseOptions>) => { export function sharedSingleStatMigrationCheck(panel: PanelModel<SingleStatBaseOptions>) {
if (!panel.options) { if (!panel.options) {
// This happens on the first load or when migrating from angular // This happens on the first load or when migrating from angular
return {}; return {};
} }
// This migration aims to keep the most recent changes up-to-date const previousVersion = parseFloat(panel.pluginVersion || '6.1');
// Plugins should explicitly migrate for known version changes and only use this let options = panel.options as any;
// as a backup
const old = panel.options as any; if (previousVersion < 6.2) {
if (old.valueOptions) { 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;
}
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; const { valueOptions } = old;
if (!valueOptions) {
return old;
}
const fieldOptions: any = {};
const fieldDefaults: any = {};
const fieldOptions = (old.fieldOptions = {} as FieldDisplayOptions); fieldOptions.mappings = old.valueMappings;
fieldOptions.thresholds = old.thresholds;
fieldOptions.defaults = fieldDefaults;
const field = (fieldOptions.defaults = {} as Field); fieldDefaults.unit = valueOptions.unit;
field.mappings = old.valueMappings; fieldDefaults.decimals = valueOptions.decimals;
field.thresholds = migrateOldThresholds(old.thresholds);
field.unit = valueOptions.unit;
field.decimals = valueOptions.decimals;
// Make sure the stats have a valid name // Make sure the stats have a valid name
if (valueOptions.stat) { if (valueOptions.stat) {
@ -54,25 +95,16 @@ export const sharedSingleStatMigrationCheck = (panel: PanelModel<SingleStatBaseO
} }
} }
field.min = old.minValue; fieldDefaults.min = old.minValue;
field.max = old.maxValue; fieldDefaults.max = old.maxValue;
// remove old props const newOptions = {
return omit(old, 'valueMappings', 'thresholds', 'valueOptions', 'minValue', 'maxValue'); ...old,
} else if (old.fieldOptions) { 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;
return old;
}
return panel.options; return omit(newOptions, 'valueMappings', 'thresholds', 'valueOptions', 'minValue', 'maxValue');
}; }
export function migrateOldThresholds(thresholds?: any[]): Threshold[] | undefined { export function migrateOldThresholds(thresholds?: any[]): Threshold[] | undefined {
if (!thresholds || !thresholds.length) { if (!thresholds || !thresholds.length) {

@ -0,0 +1,38 @@
// 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 = () => { onRefresh = () => {
const { panel, isInView, width } = this.props; const { panel, isInView, width } = this.props;
console.log('onRefresh', panel.id);
if (!isInView) { if (!isInView) {
console.log('Refresh when panel is visible', panel.id); console.log('Refresh when panel is visible', panel.id);
this.setState({ refreshWhenInView: true }); this.setState({ refreshWhenInView: true });

@ -247,8 +247,6 @@ export class PanelModel {
pluginLoaded(plugin: PanelPlugin) { pluginLoaded(plugin: PanelPlugin) {
this.plugin = plugin; this.plugin = plugin;
this.applyPluginOptionDefaults(plugin);
if (plugin.panel && plugin.onPanelMigration) { if (plugin.panel && plugin.onPanelMigration) {
const version = getPluginVersion(plugin); const version = getPluginVersion(plugin);
if (version !== this.pluginVersion) { if (version !== this.pluginVersion) {
@ -256,6 +254,8 @@ export class PanelModel {
this.pluginVersion = version; this.pluginVersion = version;
} }
} }
this.applyPluginOptionDefaults(plugin);
} }
changePlugin(newPlugin: PanelPlugin) { changePlugin(newPlugin: PanelPlugin) {

@ -40,18 +40,7 @@ describe('BarGauge Panel Migrations', () => {
orientation: 'vertical', orientation: 'vertical',
}, },
pluginVersion: '6.2.0', pluginVersion: '6.2.0',
targets: [ targets: [],
{
refId: 'A',
scenarioId: 'random_walk',
},
{
refId: 'B',
scenarioId: 'random_walk',
},
],
timeFrom: null,
timeShift: null,
title: 'Usage', title: 'Usage',
type: 'bargauge', type: 'bargauge',
} as PanelModel; } as PanelModel;

@ -1,36 +1,7 @@
import { PanelModel } from '@grafana/ui'; import { PanelModel } from '@grafana/ui';
import { import { sharedSingleStatMigrationCheck } from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
sharedSingleStatMigrationCheck,
migrateOldThresholds,
} from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
import { BarGaugeOptions } from './types'; import { BarGaugeOptions } from './types';
export const barGaugePanelMigrationCheck = (panel: PanelModel<BarGaugeOptions>): Partial<BarGaugeOptions> => { 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); return sharedSingleStatMigrationCheck(panel);
}; };

@ -1,60 +1,7 @@
import { Field, fieldReducers } from '@grafana/data'; import { PanelModel } from '@grafana/ui';
import { PanelModel, FieldDisplayOptions } from '@grafana/ui';
import { GaugeOptions } from './types'; import { GaugeOptions } from './types';
import { import { sharedSingleStatMigrationCheck } from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
sharedSingleStatMigrationCheck,
migrateOldThresholds,
} from '@grafana/ui/src/components/SingleStatShared/SingleStatBaseOptions';
export const gaugePanelMigrationCheck = (panel: PanelModel<GaugeOptions>): Partial<GaugeOptions> => { 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); return sharedSingleStatMigrationCheck(panel);
}; };

Loading…
Cancel
Save