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
This commit is contained in:
Dominik Prokop 2020-03-13 08:27:16 +01:00 committed by GitHub
parent 1228fdc57a
commit 1256d9e78d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 37 additions and 32 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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<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;
});

View File

@ -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) {

View File

@ -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<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;
});