Commit 16f3fe7e by Dominik Prokop Committed by Torkel Ödegaard

grafana/data: PanelTypeChangedHandler API update to use PanelModel instead of…

grafana/data: PanelTypeChangedHandler API update to use PanelModel instead of panel options object [BREAKING] (#22754)

This changes PanelModel's API to support PanelModel API updates when changing panel type. Primary useful when changing panel type between Angular and React panels, as other migrations can be handled via DashboardMigrator.

API change: https://github.com/grafana/grafana/pull/22754/files#diff-d9e3f91dc7d5697f6d85ada008003b4b

(cherry picked from commit 1256d9e7)
parent ca6d08d5
......@@ -63,10 +63,10 @@ export interface PanelModel<TOptions = any> {
export type PanelMigrationHandler<TOptions = any> = (panel: PanelModel<TOptions>) => Partial<TOptions>;
/**
* 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<TOptions = any> = (
options: Partial<TOptions>,
panel: PanelModel<TOptions>,
prevPluginId: string,
prevOptions: any
) => Partial<TOptions>;
......@@ -117,8 +117,12 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
}
/**
* 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;
......
......@@ -27,15 +27,16 @@ export interface SingleStatBaseOptions {
const optionsToKeep = ['fieldOptions', 'orientation'];
export function sharedSingleStatPanelChangedHandler(
options: Partial<SingleStatBaseOptions> | any,
panel: PanelModel<Partial<SingleStatBaseOptions>> | 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;
}
......
......@@ -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
......
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<AnnoOptions>(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<AnnoOptions>, prevPluginId: string, prevOptions: any) => {
if (prevPluginId === 'ryantxu-annolist-panel') {
return prevOptions as AnnoOptions;
}
return options;
return panel.options;
});
......@@ -9,12 +9,12 @@ export const gaugePanelMigrationHandler = (panel: PanelModel<GaugeOptions>): Par
// This is called when the panel changes from another panel
export const gaugePanelChangedHandler = (
options: Partial<GaugeOptions> | any,
panel: PanelModel<Partial<GaugeOptions>> | 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) {
......
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<TextOptions>(TextPanel)
.setDefaults(defaults)
.setEditor(TextPanelEditor)
.setPanelChangeHandler((options: TextOptions, prevPluginId: string, prevOptions: any) => {
.setPanelChangeHandler((panel: PanelModel<TextOptions>, prevPluginId: string, prevOptions: any) => {
if (prevPluginId === 'text') {
return prevOptions as TextOptions;
}
return options;
return panel.options;
});
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