diff --git a/packages/grafana-data/src/types/panel.ts b/packages/grafana-data/src/types/panel.ts index a195d3fe646..93c34ed99d6 100644 --- a/packages/grafana-data/src/types/panel.ts +++ b/packages/grafana-data/src/types/panel.ts @@ -63,10 +63,10 @@ export interface PanelModel { export type PanelMigrationHandler = (panel: PanelModel) => Partial; /** - * Called before a panel is initialized + * Called before a panel is initialized. Allows panel inspection for any updates before changing the panel type. */ export type PanelTypeChangedHandler = ( - options: Partial, + panel: PanelModel, prevPluginId: string, prevOptions: any ) => Partial; @@ -117,8 +117,12 @@ export class PanelPlugin extends GrafanaPlugin } /** - * This function is called when the visualization was changed. This - * passes in the options that were used in the previous visualization + * This function is called when the visualization was changed. This + * passes in the panel model for previous visualisation options inspection + * and panel model updates. + * + * This is useful for supporting PanelModel API updates when changing + * between Angular and React panels. */ setPanelChangeHandler(handler: PanelTypeChangedHandler) { this.onPanelTypeChanged = handler; diff --git a/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts b/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts index 559279afa83..2526ac39904 100644 --- a/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts +++ b/packages/grafana-ui/src/components/SingleStatShared/SingleStatBaseOptions.ts @@ -27,15 +27,16 @@ export interface SingleStatBaseOptions { const optionsToKeep = ['fieldOptions', 'orientation']; export function sharedSingleStatPanelChangedHandler( - options: Partial | any, + panel: PanelModel> | any, prevPluginId: string, prevOptions: any ) { + let options = panel.options; // Migrating from angular singlestat if (prevPluginId === 'singlestat' && prevOptions.angular) { - const panel = prevOptions.angular; - const reducer = fieldReducers.getIfExists(panel.valueName); - const options = { + const prevPanel = prevOptions.angular; + const reducer = fieldReducers.getIfExists(prevPanel.valueName); + options = { fieldOptions: { defaults: {} as FieldConfig, overrides: [] as ConfigOverrideRule[], @@ -45,28 +46,28 @@ export function sharedSingleStatPanelChangedHandler( }; const defaults = options.fieldOptions.defaults; - if (panel.format) { - defaults.unit = panel.format; + if (prevPanel.format) { + defaults.unit = prevPanel.format; } - if (panel.nullPointMode) { - defaults.nullValueMode = panel.nullPointMode; + if (prevPanel.nullPointMode) { + defaults.nullValueMode = prevPanel.nullPointMode; } - if (panel.nullText) { - defaults.noValue = panel.nullText; + if (prevPanel.nullText) { + defaults.noValue = prevPanel.nullText; } - if (panel.decimals || panel.decimals === 0) { - defaults.decimals = panel.decimals; + if (prevPanel.decimals || prevPanel.decimals === 0) { + defaults.decimals = prevPanel.decimals; } // Convert thresholds and color values - if (panel.thresholds && panel.colors) { - const levels = panel.thresholds.split(',').map((strVale: string) => { + if (prevPanel.thresholds && prevPanel.colors) { + const levels = prevPanel.thresholds.split(',').map((strVale: string) => { return Number(strVale.trim()); }); // One more color than threshold const thresholds: Threshold[] = []; - for (const color of panel.colors) { + for (const color of prevPanel.colors) { const idx = thresholds.length - 1; if (idx >= 0) { thresholds.push({ value: levels[idx], color }); @@ -81,14 +82,14 @@ export function sharedSingleStatPanelChangedHandler( } // Convert value mappings - const mappings = convertOldAngularValueMapping(panel); + const mappings = convertOldAngularValueMapping(prevPanel); if (mappings && mappings.length) { defaults.mappings = mappings; } - if (panel.gauge && panel.gauge.show) { - defaults.min = panel.gauge.minValue; - defaults.max = panel.gauge.maxValue; + if (prevPanel.gauge && prevPanel.gauge.show) { + defaults.min = prevPanel.gauge.minValue; + defaults.max = prevPanel.gauge.maxValue; } return options; } diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index fd89ffaa0ce..1c36b15ce91 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -313,7 +313,7 @@ export class PanelModel { old = oldOptions.options; } this.options = this.options || {}; - Object.assign(this.options, newPlugin.onPanelTypeChanged(this.options, oldPluginId, old)); + Object.assign(this.options, newPlugin.onPanelTypeChanged(this, oldPluginId, old)); } // switch diff --git a/public/app/plugins/panel/annolist/module.ts b/public/app/plugins/panel/annolist/module.ts index f00af0ee65e..6bee00cea8e 100644 --- a/public/app/plugins/panel/annolist/module.ts +++ b/public/app/plugins/panel/annolist/module.ts @@ -1,16 +1,16 @@ import { AnnoListPanel } from './AnnoListPanel'; import { AnnoOptions, defaults } from './types'; import { AnnoListEditor } from './AnnoListEditor'; -import { PanelPlugin } from '@grafana/data'; +import { PanelModel, PanelPlugin } from '@grafana/data'; export const plugin = new PanelPlugin(AnnoListPanel) .setDefaults(defaults) .setEditor(AnnoListEditor) // TODO, we should support this directly in the plugin infrastructure - .setPanelChangeHandler((options: AnnoOptions, prevPluginId: string, prevOptions: any) => { + .setPanelChangeHandler((panel: PanelModel, prevPluginId: string, prevOptions: any) => { if (prevPluginId === 'ryantxu-annolist-panel') { return prevOptions as AnnoOptions; } - return options; + return panel.options; }); diff --git a/public/app/plugins/panel/gauge/GaugeMigrations.ts b/public/app/plugins/panel/gauge/GaugeMigrations.ts index 83e3be05f82..d4b619aa20c 100644 --- a/public/app/plugins/panel/gauge/GaugeMigrations.ts +++ b/public/app/plugins/panel/gauge/GaugeMigrations.ts @@ -9,12 +9,12 @@ export const gaugePanelMigrationHandler = (panel: PanelModel): Par // This is called when the panel changes from another panel export const gaugePanelChangedHandler = ( - options: Partial | any, + panel: PanelModel> | any, prevPluginId: string, prevOptions: any ) => { // This handles most config changes - const opts = sharedSingleStatPanelChangedHandler(options, prevPluginId, prevOptions) as GaugeOptions; + const opts = sharedSingleStatPanelChangedHandler(panel, prevPluginId, prevOptions) as GaugeOptions; // Changing from angular singlestat if (prevPluginId === 'singlestat' && prevOptions.angular) { diff --git a/public/app/plugins/panel/text2/module.tsx b/public/app/plugins/panel/text2/module.tsx index babc3713da9..ae48f013f41 100644 --- a/public/app/plugins/panel/text2/module.tsx +++ b/public/app/plugins/panel/text2/module.tsx @@ -1,4 +1,4 @@ -import { PanelPlugin } from '@grafana/data'; +import { PanelModel, PanelPlugin } from '@grafana/data'; import { TextPanelEditor } from './TextPanelEditor'; import { TextPanel } from './TextPanel'; @@ -7,9 +7,9 @@ import { TextOptions, defaults } from './types'; export const plugin = new PanelPlugin(TextPanel) .setDefaults(defaults) .setEditor(TextPanelEditor) - .setPanelChangeHandler((options: TextOptions, prevPluginId: string, prevOptions: any) => { + .setPanelChangeHandler((panel: PanelModel, prevPluginId: string, prevOptions: any) => { if (prevPluginId === 'text') { return prevOptions as TextOptions; } - return options; + return panel.options; });