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:
Dominik Prokop
2020-03-19 11:50:31 +01:00
committed by GitHub
co-authored by Torkel Ödegaard
parent d99a67075f
commit bf7579d984
49 changed files with 679 additions and 475 deletions
@@ -43,8 +43,43 @@ describe('BarGauge Panel Migrations', () => {
targets: [],
title: 'Usage',
type: 'bargauge',
} as PanelModel;
} as Omit<PanelModel, 'fieldConfig'>;
expect(barGaugePanelMigrationHandler(panel)).toMatchSnapshot();
expect(barGaugePanelMigrationHandler(panel as PanelModel)).toMatchSnapshot();
expect((panel as any).fieldConfig).toMatchInlineSnapshot(`
Object {
"defaults": Object {
"color": Object {
"mode": "thresholds",
},
"decimals": null,
"mappings": Array [],
"max": 33,
"min": -22,
"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 [],
}
`);
});
});
@@ -8,6 +8,7 @@ import {
PanelProps,
LoadingState,
dateTime,
FieldConfigSource,
toDataFrame,
} from '@grafana/data';
import { BarGaugeDisplayMode } from '@grafana/ui';
@@ -66,13 +67,15 @@ function createBarGaugePanelWithData(data: PanelData): ReactWrapper<PanelProps<B
displayMode: BarGaugeDisplayMode.Lcd,
fieldOptions: {
calcs: ['mean'],
defaults: {},
values: false,
overrides: [],
},
orientation: VizOrientation.Horizontal,
showUnfilled: true,
};
const fieldConfig: FieldConfigSource = {
defaults: {},
overrides: [],
};
return mount<BarGaugePanel>(
<BarGaugePanel
@@ -81,6 +84,8 @@ function createBarGaugePanelWithData(data: PanelData): ReactWrapper<PanelProps<B
timeRange={timeRange}
timeZone={'utc'}
options={options}
fieldConfig={fieldConfig}
onFieldConfigChange={() => {}}
onOptionsChange={() => {}}
onChangeTimeRange={() => {}}
replaceVariables={s => s}
@@ -51,9 +51,10 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
};
getValues = (): FieldDisplay[] => {
const { data, options, replaceVariables } = this.props;
const { data, options, replaceVariables, fieldConfig } = this.props;
return getFieldDisplayValues({
...options,
fieldConfig,
fieldOptions: options.fieldOptions,
replaceVariables,
theme: config.theme,
data: data.series,
@@ -2,83 +2,94 @@
import React, { PureComponent } from 'react';
import {
ThresholdsEditor,
ValueMappingsEditor,
PanelOptionsGrid,
FieldDisplayEditor,
FieldPropertiesEditor,
PanelOptionsGroup,
FormLabel,
Select,
DataLinksEditor,
Switch,
FieldPropertiesEditor,
ThresholdsEditor,
LegacyValueMappingsEditor,
DataLinksEditor,
} from '@grafana/ui';
import {
DataLink,
FieldConfig,
FieldDisplayOptions,
PanelEditorProps,
ThresholdsConfig,
ValueMapping,
FieldDisplayOptions,
FieldConfig,
DataLink,
PanelEditorProps,
} from '@grafana/data';
import { BarGaugeOptions, displayModes } from './types';
import { orientationOptions } from '../gauge/types';
import {
getDataLinksVariableSuggestions,
getCalculationValueDataLinksVariableSuggestions,
} from 'app/features/panel/panellinks/link_srv';
getDataLinksVariableSuggestions,
} from '../../../features/panel/panellinks/link_srv';
export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGaugeOptions>> {
onThresholdsChanged = (thresholds: ThresholdsConfig) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
...current,
thresholds,
});
};
onValueMappingsChanged = (mappings: ValueMapping[]) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
...current,
mappings,
});
};
onDisplayOptionsChanged = (fieldOptions: FieldDisplayOptions) =>
this.props.onOptionsChange({
...this.props.options,
fieldOptions,
});
onDefaultsChange = (field: FieldConfig) => {
this.onDisplayOptionsChanged({
...this.props.options.fieldOptions,
defaults: field,
});
};
onOrientationChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, orientation: value });
onDisplayModeChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, displayMode: value });
onToggleShowUnfilled = () => {
this.props.onOptionsChange({ ...this.props.options, showUnfilled: !this.props.options.showUnfilled });
};
onDataLinksChanged = (links: DataLink[]) => {
this.onDefaultsChange({
...this.props.options.fieldOptions.defaults,
links,
onThresholdsChanged = (thresholds: ThresholdsConfig) => {
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
thresholds,
},
});
};
render() {
const { options } = this.props;
const { fieldOptions } = options;
const { defaults } = fieldOptions;
onValueMappingsChanged = (mappings: ValueMapping[]) => {
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
mappings,
},
});
};
onDataLinksChanged = (links: DataLink[]) => {
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
links,
},
});
};
onDefaultsChange = (field: FieldConfig, event?: React.SyntheticEvent<HTMLElement>, callback?: () => void) => {
this.props.onFieldConfigChange({
...this.props.fieldConfig,
defaults: field,
});
};
render() {
const { options, fieldConfig } = this.props;
const { fieldOptions } = options;
const { defaults } = fieldConfig;
const labelWidth = 6;
const suggestions = fieldOptions.values
? getDataLinksVariableSuggestions(this.props.data.series)
: getCalculationValueDataLinksVariableSuggestions(this.props.data.series);
const labelWidth = 6;
return (
<>
@@ -105,14 +116,16 @@ export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGauge
value={displayModes.find(item => item.value === options.displayMode)}
/>
</div>
{options.displayMode !== 'lcd' && (
<Switch
label="Unfilled"
labelClass={`width-${labelWidth}`}
checked={options.showUnfilled}
onChange={this.onToggleShowUnfilled}
/>
)}
<>
{options.displayMode !== 'lcd' && (
<Switch
label="Unfilled"
labelClass={`width-${labelWidth}`}
checked={options.showUnfilled}
onChange={this.onToggleShowUnfilled}
/>
)}
</>
</PanelOptionsGroup>
<PanelOptionsGroup title="Field">
<FieldPropertiesEditor
@@ -126,7 +139,7 @@ export class BarGaugePanelEditor extends PureComponent<PanelEditorProps<BarGauge
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={defaults.thresholds} />
</PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<LegacyValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<PanelOptionsGroup title="Data links">
<DataLinksEditor
@@ -7,37 +7,6 @@ Object {
"calcs": Array [
"mean",
],
"defaults": Object {
"color": Object {
"mode": "thresholds",
},
"decimals": null,
"mappings": Array [],
"max": 33,
"min": -22,
"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 [],
"thresholds": Array [
Object {
"color": "green",
@@ -3,10 +3,12 @@ import { PanelPlugin } from '@grafana/data';
import { BarGaugePanel } from './BarGaugePanel';
import { BarGaugePanelEditor } from './BarGaugePanelEditor';
import { BarGaugeOptions, defaults } from './types';
import { standardFieldConfig } from '../stat/types';
import { barGaugePanelMigrationHandler } from './BarGaugeMigrations';
export const plugin = new PanelPlugin<BarGaugeOptions>(BarGaugePanel)
.setDefaults(defaults)
.setFieldConfigDefaults(standardFieldConfig)
.setEditor(BarGaugePanelEditor)
.setPanelChangeHandler(sharedSingleStatPanelChangedHandler)
.setMigrationHandler(barGaugePanelMigrationHandler);
@@ -75,9 +75,68 @@ describe('Gauge Panel Migrations', () => {
timeShift: null,
title: 'Panel Title',
type: 'gauge',
} as PanelModel;
} as Omit<PanelModel, 'fieldConfig'>;
expect(gaugePanelMigrationHandler(panel)).toMatchSnapshot();
const result = gaugePanelMigrationHandler(panel as PanelModel);
expect(result).toMatchSnapshot();
// Ignored due to the API change
//@ts-ignore
expect(result.fieldOptions.defaults).toBeUndefined();
// Ignored due to the API change
//@ts-ignore
expect(result.fieldOptions.overrides).toBeUndefined();
expect((panel as PanelModel).fieldConfig).toMatchInlineSnapshot(`
Object {
"defaults": Object {
"color": Object {
"mode": "thresholds",
},
"decimals": 3,
"mappings": Array [
Object {
"from": "50",
"id": 1,
"operator": "",
"text": "BIG",
"to": "1000",
"type": 2,
"value": "",
},
],
"max": "50",
"min": "-50",
"thresholds": Object {
"mode": "absolute",
"steps": Array [
Object {
"color": "green",
"index": 0,
"value": -Infinity,
},
Object {
"color": "#EAB839",
"index": 1,
"value": -25,
},
Object {
"color": "#6ED0E0",
"index": 2,
"value": 0,
},
Object {
"color": "red",
"index": 3,
"value": 25,
},
],
},
"unit": "accMS2",
},
"overrides": Array [],
}
`);
});
it('change from angular singlestat to gauge', () => {
@@ -95,11 +154,12 @@ describe('Gauge Panel Migrations', () => {
},
};
const newOptions = gaugePanelChangedHandler({} as any, 'singlestat', old);
expect(newOptions.fieldOptions.defaults.unit).toBe('ms');
expect(newOptions.fieldOptions.defaults.min).toBe(-10);
expect(newOptions.fieldOptions.defaults.max).toBe(150);
expect(newOptions.fieldOptions.defaults.decimals).toBe(7);
const panel = {} as PanelModel;
const newOptions = gaugePanelChangedHandler(panel, 'singlestat', old);
expect(panel.fieldConfig.defaults.unit).toBe('ms');
expect(panel.fieldConfig.defaults.min).toBe(-10);
expect(panel.fieldConfig.defaults.max).toBe(150);
expect(panel.fieldConfig.defaults.decimals).toBe(7);
expect(newOptions.showThresholdMarkers).toBe(true);
expect(newOptions.showThresholdLabels).toBe(true);
});
@@ -116,10 +176,10 @@ describe('Gauge Panel Migrations', () => {
},
},
};
const newOptions = gaugePanelChangedHandler({} as any, 'singlestat', old);
expect(newOptions.fieldOptions.defaults.unit).toBe('ms');
expect(newOptions.fieldOptions.defaults.min).toBe(undefined);
expect(newOptions.fieldOptions.defaults.max).toBe(undefined);
const panel = {} as PanelModel;
gaugePanelChangedHandler(panel, 'singlestat', old);
expect(panel.fieldConfig.defaults.unit).toBe('ms');
expect(panel.fieldConfig.defaults.min).toBe(undefined);
expect(panel.fieldConfig.defaults.max).toBe(undefined);
});
});
@@ -40,8 +40,9 @@ export class GaugePanel extends PureComponent<PanelProps<GaugeOptions>> {
};
getValues = (): FieldDisplay[] => {
const { data, options, replaceVariables } = this.props;
const { data, options, replaceVariables, fieldConfig } = this.props;
return getFieldDisplayValues({
fieldConfig,
fieldOptions: options.fieldOptions,
replaceVariables,
theme: config.theme,
@@ -1,29 +1,29 @@
// Libraries
import React, { PureComponent } from 'react';
import {
ThresholdsEditor,
PanelOptionsGrid,
ValueMappingsEditor,
FieldDisplayEditor,
FieldPropertiesEditor,
Switch,
PanelOptionsGroup,
FieldPropertiesEditor,
ThresholdsEditor,
LegacyValueMappingsEditor,
DataLinksEditor,
} from '@grafana/ui';
import {
PanelEditorProps,
FieldDisplayOptions,
ThresholdsConfig,
ValueMapping,
FieldConfig,
DataLink,
FieldConfig,
ValueMapping,
} from '@grafana/data';
import { GaugeOptions } from './types';
import {
getCalculationValueDataLinksVariableSuggestions,
getDataLinksVariableSuggestions,
} from 'app/features/panel/panellinks/link_srv';
} from '../../../features/panel/panellinks/link_srv';
export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOptions>> {
labelWidth = 6;
@@ -37,27 +37,11 @@ export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOption
showThresholdMarkers: !this.props.options.showThresholdMarkers,
});
onThresholdsChanged = (thresholds: ThresholdsConfig) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
...current,
thresholds,
});
};
onValueMappingsChanged = (mappings: ValueMapping[]) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
...current,
mappings,
});
};
onDisplayOptionsChanged = (
fieldOptions: FieldDisplayOptions,
event?: React.SyntheticEvent<HTMLElement>,
callback?: () => void
) =>
) => {
this.props.onOptionsChange(
{
...this.props.options,
@@ -65,38 +49,57 @@ export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOption
},
callback
);
onDefaultsChange = (field: FieldConfig, event?: React.SyntheticEvent<HTMLElement>, callback?: () => void) => {
this.onDisplayOptionsChanged(
{
...this.props.options.fieldOptions,
defaults: field,
},
event,
callback
);
};
onDataLinksChanged = (links: DataLink[], callback?: () => void) => {
this.onDefaultsChange(
{
...this.props.options.fieldOptions.defaults,
onThresholdsChanged = (thresholds: ThresholdsConfig) => {
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
thresholds,
},
});
};
onValueMappingsChanged = (mappings: ValueMapping[]) => {
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
mappings,
},
});
};
onDataLinksChanged = (links: DataLink[]) => {
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
links,
},
undefined,
callback
);
});
};
onDefaultsChange = (field: FieldConfig) => {
this.props.onFieldConfigChange({
...this.props.fieldConfig,
defaults: field,
});
};
render() {
const { options } = this.props;
const { fieldOptions, showThresholdLabels, showThresholdMarkers } = options;
const { defaults } = fieldOptions;
const { options, fieldConfig } = this.props;
const { showThresholdLabels, showThresholdMarkers, fieldOptions } = options;
const { defaults } = fieldConfig;
const suggestions = fieldOptions.values
? getDataLinksVariableSuggestions(this.props.data.series)
: getCalculationValueDataLinksVariableSuggestions(this.props.data.series);
return (
<>
<PanelOptionsGrid>
@@ -128,11 +131,9 @@ export class GaugePanelEditor extends PureComponent<PanelEditorProps<GaugeOption
value={defaults}
/>
</PanelOptionsGroup>
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={defaults.thresholds} />
</PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<LegacyValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<PanelOptionsGroup title="Data links">
<DataLinksEditor
@@ -6,51 +6,6 @@ Object {
"calcs": Array [
"last",
],
"defaults": Object {
"color": Object {
"mode": "thresholds",
},
"decimals": 3,
"mappings": Array [
Object {
"from": "50",
"id": 1,
"operator": "",
"text": "BIG",
"to": "1000",
"type": 2,
"value": "",
},
],
"max": "50",
"min": "-50",
"thresholds": Object {
"mode": "absolute",
"steps": Array [
Object {
"color": "green",
"index": 0,
"value": -Infinity,
},
Object {
"color": "#EAB839",
"index": 1,
"value": -25,
},
Object {
"color": "#6ED0E0",
"index": 2,
"value": 0,
},
Object {
"color": "red",
"index": 3,
"value": 25,
},
],
},
"unit": "accMS2",
},
},
"orientation": "auto",
"showThresholdLabels": true,
@@ -2,10 +2,12 @@ import { PanelPlugin } from '@grafana/data';
import { GaugePanelEditor } from './GaugePanelEditor';
import { GaugePanel } from './GaugePanel';
import { GaugeOptions, defaults } from './types';
import { standardFieldConfig } from '../stat/types';
import { gaugePanelMigrationHandler, gaugePanelChangedHandler } from './GaugeMigrations';
export const plugin = new PanelPlugin<GaugeOptions>(GaugePanel)
.setDefaults(defaults)
.setFieldConfigDefaults(standardFieldConfig)
.setEditor(GaugePanelEditor)
.setPanelChangeHandler(gaugePanelChangedHandler)
.setMigrationHandler(gaugePanelMigrationHandler);
@@ -14,6 +14,7 @@ export const GraphPanel: React.FunctionComponent<GraphPanelProps> = ({
width,
height,
options,
fieldConfig,
onOptionsChange,
onChangeTimeRange,
}) => {
@@ -43,6 +44,7 @@ export const GraphPanel: React.FunctionComponent<GraphPanelProps> = ({
data={data}
timeZone={timeZone}
options={options}
fieldConfig={fieldConfig}
onOptionsChange={onOptionsChange}
onChangeTimeRange={onChangeTimeRange}
>
@@ -1,6 +1,6 @@
import React from 'react';
import { GraphSeriesToggler } from '@grafana/ui';
import { PanelData, GraphSeriesXY, AbsoluteTimeRange, TimeZone } from '@grafana/data';
import { PanelData, GraphSeriesXY, AbsoluteTimeRange, TimeZone, FieldConfigSource } from '@grafana/data';
import { getGraphSeriesModel } from './getGraphSeriesModel';
import { Options, SeriesOptions } from './types';
@@ -18,6 +18,7 @@ interface GraphPanelControllerAPI {
interface GraphPanelControllerProps {
children: (api: GraphPanelControllerAPI) => JSX.Element;
options: Options;
fieldConfig: FieldConfigSource;
data: PanelData;
timeZone: TimeZone;
onOptionsChange: (options: Options) => void;
@@ -44,7 +45,7 @@ export class GraphPanelController extends React.Component<GraphPanelControllerPr
props.options.series,
props.options.graph,
props.options.legend,
props.options.fieldOptions
props.fieldConfig
),
};
}
@@ -58,7 +59,7 @@ export class GraphPanelController extends React.Component<GraphPanelControllerPr
props.options.series,
props.options.graph,
props.options.legend,
props.options.fieldOptions
props.fieldConfig
),
};
}
@@ -3,15 +3,15 @@ import _ from 'lodash';
import React, { PureComponent } from 'react';
// Types
import { PanelEditorProps, FieldConfig } from '@grafana/data';
import { FieldConfig, PanelEditorProps } from '@grafana/data';
import {
Switch,
LegendOptions,
GraphTooltipOptions,
PanelOptionsGrid,
PanelOptionsGroup,
FieldPropertiesEditor,
Select,
FieldPropertiesEditor,
} from '@grafana/ui';
import { Options, GraphOptions } from './types';
import { GraphLegendEditor } from './GraphLegendEditor';
@@ -47,13 +47,10 @@ export class GraphPanelEditor extends PureComponent<PanelEditorProps<Options>> {
this.onGraphOptionsChange({ showPoints: !this.props.options.graph.showPoints });
};
onDefaultsChange = (field: FieldConfig) => {
this.props.onOptionsChange({
...this.props.options,
fieldOptions: {
...this.props.options.fieldOptions,
defaults: field,
},
onDefaultsChange = (field: FieldConfig, event?: React.SyntheticEvent<HTMLElement>, callback?: () => void) => {
this.props.onFieldConfigChange({
...this.props.fieldConfig,
defaults: field,
});
};
@@ -76,7 +73,7 @@ export class GraphPanelEditor extends PureComponent<PanelEditorProps<Options>> {
<FieldPropertiesEditor
showMinMax={false}
onChange={this.onDefaultsChange}
value={this.props.options.fieldOptions.defaults}
value={this.props.fieldConfig.defaults}
/>
</PanelOptionsGroup>
<PanelOptionsGroup title="Tooltip">
@@ -9,7 +9,6 @@ import {
GraphSeriesXY,
getTimeField,
DataFrame,
FieldDisplayOptions,
getSeriesTimeStep,
TimeZone,
hasMsResolution,
@@ -17,6 +16,7 @@ import {
DEFAULT_DATE_TIME_FORMAT,
FieldColor,
FieldColorMode,
FieldConfigSource,
} from '@grafana/data';
import { SeriesOptions, GraphOptions } from './types';
@@ -28,7 +28,7 @@ export const getGraphSeriesModel = (
seriesOptions: SeriesOptions,
graphOptions: GraphOptions,
legendOptions: GraphLegendEditorLegendOptions,
fieldOptions?: FieldDisplayOptions
fieldOptions?: FieldConfigSource
) => {
const graphs: GraphSeriesXY[] = [];
@@ -16,9 +16,10 @@ interface Props extends PanelProps<PieChartOptions> {}
export class PieChartPanel extends PureComponent<Props> {
render() {
const { width, height, options, data, replaceVariables } = this.props;
const { width, height, options, data, replaceVariables, fieldConfig } = this.props;
const values = getFieldDisplayValues({
fieldConfig,
fieldOptions: options.fieldOptions,
data: data.series,
theme: config.theme,
@@ -1,22 +1,25 @@
import React, { PureComponent } from 'react';
import {
PanelOptionsGrid,
ValueMappingsEditor,
FieldDisplayEditor,
FieldPropertiesEditor,
PanelOptionsGroup,
FieldPropertiesEditor,
LegacyValueMappingsEditor,
} from '@grafana/ui';
import { ValueMapping, FieldConfig, PanelEditorProps, FieldDisplayOptions } from '@grafana/data';
import { PanelEditorProps, FieldDisplayOptions, ValueMapping, FieldConfig } from '@grafana/data';
import { PieChartOptionsBox } from './PieChartOptionsBox';
import { PieChartOptions } from './types';
export class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChartOptions>> {
onValueMappingsChanged = (mappings: ValueMapping[]) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
mappings,
defaults: {
...current.defaults,
mappings,
},
});
};
@@ -27,16 +30,16 @@ export class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChart
});
onDefaultsChange = (field: FieldConfig) => {
this.onDisplayOptionsChanged({
...this.props.options.fieldOptions,
this.props.onFieldConfigChange({
...this.props.fieldConfig,
defaults: field,
});
};
render() {
const { onOptionsChange, options, data } = this.props;
const { onOptionsChange, options, data, fieldConfig, onFieldConfigChange } = this.props;
const { fieldOptions } = options;
const { defaults } = fieldOptions;
const { defaults } = fieldConfig;
return (
<>
@@ -49,10 +52,15 @@ export class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChart
<FieldPropertiesEditor showMinMax={true} onChange={this.onDefaultsChange} value={defaults} />
</PanelOptionsGroup>
<PieChartOptionsBox data={data} onOptionsChange={onOptionsChange} options={options} />
<PieChartOptionsBox
data={data}
onOptionsChange={onOptionsChange}
options={options}
fieldConfig={fieldConfig}
onFieldConfigChange={onFieldConfigChange}
/>
</PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<LegacyValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
</>
);
}
@@ -5,4 +5,5 @@ import { PieChartOptions, defaults } from './types';
export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel)
.setDefaults(defaults)
.setFieldConfigDefaults({ defaults: { unit: 'short' } })
.setEditor(PieChartPanelEditor);
@@ -14,8 +14,5 @@ export const defaults: PieChartOptions = {
fieldOptions: {
...standardFieldDisplayOptions,
calcs: [ReducerID.last],
defaults: {
unit: 'short',
},
},
};
+3 -2
View File
@@ -69,10 +69,11 @@ export class StatPanel extends PureComponent<PanelProps<StatPanelOptions>> {
};
getValues = (): FieldDisplay[] => {
const { data, options, replaceVariables } = this.props;
const { data, options, replaceVariables, fieldConfig } = this.props;
return getFieldDisplayValues({
...options,
fieldConfig,
fieldOptions: options.fieldOptions,
replaceVariables,
theme: config.theme,
data: data.series,
@@ -2,48 +2,53 @@
import React, { PureComponent } from 'react';
import {
ThresholdsEditor,
PanelOptionsGrid,
ValueMappingsEditor,
FieldDisplayEditor,
FieldPropertiesEditor,
PanelOptionsGroup,
DataLinksEditor,
FormLabel,
Select,
FieldPropertiesEditor,
ThresholdsEditor,
LegacyValueMappingsEditor,
DataLinksEditor,
} from '@grafana/ui';
import {
ThresholdsConfig,
ValueMapping,
FieldConfig,
DataLink,
PanelEditorProps,
FieldDisplayOptions,
FieldConfig,
ValueMapping,
ThresholdsConfig,
DataLink,
} from '@grafana/data';
import { StatPanelOptions, colorModes, graphModes, justifyModes } from './types';
import { orientationOptions } from '../gauge/types';
import {
getDataLinksVariableSuggestions,
getCalculationValueDataLinksVariableSuggestions,
} from 'app/features/panel/panellinks/link_srv';
getDataLinksVariableSuggestions,
} from '../../../features/panel/panellinks/link_srv';
export class StatPanelEditor extends PureComponent<PanelEditorProps<StatPanelOptions>> {
onThresholdsChanged = (thresholds: ThresholdsConfig) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
thresholds,
defaults: {
...current.defaults,
thresholds,
},
});
};
onValueMappingsChanged = (mappings: ValueMapping[]) => {
const current = this.props.options.fieldOptions.defaults;
this.onDefaultsChange({
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
mappings,
defaults: {
...current.defaults,
mappings,
},
});
};
@@ -59,23 +64,28 @@ export class StatPanelEditor extends PureComponent<PanelEditorProps<StatPanelOpt
onOrientationChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, orientation: value });
onDefaultsChange = (field: FieldConfig) => {
this.onDisplayOptionsChanged({
...this.props.options.fieldOptions,
this.props.onFieldConfigChange({
...this.props.fieldConfig,
defaults: field,
});
};
onDataLinksChanged = (links: DataLink[]) => {
this.onDefaultsChange({
...this.props.options.fieldOptions.defaults,
links,
const current = this.props.fieldConfig;
this.props.onFieldConfigChange({
...current,
defaults: {
...current.defaults,
links,
},
});
};
render() {
const { options } = this.props;
const { options, fieldConfig } = this.props;
const { fieldOptions } = options;
const { defaults } = fieldOptions;
const { defaults } = fieldConfig;
const suggestions = fieldOptions.values
? getDataLinksVariableSuggestions(this.props.data.series)
: getCalculationValueDataLinksVariableSuggestions(this.props.data.series);
@@ -126,7 +136,6 @@ export class StatPanelEditor extends PureComponent<PanelEditorProps<StatPanelOpt
/>
</div>
</PanelOptionsGroup>
<PanelOptionsGroup title="Field">
<FieldPropertiesEditor
showMinMax={true}
@@ -138,8 +147,7 @@ export class StatPanelEditor extends PureComponent<PanelEditorProps<StatPanelOpt
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={defaults.thresholds} />
</PanelOptionsGrid>
<ValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<LegacyValueMappingsEditor onChange={this.onValueMappingsChanged} valueMappings={defaults.mappings} />
<PanelOptionsGroup title="Data links">
<DataLinksEditor
+2 -1
View File
@@ -1,11 +1,12 @@
import { sharedSingleStatMigrationHandler, sharedSingleStatPanelChangedHandler } from '@grafana/ui';
import { PanelPlugin } from '@grafana/data';
import { StatPanelOptions, defaults } from './types';
import { StatPanelOptions, defaults, standardFieldConfig } from './types';
import { StatPanel } from './StatPanel';
import { StatPanelEditor } from './StatPanelEditor';
export const plugin = new PanelPlugin<StatPanelOptions>(StatPanel)
.setDefaults(defaults)
.setFieldConfigDefaults(standardFieldConfig)
.setEditor(StatPanelEditor)
.setNoPadding()
.setPanelChangeHandler(sharedSingleStatPanelChangedHandler)
+11 -1
View File
@@ -1,5 +1,12 @@
import { SingleStatBaseOptions, BigValueColorMode, BigValueGraphMode, BigValueJustifyMode } from '@grafana/ui';
import { VizOrientation, ReducerID, FieldDisplayOptions, SelectableValue, ThresholdsMode } from '@grafana/data';
import {
VizOrientation,
ReducerID,
FieldDisplayOptions,
SelectableValue,
FieldConfigSource,
ThresholdsMode,
} from '@grafana/data';
// Structure copied from angular
export interface StatPanelOptions extends SingleStatBaseOptions {
@@ -26,6 +33,9 @@ export const justifyModes: Array<SelectableValue<BigValueJustifyMode>> = [
export const standardFieldDisplayOptions: FieldDisplayOptions = {
values: false,
calcs: [ReducerID.mean],
};
export const standardFieldConfig: FieldConfigSource = {
defaults: {
thresholds: {
mode: ThresholdsMode.Absolute,
-7
View File
@@ -1,14 +1,7 @@
import { FieldConfigSource } from '@grafana/data';
export interface Options {
fieldOptions: FieldConfigSource;
showHeader: boolean;
}
export const defaults: Options = {
fieldOptions: {
defaults: {},
overrides: [],
},
showHeader: true,
};