FieldOverrides: Move FieldConfigSource from fieldOptions to PanelModel.fieldConfig (#22600)
* Apply field overrides in PanelChrome * Move applyFieldOverrides to panel query runner * Review updates * Make sure overrides are applied back on souce panel when exiting the new edit mode * TS ignores in est * Make field display work in viz repeater * Review updates * Review and test updates * Change the way overrides and trransformations are retrieved in PQR * Add fieldConfig property to PanelModel * Dashboard migration v1 * Use field config when exiting new panel edit mode * Gauge - use fieldConfig from panel model * FieldDisplayOptions - don's extend FieldConfigSource * Fix fieldDisplay ts * StatPanel updated * Stat panel defaults applied * Table2 panel options update * React graph updates * BarGauge updated * PieChart, Gauge, BarGauge and Stat updates * PieChart - remove field config defaults from options * FieldDisplayEditor - remove unused methos * PanelModel - remove debugger * Remove fieldConfig from field options when migrating dashboard * Update data links migrations * Update fieldDisaplay tests to respect new fieldConfig * Update dashboard schema version in snapshots * Fix BarGaugePanel test * Rebase fixes * Add onFieldConfigChange to PanelProps type * Update shared single stat migration * Pass PanelModel instead of options only for panel type change handler [breaking] * Renames * Don't mutate panel options * Migrations update * Remove obsolete snap * Minor updates after review * Fix null checks * Temporarily (until we decide to switch to new pane edit) bring back old aditors * Temporarily rename ValueMappingEditor and MappingRow to Legacy* * Migrations update * Updae setFieldConfigDefaults API * Update the way field config defaults are applied * Use standard field config for gauge, bar gauge and stat panels * refactoring * Revert dashboard fieldOptions migrations as those are handled by single stat migrator * Fix ts in tests * Strict null fix and some minor fixes Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
co-authored by
Torkel Ödegaard
parent
d99a67075f
commit
bf7579d984
@@ -28,7 +28,9 @@ describe('FieldDisplay', () => {
|
||||
const options = createDisplayOptions({
|
||||
fieldOptions: {
|
||||
calcs: [ReducerID.first],
|
||||
override: {},
|
||||
},
|
||||
fieldConfig: {
|
||||
overrides: [],
|
||||
defaults: {
|
||||
title: '$__cell_0 * $__field_name * $__series_name',
|
||||
},
|
||||
@@ -42,8 +44,6 @@ describe('FieldDisplay', () => {
|
||||
const options = createDisplayOptions({
|
||||
fieldOptions: {
|
||||
calcs: [ReducerID.last],
|
||||
override: {},
|
||||
defaults: {},
|
||||
},
|
||||
});
|
||||
const display = getFieldDisplayValues(options);
|
||||
@@ -56,8 +56,6 @@ describe('FieldDisplay', () => {
|
||||
values: true, //
|
||||
limit: 1000,
|
||||
calcs: [],
|
||||
override: {},
|
||||
defaults: {},
|
||||
},
|
||||
});
|
||||
const display = getFieldDisplayValues(options);
|
||||
@@ -70,8 +68,6 @@ describe('FieldDisplay', () => {
|
||||
values: true, //
|
||||
limit: 2,
|
||||
calcs: [],
|
||||
override: {},
|
||||
defaults: {},
|
||||
},
|
||||
});
|
||||
const display = getFieldDisplayValues(options);
|
||||
@@ -101,7 +97,7 @@ describe('FieldDisplay', () => {
|
||||
|
||||
it('Should return field thresholds when there is no data', () => {
|
||||
const options = createEmptyDisplayOptions({
|
||||
fieldOptions: {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
thresholds: { steps: [{ color: '#F2495C', value: 50 }] },
|
||||
},
|
||||
@@ -123,7 +119,7 @@ describe('FieldDisplay', () => {
|
||||
it('Should return field mapped value when there is no data', () => {
|
||||
const mapEmptyToText = '0';
|
||||
const options = createEmptyDisplayOptions({
|
||||
fieldOptions: {
|
||||
fieldConfig: {
|
||||
defaults: {
|
||||
mappings: [
|
||||
{
|
||||
@@ -146,8 +142,8 @@ describe('FieldDisplay', () => {
|
||||
it('Should always return display numeric 0 when there is no data', () => {
|
||||
const mapEmptyToText = '0';
|
||||
const options = createEmptyDisplayOptions({
|
||||
fieldOptions: {
|
||||
override: {
|
||||
fieldConfig: {
|
||||
overrides: {
|
||||
mappings: [
|
||||
{
|
||||
id: 1,
|
||||
@@ -241,7 +237,7 @@ function createEmptyDisplayOptions(extend = {}): GetFieldDisplayValuesOptions {
|
||||
});
|
||||
}
|
||||
|
||||
function createDisplayOptions(extend = {}): GetFieldDisplayValuesOptions {
|
||||
function createDisplayOptions(extend: Partial<GetFieldDisplayValuesOptions> = {}): GetFieldDisplayValuesOptions {
|
||||
const options: GetFieldDisplayValuesOptions = {
|
||||
data: [
|
||||
toDataFrame({
|
||||
@@ -258,8 +254,10 @@ function createDisplayOptions(extend = {}): GetFieldDisplayValuesOptions {
|
||||
},
|
||||
fieldOptions: {
|
||||
calcs: [],
|
||||
defaults: {},
|
||||
},
|
||||
fieldConfig: {
|
||||
overrides: [],
|
||||
defaults: {},
|
||||
},
|
||||
theme: {} as GrafanaTheme,
|
||||
};
|
||||
|
||||
@@ -19,7 +19,8 @@ import { ReducerID, reduceField } from '../transformations/fieldReducer';
|
||||
import { ScopedVars } from '../types/ScopedVars';
|
||||
import { getTimeField } from '../dataframe/processDataFrame';
|
||||
|
||||
export interface FieldDisplayOptions extends FieldConfigSource {
|
||||
// export interface FieldDisplayOptions extends FieldConfigSource {
|
||||
export interface FieldDisplayOptions {
|
||||
values?: boolean; // If true show each row value
|
||||
limit?: number; // if showing all values limit
|
||||
calcs: string[]; // when !values, pick one value for the whole field
|
||||
@@ -57,6 +58,7 @@ function getTitleTemplate(title: string | undefined, stats: string[], data?: Dat
|
||||
if (fieldCount > 1 || !parts.length) {
|
||||
parts.push('${' + VAR_FIELD_NAME + '}');
|
||||
}
|
||||
|
||||
return parts.join(' ');
|
||||
}
|
||||
|
||||
@@ -75,6 +77,7 @@ export interface FieldDisplay {
|
||||
export interface GetFieldDisplayValuesOptions {
|
||||
data?: DataFrame[];
|
||||
fieldOptions: FieldDisplayOptions;
|
||||
fieldConfig: FieldConfigSource;
|
||||
replaceVariables: InterpolateFunction;
|
||||
sparkline?: boolean; // Calculate the sparkline
|
||||
theme: GrafanaTheme;
|
||||
@@ -84,7 +87,7 @@ export interface GetFieldDisplayValuesOptions {
|
||||
export const DEFAULT_FIELD_DISPLAY_VALUES_LIMIT = 25;
|
||||
|
||||
export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): FieldDisplay[] => {
|
||||
const { replaceVariables, fieldOptions } = options;
|
||||
const { replaceVariables, fieldOptions, fieldConfig } = options;
|
||||
const calcs = fieldOptions.calcs.length ? fieldOptions.calcs : [ReducerID.last];
|
||||
|
||||
const values: FieldDisplay[] = [];
|
||||
@@ -94,7 +97,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
const data = options.data;
|
||||
let hitLimit = false;
|
||||
const limit = fieldOptions.limit ? fieldOptions.limit : DEFAULT_FIELD_DISPLAY_VALUES_LIMIT;
|
||||
const defaultTitle = getTitleTemplate(fieldOptions.defaults.title, calcs, data);
|
||||
const defaultTitle = getTitleTemplate(fieldConfig.defaults.title, calcs, data);
|
||||
const scopedVars: ScopedVars = {};
|
||||
|
||||
for (let s = 0; s < data.length && !hitLimit; s++) {
|
||||
@@ -194,7 +197,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
|
||||
|
||||
if (values.length === 0) {
|
||||
values.push(createNoValuesFieldDisplay(options));
|
||||
} else if (values.length === 1 && !fieldOptions.defaults.title) {
|
||||
} else if (values.length === 1 && !fieldConfig.defaults.title) {
|
||||
// Don't show title for single item
|
||||
values[0].display.title = undefined;
|
||||
}
|
||||
@@ -237,8 +240,8 @@ export function getDisplayValueAlignmentFactors(values: FieldDisplay[]): Display
|
||||
|
||||
function createNoValuesFieldDisplay(options: GetFieldDisplayValuesOptions): FieldDisplay {
|
||||
const displayName = 'No data';
|
||||
const { fieldOptions } = options;
|
||||
const { defaults } = fieldOptions;
|
||||
const { fieldConfig } = options;
|
||||
const { defaults } = fieldConfig;
|
||||
|
||||
const displayProcessor = getDisplayProcessor({
|
||||
field: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ScopedVars } from './ScopedVars';
|
||||
import { LoadingState } from './data';
|
||||
import { DataFrame } from './dataFrame';
|
||||
import { AbsoluteTimeRange, TimeRange, TimeZone } from './time';
|
||||
import { FieldConfigEditorRegistry } from './fieldOverrides';
|
||||
import { FieldConfigEditorRegistry, FieldConfigSource } from './fieldOverrides';
|
||||
|
||||
export type InterpolateFunction = (value: string, scopedVars?: ScopedVars, format?: string | Function) => string;
|
||||
|
||||
@@ -54,6 +54,10 @@ export interface PanelProps<T = any> {
|
||||
timeZone: TimeZone;
|
||||
options: T;
|
||||
onOptionsChange: (options: T) => void;
|
||||
/** Panel fields configuration */
|
||||
fieldConfig: FieldConfigSource;
|
||||
/** Enables panel field config manipulation */
|
||||
onFieldConfigChange: (config: FieldConfigSource) => void;
|
||||
renderCounter: number;
|
||||
transparent: boolean;
|
||||
width: number;
|
||||
@@ -70,11 +74,23 @@ export interface PanelEditorProps<T = any> {
|
||||
callback?: () => void
|
||||
) => void;
|
||||
data: PanelData;
|
||||
|
||||
/**
|
||||
* Panel fields configuration - temporart solution
|
||||
* TODO[FieldConfig]: Remove when we switch old editor to new
|
||||
*/
|
||||
fieldConfig: FieldConfigSource;
|
||||
/**
|
||||
* Enables panel field config manipulation
|
||||
* TODO[FieldConfig]: Remove when we switch old editor to new
|
||||
*/
|
||||
onFieldConfigChange: (config: FieldConfigSource) => void;
|
||||
}
|
||||
|
||||
export interface PanelModel<TOptions = any> {
|
||||
id: number;
|
||||
options: TOptions;
|
||||
fieldConfig: FieldConfigSource;
|
||||
pluginVersion?: string;
|
||||
scopedVars?: ScopedVars;
|
||||
}
|
||||
@@ -98,6 +114,10 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
|
||||
editor?: ComponentClass<PanelEditorProps<TOptions>>;
|
||||
customFieldConfigs?: FieldConfigEditorRegistry;
|
||||
defaults?: TOptions;
|
||||
fieldConfigDefaults?: FieldConfigSource = {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
};
|
||||
onPanelMigration?: PanelMigrationHandler<TOptions>;
|
||||
onPanelTypeChanged?: PanelTypeChangedHandler<TOptions>;
|
||||
noPadding?: boolean;
|
||||
@@ -155,6 +175,19 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
|
||||
this.customFieldConfigs = registry;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables configuration of panel's default field config
|
||||
*/
|
||||
setFieldConfigDefaults(defaultConfig: Partial<FieldConfigSource>) {
|
||||
this.fieldConfigDefaults = {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
...defaultConfig,
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export interface PanelMenuItem {
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
InterpolateFunction,
|
||||
GrafanaTheme,
|
||||
FieldMatcherID,
|
||||
FieldDisplayOptions,
|
||||
MutableDataFrame,
|
||||
DataFrame,
|
||||
toDataFrame,
|
||||
@@ -82,7 +81,7 @@ describe('FieldOverrides', () => {
|
||||
it('will apply field overrides', () => {
|
||||
const data = applyFieldOverrides({
|
||||
data: [f0], // the frame
|
||||
fieldOptions: src as FieldDisplayOptions, // defaults + overrides
|
||||
fieldOptions: src as FieldConfigSource, // defaults + overrides
|
||||
replaceVariables: (undefined as any) as InterpolateFunction,
|
||||
theme: (undefined as any) as GrafanaTheme,
|
||||
})[0];
|
||||
@@ -108,7 +107,7 @@ describe('FieldOverrides', () => {
|
||||
it('will apply set min/max when asked', () => {
|
||||
const data = applyFieldOverrides({
|
||||
data: [f0], // the frame
|
||||
fieldOptions: src as FieldDisplayOptions, // defaults + overrides
|
||||
fieldOptions: src as FieldConfigSource, // defaults + overrides
|
||||
replaceVariables: (undefined as any) as InterpolateFunction,
|
||||
theme: (undefined as any) as GrafanaTheme,
|
||||
autoMinMax: true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { FieldOverrideContext, FieldOverrideEditorProps, FieldConfigEditorProps, ValueMapping } from '@grafana/data';
|
||||
import { ValueMappingsEditor } from '..';
|
||||
import { LegacyValueMappingsEditor } from '..';
|
||||
|
||||
export interface ValueMappingFieldConfigSettings {}
|
||||
|
||||
@@ -27,7 +27,7 @@ export class ValueMappingsValueEditor extends React.PureComponent<
|
||||
value = [];
|
||||
}
|
||||
|
||||
return <ValueMappingsEditor valueMappings={value} onChange={onChange} />;
|
||||
return <LegacyValueMappingsEditor valueMappings={value} onChange={onChange} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
toNumberString,
|
||||
toIntegerOrUndefined,
|
||||
SelectableValue,
|
||||
FieldConfig,
|
||||
} from '@grafana/data';
|
||||
|
||||
const showOptions: Array<SelectableValue<boolean>> = [
|
||||
@@ -47,10 +46,6 @@ export class FieldDisplayEditor extends PureComponent<Props> {
|
||||
this.props.onChange({ ...this.props.value, calcs });
|
||||
};
|
||||
|
||||
onDefaultsChange = (value: FieldConfig) => {
|
||||
this.props.onChange({ ...this.props.value, defaults: value });
|
||||
};
|
||||
|
||||
onLimitChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.props.onChange({
|
||||
...this.props.value,
|
||||
|
||||
@@ -34,7 +34,48 @@ describe('sharedSingleStatMigrationHandler', () => {
|
||||
type: 'bargauge',
|
||||
};
|
||||
|
||||
expect(sharedSingleStatMigrationHandler(panel as any)).toMatchSnapshot();
|
||||
sharedSingleStatMigrationHandler(panel as any);
|
||||
expect((panel as any).fieldConfig).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"defaults": Object {
|
||||
"color": Object {
|
||||
"mode": "thresholds",
|
||||
},
|
||||
"decimals": 5,
|
||||
"mappings": Array [
|
||||
Object {
|
||||
"text": "OK",
|
||||
"type": 1,
|
||||
"value": "1",
|
||||
},
|
||||
],
|
||||
"max": 100,
|
||||
"min": 10,
|
||||
"thresholds": Object {
|
||||
"mode": "absolute",
|
||||
"steps": Array [
|
||||
Object {
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": -Infinity,
|
||||
},
|
||||
Object {
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40,
|
||||
},
|
||||
Object {
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80,
|
||||
},
|
||||
],
|
||||
},
|
||||
"unit": "watt",
|
||||
},
|
||||
"overrides": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('move thresholds to scale', () => {
|
||||
@@ -64,7 +105,17 @@ describe('sharedSingleStatMigrationHandler', () => {
|
||||
},
|
||||
};
|
||||
|
||||
expect(sharedSingleStatMigrationHandler(panel as any)).toMatchSnapshot();
|
||||
sharedSingleStatMigrationHandler(panel as any);
|
||||
|
||||
expect((panel as any).fieldConfig).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"defaults": Object {
|
||||
"mappings": undefined,
|
||||
"thresholds": undefined,
|
||||
},
|
||||
"overrides": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('Remove unused `overrides` option', () => {
|
||||
@@ -90,6 +141,17 @@ describe('sharedSingleStatMigrationHandler', () => {
|
||||
type: 'bargauge',
|
||||
};
|
||||
|
||||
expect(sharedSingleStatMigrationHandler(panel as any)).toMatchSnapshot();
|
||||
sharedSingleStatMigrationHandler(panel as any);
|
||||
expect((panel as any).fieldConfig).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"defaults": Object {
|
||||
"mappings": undefined,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": undefined,
|
||||
},
|
||||
"overrides": Array [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ import {
|
||||
VizOrientation,
|
||||
PanelModel,
|
||||
FieldDisplayOptions,
|
||||
ConfigOverrideRule,
|
||||
ThresholdsMode,
|
||||
ThresholdsConfig,
|
||||
validateFieldConfig,
|
||||
@@ -32,66 +31,15 @@ export function sharedSingleStatPanelChangedHandler(
|
||||
prevOptions: any
|
||||
) {
|
||||
let options = panel.options;
|
||||
|
||||
panel.fieldConfig = panel.fieldConfig || {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
};
|
||||
|
||||
// Migrating from angular singlestat
|
||||
if (prevPluginId === 'singlestat' && prevOptions.angular) {
|
||||
const prevPanel = prevOptions.angular;
|
||||
const reducer = fieldReducers.getIfExists(prevPanel.valueName);
|
||||
options = {
|
||||
fieldOptions: {
|
||||
defaults: {} as FieldConfig,
|
||||
overrides: [] as ConfigOverrideRule[],
|
||||
calcs: [reducer ? reducer.id : ReducerID.mean],
|
||||
},
|
||||
orientation: VizOrientation.Horizontal,
|
||||
};
|
||||
|
||||
const defaults = options.fieldOptions.defaults;
|
||||
if (prevPanel.format) {
|
||||
defaults.unit = prevPanel.format;
|
||||
}
|
||||
if (prevPanel.nullPointMode) {
|
||||
defaults.nullValueMode = prevPanel.nullPointMode;
|
||||
}
|
||||
if (prevPanel.nullText) {
|
||||
defaults.noValue = prevPanel.nullText;
|
||||
}
|
||||
if (prevPanel.decimals || prevPanel.decimals === 0) {
|
||||
defaults.decimals = prevPanel.decimals;
|
||||
}
|
||||
|
||||
// Convert thresholds and color values
|
||||
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 prevPanel.colors) {
|
||||
const idx = thresholds.length - 1;
|
||||
if (idx >= 0) {
|
||||
thresholds.push({ value: levels[idx], color });
|
||||
} else {
|
||||
thresholds.push({ value: -Infinity, color });
|
||||
}
|
||||
}
|
||||
defaults.thresholds = {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: thresholds,
|
||||
};
|
||||
}
|
||||
|
||||
// Convert value mappings
|
||||
const mappings = convertOldAngularValueMapping(prevPanel);
|
||||
if (mappings && mappings.length) {
|
||||
defaults.mappings = mappings;
|
||||
}
|
||||
|
||||
if (prevPanel.gauge && prevPanel.gauge.show) {
|
||||
defaults.min = prevPanel.gauge.minValue;
|
||||
defaults.max = prevPanel.gauge.maxValue;
|
||||
}
|
||||
return options;
|
||||
return migrateFromAngularSinglestat(panel, prevOptions);
|
||||
}
|
||||
|
||||
for (const k of optionsToKeep) {
|
||||
@@ -99,6 +47,70 @@ export function sharedSingleStatPanelChangedHandler(
|
||||
options[k] = cloneDeep(prevOptions[k]);
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
function migrateFromAngularSinglestat(panel: PanelModel<Partial<SingleStatBaseOptions>> | any, prevOptions: any) {
|
||||
const prevPanel = prevOptions.angular;
|
||||
const reducer = fieldReducers.getIfExists(prevPanel.valueName);
|
||||
const options = {
|
||||
fieldOptions: {
|
||||
calcs: [reducer ? reducer.id : ReducerID.mean],
|
||||
},
|
||||
orientation: VizOrientation.Horizontal,
|
||||
};
|
||||
|
||||
const defaults: FieldConfig = {};
|
||||
|
||||
if (prevPanel.format) {
|
||||
defaults.unit = prevPanel.format;
|
||||
}
|
||||
if (prevPanel.nullPointMode) {
|
||||
defaults.nullValueMode = prevPanel.nullPointMode;
|
||||
}
|
||||
if (prevPanel.nullText) {
|
||||
defaults.noValue = prevPanel.nullText;
|
||||
}
|
||||
if (prevPanel.decimals || prevPanel.decimals === 0) {
|
||||
defaults.decimals = prevPanel.decimals;
|
||||
}
|
||||
|
||||
// Convert thresholds and color values
|
||||
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 prevPanel.colors) {
|
||||
const idx = thresholds.length - 1;
|
||||
if (idx >= 0) {
|
||||
thresholds.push({ value: levels[idx], color });
|
||||
} else {
|
||||
thresholds.push({ value: -Infinity, color });
|
||||
}
|
||||
}
|
||||
defaults.thresholds = {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: thresholds,
|
||||
};
|
||||
}
|
||||
|
||||
// Convert value mappings
|
||||
const mappings = convertOldAngularValueMapping(prevPanel);
|
||||
if (mappings && mappings.length) {
|
||||
defaults.mappings = mappings;
|
||||
}
|
||||
|
||||
if (prevPanel.gauge && prevPanel.gauge.show) {
|
||||
defaults.min = prevPanel.gauge.minValue;
|
||||
defaults.max = prevPanel.gauge.maxValue;
|
||||
}
|
||||
|
||||
panel.fieldConfig.defaults = defaults;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -162,6 +174,22 @@ export function sharedSingleStatMigrationHandler(panel: PanelModel<SingleStatBas
|
||||
validateFieldConfig(defaults);
|
||||
}
|
||||
|
||||
if (previousVersion < 7.0) {
|
||||
panel.fieldConfig = panel.fieldConfig || { defaults: {}, overrides: [] };
|
||||
panel.fieldConfig = {
|
||||
defaults:
|
||||
options.fieldOptions && options.fieldOptions.defaults
|
||||
? { ...panel.fieldConfig.defaults, ...options.fieldOptions.defaults }
|
||||
: panel.fieldConfig.defaults,
|
||||
overrides:
|
||||
options.fieldOptions && options.fieldOptions.overrides
|
||||
? [...panel.fieldConfig.overrides, ...options.fieldOptions.overrides]
|
||||
: panel.fieldConfig.overrides,
|
||||
};
|
||||
delete options.fieldOptions.defaults;
|
||||
delete options.fieldOptions.overrides;
|
||||
}
|
||||
|
||||
return options as SingleStatBaseOptions;
|
||||
}
|
||||
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`sharedSingleStatMigrationHandler Remove unused \`overrides\` option 1`] = `
|
||||
Object {
|
||||
"fieldOptions": Object {
|
||||
"decimals": 5,
|
||||
"defaults": Object {
|
||||
"mappings": undefined,
|
||||
"max": 100,
|
||||
"min": 0,
|
||||
"thresholds": undefined,
|
||||
},
|
||||
"overrides": Array [],
|
||||
"stat": "last",
|
||||
"unit": "watt",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`sharedSingleStatMigrationHandler from old valueOptions model without pluginVersion 1`] = `
|
||||
Object {
|
||||
"fieldOptions": Object {
|
||||
"calcs": Array [
|
||||
"last",
|
||||
],
|
||||
"defaults": Object {
|
||||
"color": Object {
|
||||
"mode": "thresholds",
|
||||
},
|
||||
"decimals": 5,
|
||||
"mappings": Array [
|
||||
Object {
|
||||
"text": "OK",
|
||||
"type": 1,
|
||||
"value": "1",
|
||||
},
|
||||
],
|
||||
"max": 100,
|
||||
"min": 10,
|
||||
"thresholds": Object {
|
||||
"mode": "absolute",
|
||||
"steps": Array [
|
||||
Object {
|
||||
"color": "green",
|
||||
"index": 0,
|
||||
"value": -Infinity,
|
||||
},
|
||||
Object {
|
||||
"color": "orange",
|
||||
"index": 1,
|
||||
"value": 40,
|
||||
},
|
||||
Object {
|
||||
"color": "red",
|
||||
"index": 2,
|
||||
"value": 80,
|
||||
},
|
||||
],
|
||||
},
|
||||
"unit": "watt",
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`sharedSingleStatMigrationHandler move thresholds to scale 1`] = `
|
||||
Object {
|
||||
"fieldOptions": Object {
|
||||
"defaults": Object {
|
||||
"mappings": undefined,
|
||||
"thresholds": undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
`;
|
||||
@@ -58,7 +58,7 @@ export class StatsPicker extends PureComponent<Props> {
|
||||
if (isArray(item)) {
|
||||
onChange(item.map(v => v.value));
|
||||
} else {
|
||||
onChange(item.value ? [item.value] : []);
|
||||
onChange(item && item.value ? [item.value] : []);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ const mappingOptions = [
|
||||
{ value: MappingType.RangeToText, label: 'Range' },
|
||||
];
|
||||
|
||||
export default class MappingRow extends PureComponent<Props, State> {
|
||||
export default class LegacyMappingRow extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { LegacyValueMappingsEditor } from './LegacyValueMappingsEditor';
|
||||
|
||||
const ValueMappingsEditorStories = storiesOf('Panel/LegacyValueMappingsEditor', module);
|
||||
|
||||
ValueMappingsEditorStories.add('default', () => {
|
||||
return <LegacyValueMappingsEditor valueMappings={[]} onChange={action('Mapping changed')} />;
|
||||
});
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { ValueMappingsEditor, Props } from './ValueMappingsEditor';
|
||||
import { LegacyValueMappingsEditor, Props } from './LegacyValueMappingsEditor';
|
||||
import { MappingType } from '@grafana/data';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
@@ -15,9 +15,9 @@ const setup = (propOverrides?: object) => {
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
||||
const wrapper = shallow(<ValueMappingsEditor {...props} />);
|
||||
const wrapper = shallow(<LegacyValueMappingsEditor {...props} />);
|
||||
|
||||
const instance = wrapper.instance() as ValueMappingsEditor;
|
||||
const instance = wrapper.instance() as LegacyValueMappingsEditor;
|
||||
|
||||
return {
|
||||
instance,
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import MappingRow from './MappingRow';
|
||||
import LegacyMappingRow from './LegacyMappingRow';
|
||||
import { MappingType, ValueMapping } from '@grafana/data';
|
||||
import { Button } from '../Button/Button';
|
||||
import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup';
|
||||
@@ -15,7 +15,7 @@ interface State {
|
||||
nextIdToAdd: number;
|
||||
}
|
||||
|
||||
export class ValueMappingsEditor extends PureComponent<Props, State> {
|
||||
export class LegacyValueMappingsEditor extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
@@ -91,7 +91,7 @@ export class ValueMappingsEditor extends PureComponent<Props, State> {
|
||||
<div>
|
||||
{valueMappings.length > 0 &&
|
||||
valueMappings.map((valueMapping, index) => (
|
||||
<MappingRow
|
||||
<LegacyMappingRow
|
||||
key={`${valueMapping.text}-${index}`}
|
||||
valueMapping={valueMapping}
|
||||
updateValueMapping={this.updateGauge}
|
||||
@@ -1,10 +0,0 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { ValueMappingsEditor } from './ValueMappingsEditor';
|
||||
|
||||
const ValueMappingsEditorStories = storiesOf('Panel/ValueMappingsEditor', module);
|
||||
|
||||
ValueMappingsEditorStories.add('default', () => {
|
||||
return <ValueMappingsEditor valueMappings={[]} onChange={action('Mapping changed')} />;
|
||||
});
|
||||
+2
-2
@@ -5,7 +5,7 @@ exports[`Render should render component 1`] = `
|
||||
title="Value mappings"
|
||||
>
|
||||
<div>
|
||||
<MappingRow
|
||||
<LegacyMappingRow
|
||||
key="Ok-0"
|
||||
removeValueMapping={[Function]}
|
||||
updateValueMapping={[Function]}
|
||||
@@ -19,7 +19,7 @@ exports[`Render should render component 1`] = `
|
||||
}
|
||||
}
|
||||
/>
|
||||
<MappingRow
|
||||
<LegacyMappingRow
|
||||
key="Meh-1"
|
||||
removeValueMapping={[Function]}
|
||||
updateValueMapping={[Function]}
|
||||
@@ -28,7 +28,7 @@ export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker';
|
||||
export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';
|
||||
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
|
||||
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
|
||||
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
|
||||
export { LegacyValueMappingsEditor } from './ValueMappingsEditor/LegacyValueMappingsEditor';
|
||||
export { Switch } from './Switch/Switch';
|
||||
export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
|
||||
export { PieChart, PieChartType } from './PieChart/PieChart';
|
||||
|
||||
Reference in New Issue
Block a user