Commit 1256d9e7 by Dominik Prokop Committed by GitHub

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
parent 1228fdc5
...@@ -63,10 +63,10 @@ export interface PanelModel<TOptions = any> { ...@@ -63,10 +63,10 @@ export interface PanelModel<TOptions = any> {
export type PanelMigrationHandler<TOptions = any> = (panel: PanelModel<TOptions>) => Partial<TOptions>; 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> = ( export type PanelTypeChangedHandler<TOptions = any> = (
options: Partial<TOptions>, panel: PanelModel<TOptions>,
prevPluginId: string, prevPluginId: string,
prevOptions: any prevOptions: any
) => Partial<TOptions>; ) => Partial<TOptions>;
...@@ -117,8 +117,12 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta> ...@@ -117,8 +117,12 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
} }
/** /**
* This function is called when the visualization was changed. This * This function is called when the visualization was changed. This
* passes in the options that were used in the previous visualization * 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) { setPanelChangeHandler(handler: PanelTypeChangedHandler) {
this.onPanelTypeChanged = handler; this.onPanelTypeChanged = handler;
......
...@@ -27,15 +27,16 @@ export interface SingleStatBaseOptions { ...@@ -27,15 +27,16 @@ export interface SingleStatBaseOptions {
const optionsToKeep = ['fieldOptions', 'orientation']; const optionsToKeep = ['fieldOptions', 'orientation'];
export function sharedSingleStatPanelChangedHandler( export function sharedSingleStatPanelChangedHandler(
options: Partial<SingleStatBaseOptions> | any, panel: PanelModel<Partial<SingleStatBaseOptions>> | any,
prevPluginId: string, prevPluginId: string,
prevOptions: any prevOptions: any
) { ) {
let options = panel.options;
// Migrating from angular singlestat // Migrating from angular singlestat
if (prevPluginId === 'singlestat' && prevOptions.angular) { if (prevPluginId === 'singlestat' && prevOptions.angular) {
const panel = prevOptions.angular; const prevPanel = prevOptions.angular;
const reducer = fieldReducers.getIfExists(panel.valueName); const reducer = fieldReducers.getIfExists(prevPanel.valueName);
const options = { options = {
fieldOptions: { fieldOptions: {
defaults: {} as FieldConfig, defaults: {} as FieldConfig,
overrides: [] as ConfigOverrideRule[], overrides: [] as ConfigOverrideRule[],
...@@ -45,28 +46,28 @@ export function sharedSingleStatPanelChangedHandler( ...@@ -45,28 +46,28 @@ export function sharedSingleStatPanelChangedHandler(
}; };
const defaults = options.fieldOptions.defaults; const defaults = options.fieldOptions.defaults;
if (panel.format) { if (prevPanel.format) {
defaults.unit = panel.format; defaults.unit = prevPanel.format;
} }
if (panel.nullPointMode) { if (prevPanel.nullPointMode) {
defaults.nullValueMode = panel.nullPointMode; defaults.nullValueMode = prevPanel.nullPointMode;
} }
if (panel.nullText) { if (prevPanel.nullText) {
defaults.noValue = panel.nullText; defaults.noValue = prevPanel.nullText;
} }
if (panel.decimals || panel.decimals === 0) { if (prevPanel.decimals || prevPanel.decimals === 0) {
defaults.decimals = panel.decimals; defaults.decimals = prevPanel.decimals;
} }
// Convert thresholds and color values // Convert thresholds and color values
if (panel.thresholds && panel.colors) { if (prevPanel.thresholds && prevPanel.colors) {
const levels = panel.thresholds.split(',').map((strVale: string) => { const levels = prevPanel.thresholds.split(',').map((strVale: string) => {
return Number(strVale.trim()); return Number(strVale.trim());
}); });
// One more color than threshold // One more color than threshold
const thresholds: Threshold[] = []; const thresholds: Threshold[] = [];
for (const color of panel.colors) { for (const color of prevPanel.colors) {
const idx = thresholds.length - 1; const idx = thresholds.length - 1;
if (idx >= 0) { if (idx >= 0) {
thresholds.push({ value: levels[idx], color }); thresholds.push({ value: levels[idx], color });
...@@ -81,14 +82,14 @@ export function sharedSingleStatPanelChangedHandler( ...@@ -81,14 +82,14 @@ export function sharedSingleStatPanelChangedHandler(
} }
// Convert value mappings // Convert value mappings
const mappings = convertOldAngularValueMapping(panel); const mappings = convertOldAngularValueMapping(prevPanel);
if (mappings && mappings.length) { if (mappings && mappings.length) {
defaults.mappings = mappings; defaults.mappings = mappings;
} }
if (panel.gauge && panel.gauge.show) { if (prevPanel.gauge && prevPanel.gauge.show) {
defaults.min = panel.gauge.minValue; defaults.min = prevPanel.gauge.minValue;
defaults.max = panel.gauge.maxValue; defaults.max = prevPanel.gauge.maxValue;
} }
return options; return options;
} }
......
...@@ -313,7 +313,7 @@ export class PanelModel { ...@@ -313,7 +313,7 @@ export class PanelModel {
old = oldOptions.options; old = oldOptions.options;
} }
this.options = this.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 // switch
......
import { AnnoListPanel } from './AnnoListPanel'; import { AnnoListPanel } from './AnnoListPanel';
import { AnnoOptions, defaults } from './types'; import { AnnoOptions, defaults } from './types';
import { AnnoListEditor } from './AnnoListEditor'; import { AnnoListEditor } from './AnnoListEditor';
import { PanelPlugin } from '@grafana/data'; import { PanelModel, PanelPlugin } from '@grafana/data';
export const plugin = new PanelPlugin<AnnoOptions>(AnnoListPanel) export const plugin = new PanelPlugin<AnnoOptions>(AnnoListPanel)
.setDefaults(defaults) .setDefaults(defaults)
.setEditor(AnnoListEditor) .setEditor(AnnoListEditor)
// TODO, we should support this directly in the plugin infrastructure // 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') { if (prevPluginId === 'ryantxu-annolist-panel') {
return prevOptions as AnnoOptions; return prevOptions as AnnoOptions;
} }
return options; return panel.options;
}); });
...@@ -9,12 +9,12 @@ export const gaugePanelMigrationHandler = (panel: PanelModel<GaugeOptions>): Par ...@@ -9,12 +9,12 @@ export const gaugePanelMigrationHandler = (panel: PanelModel<GaugeOptions>): Par
// This is called when the panel changes from another panel // This is called when the panel changes from another panel
export const gaugePanelChangedHandler = ( export const gaugePanelChangedHandler = (
options: Partial<GaugeOptions> | any, panel: PanelModel<Partial<GaugeOptions>> | any,
prevPluginId: string, prevPluginId: string,
prevOptions: any prevOptions: any
) => { ) => {
// This handles most config changes // 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 // Changing from angular singlestat
if (prevPluginId === 'singlestat' && prevOptions.angular) { if (prevPluginId === 'singlestat' && prevOptions.angular) {
......
import { PanelPlugin } from '@grafana/data'; import { PanelModel, PanelPlugin } from '@grafana/data';
import { TextPanelEditor } from './TextPanelEditor'; import { TextPanelEditor } from './TextPanelEditor';
import { TextPanel } from './TextPanel'; import { TextPanel } from './TextPanel';
...@@ -7,9 +7,9 @@ import { TextOptions, defaults } from './types'; ...@@ -7,9 +7,9 @@ import { TextOptions, defaults } from './types';
export const plugin = new PanelPlugin<TextOptions>(TextPanel) export const plugin = new PanelPlugin<TextOptions>(TextPanel)
.setDefaults(defaults) .setDefaults(defaults)
.setEditor(TextPanelEditor) .setEditor(TextPanelEditor)
.setPanelChangeHandler((options: TextOptions, prevPluginId: string, prevOptions: any) => { .setPanelChangeHandler((panel: PanelModel<TextOptions>, prevPluginId: string, prevOptions: any) => {
if (prevPluginId === 'text') { if (prevPluginId === 'text') {
return prevOptions as TextOptions; 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