diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts index 889e4ab310e..2ac38b6253a 100644 --- a/packages/grafana-ui/src/types/panel.ts +++ b/packages/grafana-ui/src/types/panel.ts @@ -26,13 +26,21 @@ export interface PanelEditorProps { onOptionsChange: (options: T) => void; } -export type PreservePanelOptionsHandler = (pluginId: string, prevOptions: any) => Partial; +/** + * Called before a panel is initalized + */ +export type PanelTypeChangedHook = ( + options: TOptions, + prevPluginId?: string, + prevOptions?: any +) => TOptions; export class ReactPanelPlugin { panel: ComponentClass>; editor?: ComponentClass>; defaults?: TOptions; - preserveOptions?: PreservePanelOptionsHandler; + + panelTypeChangedHook?: PanelTypeChangedHook; constructor(panel: ComponentClass>) { this.panel = panel; @@ -46,8 +54,12 @@ export class ReactPanelPlugin { this.defaults = defaults; } - setPreserveOptionsHandler(handler: PreservePanelOptionsHandler) { - this.preserveOptions = handler; + /** + * Called when the visualization changes. + * Lets you keep whatever settings made sense in the previous panel + */ + setPanelTypeChangedHook(v: PanelTypeChangedHook) { + this.panelTypeChangedHook = v; } } diff --git a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx index 3955f45d926..029fb0e8371 100644 --- a/public/app/features/dashboard/dashgrid/DashboardPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardPanel.tsx @@ -14,6 +14,7 @@ import { PanelEditor } from '../panel_editor/PanelEditor'; import { PanelModel, DashboardModel } from '../state'; import { PanelPlugin } from 'app/types'; import { PanelResizer } from './PanelResizer'; +import { PanelTypeChangedHook } from '@grafana/ui'; export interface Props { panel: PanelModel; @@ -91,7 +92,11 @@ export class DashboardPanel extends PureComponent { this.props.panel.changeType(pluginId); } else { - panel.changeType(pluginId, plugin.exports.reactPanel.preserveOptions); + let hook: PanelTypeChangedHook | null = null; + if (plugin.exports.reactPanel) { + hook = plugin.exports.reactPanel.panelTypeChangedHook; + } + panel.changeType(pluginId, hook); } } diff --git a/public/app/features/dashboard/state/PanelModel.ts b/public/app/features/dashboard/state/PanelModel.ts index 88065fdf208..128bd8d0785 100644 --- a/public/app/features/dashboard/state/PanelModel.ts +++ b/public/app/features/dashboard/state/PanelModel.ts @@ -3,7 +3,7 @@ import _ from 'lodash'; // Types import { Emitter } from 'app/core/utils/emitter'; -import { DataQuery, TimeSeries, Threshold, ScopedVars } from '@grafana/ui'; +import { DataQuery, TimeSeries, Threshold, ScopedVars, PanelTypeChangedHook } from '@grafana/ui'; import { TableData } from '@grafana/ui/src'; export interface GridPos { @@ -237,7 +237,7 @@ export class PanelModel { }); } - changeType(pluginId: string, preserveOptions?: any) { + changeType(pluginId: string, hook?: PanelTypeChangedHook) { const oldOptions: any = this.getOptionsToRemember(); const oldPluginId = this.type; @@ -255,9 +255,12 @@ export class PanelModel { this.cachedPluginOptions[oldPluginId] = oldOptions; this.restorePanelOptions(pluginId); - if (preserveOptions && oldOptions) { + // Callback that can validate and migrate any existing settings + if (hook) { this.options = this.options || {}; - Object.assign(this.options, preserveOptions(oldPluginId, oldOptions.options)); + const old = oldOptions ? oldOptions.options : null; + + Object.assign(this.options, hook(this.options, oldPluginId, old)); } } diff --git a/public/app/plugins/panel/bargauge/module.tsx b/public/app/plugins/panel/bargauge/module.tsx index d5dcbabc34f..e7f2e2d7738 100644 --- a/public/app/plugins/panel/bargauge/module.tsx +++ b/public/app/plugins/panel/bargauge/module.tsx @@ -8,10 +8,8 @@ export const reactPanel = new ReactPanelPlugin(BarGaugePanel); reactPanel.setEditor(BarGaugePanelEditor); reactPanel.setDefaults(defaults); -reactPanel.setPreserveOptionsHandler((pluginId: string, prevOptions: any) => { - const options: Partial = {}; - - if (prevOptions.valueOptions) { +reactPanel.setPanelTypeChangedHook((options: BarGaugeOptions, prevPluginId?: string, prevOptions?: any) => { + if (prevOptions && prevOptions.valueOptions) { options.valueOptions = prevOptions.valueOptions; options.thresholds = prevOptions.thresholds; options.maxValue = prevOptions.maxValue; diff --git a/public/app/plugins/panel/gauge/module.tsx b/public/app/plugins/panel/gauge/module.tsx index 95a6e29ae4d..b8e90a27bff 100644 --- a/public/app/plugins/panel/gauge/module.tsx +++ b/public/app/plugins/panel/gauge/module.tsx @@ -8,10 +8,8 @@ export const reactPanel = new ReactPanelPlugin(GaugePanel); reactPanel.setEditor(GaugePanelEditor); reactPanel.setDefaults(defaults); -reactPanel.setPreserveOptionsHandler((pluginId: string, prevOptions: any) => { - const options: Partial = {}; - - if (prevOptions.valueOptions) { +reactPanel.setPanelTypeChangedHook((options: GaugeOptions, prevPluginId?: string, prevOptions?: any) => { + if (prevOptions && prevOptions.valueOptions) { options.valueOptions = prevOptions.valueOptions; options.thresholds = prevOptions.thresholds; options.maxValue = prevOptions.maxValue; diff --git a/public/app/plugins/panel/text2/module.tsx b/public/app/plugins/panel/text2/module.tsx index bac292e8c29..b2e3057de34 100644 --- a/public/app/plugins/panel/text2/module.tsx +++ b/public/app/plugins/panel/text2/module.tsx @@ -8,3 +8,10 @@ export const reactPanel = new ReactPanelPlugin(TextPanel); reactPanel.setEditor(TextPanelEditor); reactPanel.setDefaults(defaults); +reactPanel.setPanelTypeChangedHook((options: TextOptions, prevPluginId: string, prevOptions: any) => { + if (prevPluginId === 'text') { + return prevOptions as TextOptions; + } + + return options; +});