mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
NewPanelEditor: Options/FieldConfig API for defaults and common options selection (#23214)
* Add "some" typesafety to panel options/field config APIs * Allow selected common field config properties config, allow option defaults config via fluent API * Update packages/grafana-data/src/panel/PanelPlugin.ts Co-Authored-By: Ryan McKinley <ryantxu@gmail.com> * Add defaults support for custom field config * Enable defaults setting for standard and custom field configs * Remove setFieldConfigDefaults from PanelPlugin API and replace it with useStandardFieldConfig * Update API for standard field config defaults Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
parent
a92bcb78a5
commit
dcf6bbc14f
@ -67,6 +67,9 @@ export const stringOverrideProcessor = (
|
||||
context: FieldOverrideContext,
|
||||
settings?: StringFieldConfigSettings
|
||||
) => {
|
||||
if (value === null || value === undefined) {
|
||||
return value;
|
||||
}
|
||||
if (settings && settings.expandTemplateVars && context.replaceVariables) {
|
||||
return context.replaceVariables(value, context.field!.config.scopedVars);
|
||||
}
|
||||
|
@ -12,4 +12,4 @@ export * from './datetime';
|
||||
export * from './text';
|
||||
export * from './valueFormats';
|
||||
export * from './field';
|
||||
export { PanelPlugin } from './panel/PanelPlugin';
|
||||
export { PanelPlugin, defaultStandardFieldConfigProperties } from './panel/PanelPlugin';
|
||||
|
@ -1,9 +1,19 @@
|
||||
import React from 'react';
|
||||
import { identityOverrideProcessor } from '../field';
|
||||
import { PanelPlugin } from './PanelPlugin';
|
||||
import { identityOverrideProcessor, standardEditorsRegistry } from '../field';
|
||||
import { PanelPlugin, standardFieldConfigProperties } from './PanelPlugin';
|
||||
import { StandardFieldConfigProperties } from '../types';
|
||||
|
||||
describe('PanelPlugin', () => {
|
||||
describe('declarative options', () => {
|
||||
beforeAll(() => {
|
||||
standardEditorsRegistry.setInit(() => {
|
||||
return [
|
||||
{
|
||||
id: 'number',
|
||||
},
|
||||
] as any;
|
||||
});
|
||||
});
|
||||
test('field config UI API', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
@ -45,4 +55,190 @@ describe('PanelPlugin', () => {
|
||||
expect(panel.optionEditors!.list()).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('default options', () => {
|
||||
describe('panel options', () => {
|
||||
test('default values', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.setPanelOptions(builder => {
|
||||
builder
|
||||
.addNumberInput({
|
||||
id: 'numericOption',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
defaultValue: 10,
|
||||
})
|
||||
.addNumberInput({
|
||||
id: 'numericOptionNoDefault',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'customOption',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
editor: () => <div>Editor</div>,
|
||||
settings: {},
|
||||
defaultValue: { value: 'Custom default value' },
|
||||
});
|
||||
});
|
||||
|
||||
const expectedDefaults = {
|
||||
numericOption: 10,
|
||||
customOption: { value: 'Custom default value' },
|
||||
};
|
||||
|
||||
expect(panel.defaults).toEqual(expectedDefaults);
|
||||
});
|
||||
|
||||
test('default values for nested paths', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.setPanelOptions(builder => {
|
||||
builder.addNumberInput({
|
||||
id: 'numericOption.nested',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
defaultValue: 10,
|
||||
});
|
||||
});
|
||||
|
||||
const expectedDefaults = {
|
||||
numericOption: { nested: 10 },
|
||||
};
|
||||
|
||||
expect(panel.defaults).toEqual(expectedDefaults);
|
||||
});
|
||||
});
|
||||
|
||||
describe('field config options', () => {
|
||||
test('default values', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.setCustomFieldOptions(builder => {
|
||||
builder
|
||||
.addNumberInput({
|
||||
id: 'numericOption',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
defaultValue: 10,
|
||||
})
|
||||
.addNumberInput({
|
||||
id: 'numericOptionNoDefault',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'customOption',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
editor: () => <div>Editor</div>,
|
||||
override: () => <div>Override editor</div>,
|
||||
process: identityOverrideProcessor,
|
||||
shouldApply: () => true,
|
||||
settings: {},
|
||||
defaultValue: { value: 'Custom default value' },
|
||||
});
|
||||
});
|
||||
|
||||
const expectedDefaults = {
|
||||
numericOption: 10,
|
||||
customOption: { value: 'Custom default value' },
|
||||
};
|
||||
|
||||
expect(panel.fieldConfigDefaults.defaults.custom).toEqual(expectedDefaults);
|
||||
});
|
||||
|
||||
test('default values for nested paths', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.setCustomFieldOptions(builder => {
|
||||
builder.addNumberInput({
|
||||
id: 'numericOption.nested',
|
||||
name: 'Option editor',
|
||||
description: 'Option editor description',
|
||||
defaultValue: 10,
|
||||
});
|
||||
});
|
||||
|
||||
const expectedDefaults = {
|
||||
numericOption: { nested: 10 },
|
||||
};
|
||||
|
||||
expect(panel.fieldConfigDefaults.defaults.custom).toEqual(expectedDefaults);
|
||||
});
|
||||
});
|
||||
|
||||
describe('standard field config options', () => {
|
||||
test('standard config', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.useStandardFieldConfig();
|
||||
expect(panel.standardFieldConfigProperties).toEqual(Array.from(standardFieldConfigProperties.keys()));
|
||||
});
|
||||
|
||||
test('selected standard config', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.useStandardFieldConfig([StandardFieldConfigProperties.Min, StandardFieldConfigProperties.Thresholds]);
|
||||
expect(panel.standardFieldConfigProperties).toEqual(['min', 'thresholds']);
|
||||
});
|
||||
|
||||
describe('default values', () => {
|
||||
test('setting default values', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.useStandardFieldConfig([StandardFieldConfigProperties.Color, StandardFieldConfigProperties.Min], {
|
||||
[StandardFieldConfigProperties.Color]: '#ff00ff',
|
||||
[StandardFieldConfigProperties.Min]: 10,
|
||||
});
|
||||
|
||||
expect(panel.standardFieldConfigProperties).toEqual(['color', 'min']);
|
||||
|
||||
expect(panel.fieldConfigDefaults).toEqual({
|
||||
defaults: {
|
||||
min: 10,
|
||||
color: '#ff00ff',
|
||||
},
|
||||
overrides: [],
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore defaults that are not specified as availeble properties', () => {
|
||||
const panel = new PanelPlugin(() => {
|
||||
return <div>Panel</div>;
|
||||
});
|
||||
|
||||
panel.useStandardFieldConfig([StandardFieldConfigProperties.Color], {
|
||||
[StandardFieldConfigProperties.Color]: '#ff00ff',
|
||||
[StandardFieldConfigProperties.Min]: 10,
|
||||
});
|
||||
|
||||
expect(panel.standardFieldConfigProperties).toEqual(['color']);
|
||||
|
||||
expect(panel.fieldConfigDefaults).toEqual({
|
||||
defaults: {
|
||||
color: '#ff00ff',
|
||||
},
|
||||
overrides: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -8,26 +8,48 @@ import {
|
||||
PanelPluginMeta,
|
||||
PanelProps,
|
||||
PanelTypeChangedHandler,
|
||||
StandardFieldConfigProperties,
|
||||
} from '../types';
|
||||
import { FieldConfigEditorBuilder, PanelOptionsEditorBuilder } from '../utils/OptionsUIBuilders';
|
||||
import { ComponentClass, ComponentType } from 'react';
|
||||
import set from 'lodash/set';
|
||||
import { deprecationWarning } from '../utils';
|
||||
|
||||
export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta> {
|
||||
private customFieldConfigsUIBuilder = new FieldConfigEditorBuilder();
|
||||
private _customFieldConfigs?: FieldConfigEditorRegistry;
|
||||
private registerCustomFieldConfigs?: (builder: FieldConfigEditorBuilder) => void;
|
||||
export const defaultStandardFieldConfigProperties: StandardFieldConfigProperties[] = [
|
||||
StandardFieldConfigProperties.Min,
|
||||
StandardFieldConfigProperties.Max,
|
||||
StandardFieldConfigProperties.Title,
|
||||
StandardFieldConfigProperties.Unit,
|
||||
StandardFieldConfigProperties.Decimals,
|
||||
StandardFieldConfigProperties.NoValue,
|
||||
StandardFieldConfigProperties.Color,
|
||||
StandardFieldConfigProperties.Thresholds,
|
||||
StandardFieldConfigProperties.Mappings,
|
||||
StandardFieldConfigProperties.Links,
|
||||
];
|
||||
|
||||
private optionsUIBuilder = new PanelOptionsEditorBuilder();
|
||||
private _optionEditors?: PanelOptionEditorsRegistry;
|
||||
private registerOptionEditors?: (builder: PanelOptionsEditorBuilder) => void;
|
||||
export const standardFieldConfigProperties = new Map(defaultStandardFieldConfigProperties.map(p => [p, undefined]));
|
||||
|
||||
panel: ComponentType<PanelProps<TOptions>>;
|
||||
editor?: ComponentClass<PanelEditorProps<TOptions>>;
|
||||
defaults?: TOptions;
|
||||
fieldConfigDefaults?: FieldConfigSource = {
|
||||
export class PanelPlugin<TOptions = any, TFieldConfigOptions extends object = any> extends GrafanaPlugin<
|
||||
PanelPluginMeta
|
||||
> {
|
||||
private _defaults?: TOptions;
|
||||
private _standardFieldConfigProperties?: Map<StandardFieldConfigProperties, any>;
|
||||
|
||||
private _fieldConfigDefaults: FieldConfigSource<TFieldConfigOptions> = {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
};
|
||||
private _customFieldConfigs?: FieldConfigEditorRegistry;
|
||||
private customFieldConfigsUIBuilder = new FieldConfigEditorBuilder<TFieldConfigOptions>();
|
||||
private registerCustomFieldConfigs?: (builder: FieldConfigEditorBuilder<TFieldConfigOptions>) => void;
|
||||
|
||||
private _optionEditors?: PanelOptionEditorsRegistry;
|
||||
private optionsUIBuilder = new PanelOptionsEditorBuilder<TOptions>();
|
||||
private registerOptionEditors?: (builder: PanelOptionsEditorBuilder<TOptions>) => void;
|
||||
|
||||
panel: ComponentType<PanelProps<TOptions>>;
|
||||
editor?: ComponentClass<PanelEditorProps<TOptions>>;
|
||||
onPanelMigration?: PanelMigrationHandler<TOptions>;
|
||||
onPanelTypeChanged?: PanelTypeChangedHandler<TOptions>;
|
||||
noPadding?: boolean;
|
||||
@ -42,6 +64,66 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
|
||||
this.panel = panel;
|
||||
}
|
||||
|
||||
get defaults() {
|
||||
let result = this._defaults || {};
|
||||
|
||||
if (!this._defaults) {
|
||||
const editors = this.optionEditors;
|
||||
|
||||
if (!editors || editors.list().length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const editor of editors.list()) {
|
||||
set(result, editor.id, editor.defaultValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
get fieldConfigDefaults(): FieldConfigSource<TFieldConfigOptions> {
|
||||
let customPropertiesDefaults = this._fieldConfigDefaults.defaults.custom;
|
||||
|
||||
if (!customPropertiesDefaults) {
|
||||
customPropertiesDefaults = {} as TFieldConfigOptions;
|
||||
}
|
||||
const editors = this.customFieldConfigs;
|
||||
|
||||
if (editors && editors.list().length !== 0) {
|
||||
for (const editor of editors.list()) {
|
||||
set(customPropertiesDefaults, editor.id, editor.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
defaults: {
|
||||
...(this._standardFieldConfigProperties ? Object.fromEntries(this._standardFieldConfigProperties) : {}),
|
||||
custom:
|
||||
Object.keys(customPropertiesDefaults).length > 0
|
||||
? {
|
||||
...customPropertiesDefaults,
|
||||
}
|
||||
: undefined,
|
||||
...this._fieldConfigDefaults.defaults,
|
||||
},
|
||||
// TODO: not sure yet what about overrides, if anything
|
||||
overrides: this._fieldConfigDefaults.overrides,
|
||||
};
|
||||
}
|
||||
|
||||
get standardFieldConfigProperties() {
|
||||
return this._standardFieldConfigProperties ? Array.from(this._standardFieldConfigProperties.keys()) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated setDefaults is deprecated in favor of setPanelOptions
|
||||
*/
|
||||
setDefaults(defaults: TOptions) {
|
||||
deprecationWarning('PanelPlugin', 'setDefaults', 'setPanelOptions');
|
||||
this._defaults = defaults;
|
||||
return this;
|
||||
}
|
||||
|
||||
get customFieldConfigs() {
|
||||
if (!this._customFieldConfigs && this.registerCustomFieldConfigs) {
|
||||
this.registerCustomFieldConfigs(this.customFieldConfigsUIBuilder);
|
||||
@ -65,11 +147,6 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
|
||||
return this;
|
||||
}
|
||||
|
||||
setDefaults(defaults: TOptions) {
|
||||
this.defaults = defaults;
|
||||
return this;
|
||||
}
|
||||
|
||||
setNoPadding() {
|
||||
this.noPadding = true;
|
||||
return this;
|
||||
@ -134,7 +211,7 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
|
||||
*
|
||||
* @public
|
||||
**/
|
||||
setCustomFieldOptions(builder: (builder: FieldConfigEditorBuilder) => void) {
|
||||
setCustomFieldOptions(builder: (builder: FieldConfigEditorBuilder<TFieldConfigOptions>) => void) {
|
||||
// builder is applied lazily when custom field configs are accessed
|
||||
this.registerCustomFieldConfigs = builder;
|
||||
return this;
|
||||
@ -170,22 +247,63 @@ export class PanelPlugin<TOptions = any> extends GrafanaPlugin<PanelPluginMeta>
|
||||
*
|
||||
* @public
|
||||
**/
|
||||
setPanelOptions(builder: (builder: PanelOptionsEditorBuilder) => void) {
|
||||
setPanelOptions(builder: (builder: PanelOptionsEditorBuilder<TOptions>) => void) {
|
||||
// builder is applied lazily when options UI is created
|
||||
this.registerOptionEditors = builder;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables configuration of panel's default field config
|
||||
* Allows specyfing which standard field config options panel should use and defining default values
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
*
|
||||
* import { ShapePanel } from './ShapePanel';
|
||||
*
|
||||
* interface ShapePanelOptions {}
|
||||
*
|
||||
* // when plugin should use all standard options
|
||||
* export const plugin = new PanelPlugin<ShapePanelOptions>(ShapePanel)
|
||||
* .useStandardFieldConfig();
|
||||
*
|
||||
* // when plugin should only display specific standard options
|
||||
* // note, that options will be displayed in the order they are provided
|
||||
* export const plugin = new PanelPlugin<ShapePanelOptions>(ShapePanel)
|
||||
* .useStandardFieldConfig([StandardFieldConfigProperties.Min, StandardFieldConfigProperties.Max, StandardFieldConfigProperties.Links]);
|
||||
*
|
||||
* // when standard option's default value needs to be provided
|
||||
* export const plugin = new PanelPlugin<ShapePanelOptions>(ShapePanel)
|
||||
* .useStandardFieldConfig([StandardFieldConfigProperties.Min, StandardFieldConfigProperties.Max], {
|
||||
* [StandardFieldConfigProperties.Min]: 20,
|
||||
* [StandardFieldConfigProperties.Max]: 100
|
||||
* });
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
setFieldConfigDefaults(defaultConfig: Partial<FieldConfigSource>) {
|
||||
this.fieldConfigDefaults = {
|
||||
defaults: {},
|
||||
overrides: [],
|
||||
...defaultConfig,
|
||||
};
|
||||
useStandardFieldConfig(
|
||||
properties?: StandardFieldConfigProperties[],
|
||||
defauls?: Partial<Record<StandardFieldConfigProperties, any>>
|
||||
) {
|
||||
if (!properties) {
|
||||
this._standardFieldConfigProperties = standardFieldConfigProperties;
|
||||
return this;
|
||||
} else {
|
||||
this._standardFieldConfigProperties = new Map(properties.map(p => [p, standardFieldConfigProperties.get(p)]));
|
||||
}
|
||||
|
||||
if (defauls) {
|
||||
Object.keys(defauls).map(k => {
|
||||
if (properties.indexOf(k as StandardFieldConfigProperties) > -1) {
|
||||
this._standardFieldConfigProperties!.set(
|
||||
k as StandardFieldConfigProperties,
|
||||
defauls[k as StandardFieldConfigProperties]
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -5,52 +5,59 @@ import { NumberFieldConfigSettings, SelectFieldConfigSettings, StringFieldConfig
|
||||
/**
|
||||
* Option editor registry item
|
||||
*/
|
||||
export interface OptionsEditorItem<TSettings, TEditorProps> extends RegistryItem {
|
||||
export interface OptionsEditorItem<TOptions, TSettings, TEditorProps, TValue> extends RegistryItem {
|
||||
id: (keyof TOptions & string) | string;
|
||||
editor: ComponentType<TEditorProps>;
|
||||
settings?: TSettings;
|
||||
defaultValue?: TValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration of option editor registry item
|
||||
*/
|
||||
interface OptionEditorConfig<TSettings> {
|
||||
id: string;
|
||||
interface OptionEditorConfig<TOptions, TSettings, TValue = any> {
|
||||
id: keyof TOptions & string;
|
||||
name: string;
|
||||
description: string;
|
||||
settings?: TSettings;
|
||||
defaultValue?: TValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes an API for option editors UI builder
|
||||
*/
|
||||
export interface OptionsUIRegistryBuilderAPI<TEditorProps, T extends OptionsEditorItem<any, TEditorProps>> {
|
||||
export interface OptionsUIRegistryBuilderAPI<
|
||||
TOptions,
|
||||
TEditorProps,
|
||||
T extends OptionsEditorItem<TOptions, any, TEditorProps, any>
|
||||
> {
|
||||
addNumberInput?<TSettings extends NumberFieldConfigSettings = NumberFieldConfigSettings>(
|
||||
config: OptionEditorConfig<TSettings>
|
||||
config: OptionEditorConfig<TOptions, TSettings, number>
|
||||
): this;
|
||||
|
||||
addTextInput?<TSettings extends StringFieldConfigSettings = StringFieldConfigSettings>(
|
||||
config: OptionEditorConfig<TSettings>
|
||||
config: OptionEditorConfig<TOptions, TSettings, string>
|
||||
): this;
|
||||
|
||||
addSelect?<TOption, TSettings extends SelectFieldConfigSettings<TOption>>(
|
||||
config: OptionEditorConfig<TSettings>
|
||||
config: OptionEditorConfig<TOptions, TSettings, TOption>
|
||||
): this;
|
||||
|
||||
addRadio?<TOption, TSettings extends SelectFieldConfigSettings<TOption> = SelectFieldConfigSettings<TOption>>(
|
||||
config: OptionEditorConfig<TSettings>
|
||||
config: OptionEditorConfig<TOptions, TSettings, TOption>
|
||||
): this;
|
||||
|
||||
addBooleanSwitch?<TSettings = any>(config: OptionEditorConfig<TSettings>): this;
|
||||
addBooleanSwitch?<TSettings = any>(config: OptionEditorConfig<TOptions, TSettings, boolean>): this;
|
||||
|
||||
addUnitPicker?<TSettings = any>(config: OptionEditorConfig<TSettings>): this;
|
||||
addUnitPicker?<TSettings = any>(config: OptionEditorConfig<TOptions, TSettings, string>): this;
|
||||
|
||||
addColorPicker?<TSettings = any>(config: OptionEditorConfig<TSettings>): this;
|
||||
addColorPicker?<TSettings = any>(config: OptionEditorConfig<TOptions, TSettings, string>): this;
|
||||
|
||||
/**
|
||||
* Enables custom editor definition
|
||||
* @param config
|
||||
*/
|
||||
addCustomEditor<TSettings>(config: OptionsEditorItem<TSettings, TEditorProps>): this;
|
||||
addCustomEditor<TSettings, TValue>(config: OptionsEditorItem<TOptions, TSettings, TEditorProps, TValue>): this;
|
||||
|
||||
/**
|
||||
* Returns registry of option editors
|
||||
@ -58,11 +65,14 @@ export interface OptionsUIRegistryBuilderAPI<TEditorProps, T extends OptionsEdit
|
||||
getRegistry: () => Registry<T>;
|
||||
}
|
||||
|
||||
export abstract class OptionsUIRegistryBuilder<TEditorProps, T extends OptionsEditorItem<any, TEditorProps>>
|
||||
implements OptionsUIRegistryBuilderAPI<TEditorProps, T> {
|
||||
export abstract class OptionsUIRegistryBuilder<
|
||||
TOptions,
|
||||
TEditorProps,
|
||||
T extends OptionsEditorItem<TOptions, any, TEditorProps, any>
|
||||
> implements OptionsUIRegistryBuilderAPI<TOptions, TEditorProps, T> {
|
||||
private properties: T[] = [];
|
||||
|
||||
addCustomEditor<TValue>(config: T & OptionsEditorItem<TValue, TEditorProps>): this {
|
||||
addCustomEditor<TSettings, TValue>(config: T & OptionsEditorItem<TOptions, TSettings, TEditorProps, TValue>): this {
|
||||
this.properties.push(config);
|
||||
return this;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ export enum FieldType {
|
||||
*
|
||||
* Plugins may extend this with additional properties. Something like series overrides
|
||||
*/
|
||||
export interface FieldConfig {
|
||||
export interface FieldConfig<TOptions extends object = any> {
|
||||
title?: string; // The display value for this field. This supports template variables blank is auto
|
||||
filterable?: boolean;
|
||||
|
||||
@ -50,7 +50,7 @@ export interface FieldConfig {
|
||||
noValue?: string;
|
||||
|
||||
// Panel Specific Values
|
||||
custom?: Record<string, any>;
|
||||
custom?: TOptions;
|
||||
|
||||
scopedVars?: ScopedVars;
|
||||
}
|
||||
|
@ -25,9 +25,9 @@ export interface ConfigOverrideRule {
|
||||
properties: DynamicConfigValue[];
|
||||
}
|
||||
|
||||
export interface FieldConfigSource {
|
||||
export interface FieldConfigSource<TOptions extends object = any> {
|
||||
// Defatuls applied to all numeric fields
|
||||
defaults: FieldConfig;
|
||||
defaults: FieldConfig<TOptions>;
|
||||
|
||||
// Rules to override individual values
|
||||
overrides: ConfigOverrideRule[];
|
||||
@ -54,16 +54,17 @@ export interface FieldOverrideEditorProps<TValue, TSettings> extends Omit<Standa
|
||||
context: FieldOverrideContext;
|
||||
}
|
||||
|
||||
export interface FieldConfigEditorConfig<TSettings = any> {
|
||||
id: string;
|
||||
export interface FieldConfigEditorConfig<TOptions, TSettings = any, TValue = any> {
|
||||
id: (keyof TOptions & string) | string;
|
||||
name: string;
|
||||
description: string;
|
||||
settings?: TSettings;
|
||||
shouldApply?: (field: Field) => boolean;
|
||||
defaultValue?: TValue;
|
||||
}
|
||||
|
||||
export interface FieldPropertyEditorItem<TValue = any, TSettings extends {} = any>
|
||||
extends OptionsEditorItem<TSettings, FieldConfigEditorProps<TValue, TSettings>> {
|
||||
export interface FieldPropertyEditorItem<TOptions = any, TValue = any, TSettings extends {} = any>
|
||||
extends OptionsEditorItem<TOptions, TSettings, FieldConfigEditorProps<TValue, TSettings>, TValue> {
|
||||
// An editor that can be filled in with context info (template variables etc)
|
||||
override: ComponentType<FieldOverrideEditorProps<TValue, TSettings>>;
|
||||
|
||||
@ -86,3 +87,16 @@ export interface ApplyFieldOverrideOptions {
|
||||
standard?: FieldConfigEditorRegistry;
|
||||
custom?: FieldConfigEditorRegistry;
|
||||
}
|
||||
|
||||
export enum StandardFieldConfigProperties {
|
||||
Unit = 'unit',
|
||||
Min = 'min',
|
||||
Max = 'max',
|
||||
Decimals = 'decimals',
|
||||
Title = 'title',
|
||||
NoValue = 'noValue',
|
||||
Thresholds = 'thresholds',
|
||||
Mappings = 'mappings',
|
||||
Links = 'links',
|
||||
Color = 'color',
|
||||
}
|
||||
|
@ -115,14 +115,15 @@ export type PanelOptionEditorsRegistry = Registry<PanelOptionsEditorItem>;
|
||||
|
||||
export interface PanelOptionsEditorProps<TValue> extends StandardEditorProps<TValue> {}
|
||||
|
||||
export interface PanelOptionsEditorItem<TValue = any, TSettings = any>
|
||||
extends OptionsEditorItem<TSettings, PanelOptionsEditorProps<TValue>> {}
|
||||
export interface PanelOptionsEditorItem<TOptions = any, TValue = any, TSettings = any>
|
||||
extends OptionsEditorItem<TOptions, TSettings, PanelOptionsEditorProps<TValue>, TValue> {}
|
||||
|
||||
export interface PanelOptionsEditorConfig<TSettings = any> {
|
||||
id: string;
|
||||
export interface PanelOptionsEditorConfig<TOptions, TSettings = any, TValue = any> {
|
||||
id: (keyof TOptions & string) | string;
|
||||
name: string;
|
||||
description: string;
|
||||
settings?: TSettings;
|
||||
defaultValue?: TValue;
|
||||
}
|
||||
|
||||
export interface PanelMenuItem {
|
||||
|
@ -26,11 +26,12 @@ import {
|
||||
/**
|
||||
* Fluent API for declarative creation of field config option editors
|
||||
*/
|
||||
export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
export class FieldConfigEditorBuilder<TOptions> extends OptionsUIRegistryBuilder<
|
||||
TOptions,
|
||||
FieldConfigEditorProps<any, any>,
|
||||
FieldPropertyEditorItem
|
||||
FieldPropertyEditorItem<TOptions>
|
||||
> {
|
||||
addNumberInput<TSettings>(config: FieldConfigEditorConfig<TSettings & NumberFieldConfigSettings>) {
|
||||
addNumberInput<TSettings>(config: FieldConfigEditorConfig<TOptions, TSettings & NumberFieldConfigSettings, number>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
override: standardEditorsRegistry.get('number').editor as any,
|
||||
@ -41,7 +42,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
});
|
||||
}
|
||||
|
||||
addTextInput<TSettings>(config: FieldConfigEditorConfig<TSettings & StringFieldConfigSettings>) {
|
||||
addTextInput<TSettings>(config: FieldConfigEditorConfig<TOptions, TSettings & StringFieldConfigSettings, string>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
override: standardEditorsRegistry.get('text').editor as any,
|
||||
@ -52,7 +53,9 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
});
|
||||
}
|
||||
|
||||
addSelect<TOption, TSettings = any>(config: FieldConfigEditorConfig<TSettings & SelectFieldConfigSettings<TOption>>) {
|
||||
addSelect<TOption, TSettings extends SelectFieldConfigSettings<TOption>>(
|
||||
config: FieldConfigEditorConfig<TOptions, TSettings, TOption>
|
||||
) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
override: standardEditorsRegistry.get('select').editor as any,
|
||||
@ -64,7 +67,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
});
|
||||
}
|
||||
|
||||
addRadio<TOption, TSettings = any>(config: FieldConfigEditorConfig<TSettings & SelectFieldConfigSettings<TOption>>) {
|
||||
addRadio<TOption, TSettings = any>(config: FieldConfigEditorConfig<TOptions, TSettings, TOption>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
override: standardEditorsRegistry.get('radio').editor as any,
|
||||
@ -76,7 +79,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
});
|
||||
}
|
||||
|
||||
addBooleanSwitch<TSettings = any>(config: FieldConfigEditorConfig<TSettings>) {
|
||||
addBooleanSwitch<TSettings = any>(config: FieldConfigEditorConfig<TOptions, TSettings, boolean>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('boolean').editor as any,
|
||||
@ -87,7 +90,9 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
});
|
||||
}
|
||||
|
||||
addColorPicker<TSettings = any>(config: FieldConfigEditorConfig<TSettings & ColorFieldConfigSettings>) {
|
||||
addColorPicker<TSettings = any>(
|
||||
config: FieldConfigEditorConfig<TOptions, TSettings & ColorFieldConfigSettings, string>
|
||||
) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('color').editor as any,
|
||||
@ -98,7 +103,9 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
});
|
||||
}
|
||||
|
||||
addUnitPicker<TSettings = any>(config: FieldConfigEditorConfig<TSettings & UnitFieldConfigSettings>) {
|
||||
addUnitPicker<TSettings = any>(
|
||||
config: FieldConfigEditorConfig<TOptions, TSettings & UnitFieldConfigSettings, string>
|
||||
) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('unit').editor as any,
|
||||
@ -113,43 +120,53 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
|
||||
/**
|
||||
* Fluent API for declarative creation of panel options
|
||||
*/
|
||||
export class PanelOptionsEditorBuilder extends OptionsUIRegistryBuilder<StandardEditorProps, PanelOptionsEditorItem> {
|
||||
addNumberInput<TSettings>(config: PanelOptionsEditorConfig<TSettings & NumberFieldConfigSettings>) {
|
||||
export class PanelOptionsEditorBuilder<TOptions> extends OptionsUIRegistryBuilder<
|
||||
TOptions,
|
||||
StandardEditorProps,
|
||||
PanelOptionsEditorItem<TOptions>
|
||||
> {
|
||||
addNumberInput<TSettings>(config: PanelOptionsEditorConfig<TOptions, TSettings & NumberFieldConfigSettings, number>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('number').editor as any,
|
||||
});
|
||||
}
|
||||
|
||||
addTextInput<TSettings>(config: PanelOptionsEditorConfig<TSettings & StringFieldConfigSettings>) {
|
||||
addTextInput<TSettings>(config: PanelOptionsEditorConfig<TOptions, TSettings & StringFieldConfigSettings, string>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('text').editor as any,
|
||||
});
|
||||
}
|
||||
|
||||
addSelect<TOption, TSettings>(config: PanelOptionsEditorConfig<TSettings & SelectFieldConfigSettings<TOption>>) {
|
||||
addSelect<TOption, TSettings extends SelectFieldConfigSettings<TOption>>(
|
||||
config: PanelOptionsEditorConfig<TOptions, TSettings, TOption>
|
||||
) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('select').editor as any,
|
||||
});
|
||||
}
|
||||
|
||||
addRadio<TOption, TSettings>(config: PanelOptionsEditorConfig<TSettings & SelectFieldConfigSettings<TOption>>) {
|
||||
addRadio<TOption, TSettings extends SelectFieldConfigSettings<TOption>>(
|
||||
config: PanelOptionsEditorConfig<TOptions, TSettings, TOption>
|
||||
) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('radio').editor as any,
|
||||
});
|
||||
}
|
||||
|
||||
addBooleanSwitch<TSettings = any>(config: PanelOptionsEditorConfig<TSettings>) {
|
||||
addBooleanSwitch<TSettings = any>(config: PanelOptionsEditorConfig<TOptions, TSettings, boolean>) {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('boolean').editor as any,
|
||||
});
|
||||
}
|
||||
|
||||
addColorPicker<TSettings = any>(config: PanelOptionsEditorConfig<TSettings & ColorFieldConfigSettings>): this {
|
||||
addColorPicker<TSettings = any>(
|
||||
config: PanelOptionsEditorConfig<TOptions, TSettings & ColorFieldConfigSettings, string>
|
||||
): this {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('color').editor as any,
|
||||
@ -157,7 +174,9 @@ export class PanelOptionsEditorBuilder extends OptionsUIRegistryBuilder<Standard
|
||||
});
|
||||
}
|
||||
|
||||
addUnitPicker<TSettings = any>(config: PanelOptionsEditorConfig<TSettings & UnitFieldConfigSettings>): this {
|
||||
addUnitPicker<TSettings = any>(
|
||||
config: PanelOptionsEditorConfig<TOptions, TSettings & UnitFieldConfigSettings, string>
|
||||
): this {
|
||||
return this.addCustomEditor({
|
||||
...config,
|
||||
editor: standardEditorsRegistry.get('unit').editor as any,
|
||||
|
@ -6,7 +6,7 @@ const history: KeyValue<number> = {};
|
||||
export const deprecationWarning = (file: string, oldName: string, newName?: string) => {
|
||||
let message = `[Deprecation warning] ${file}: ${oldName} is deprecated`;
|
||||
if (newName) {
|
||||
message += `. Use ${newName} instead`;
|
||||
message += `. Use ${newName} instead`;
|
||||
}
|
||||
const now = Date.now();
|
||||
const last = history[message];
|
||||
|
@ -5,6 +5,13 @@ import Forms from '../Forms';
|
||||
export const StringValueEditor: React.FC<FieldConfigEditorProps<string, StringFieldConfigSettings>> = ({
|
||||
value,
|
||||
onChange,
|
||||
item,
|
||||
}) => {
|
||||
return <Forms.Input value={value || ''} onChange={e => onChange(e.currentTarget.value)} />;
|
||||
return (
|
||||
<Forms.Input
|
||||
placeholder={item.settings?.placeholder}
|
||||
value={value || ''}
|
||||
onChange={e => onChange(e.currentTarget.value)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ import { StatsPickerEditor } from '../components/OptionsUI/stats';
|
||||
* Returns collection of common field config properties definitions
|
||||
*/
|
||||
export const getStandardFieldConfigs = () => {
|
||||
const title: FieldPropertyEditorItem<string, StringFieldConfigSettings> = {
|
||||
const title: FieldPropertyEditorItem<any, string, StringFieldConfigSettings> = {
|
||||
id: 'title',
|
||||
name: 'Title',
|
||||
description: "Field's title",
|
||||
@ -38,13 +38,13 @@ export const getStandardFieldConfigs = () => {
|
||||
override: standardEditorsRegistry.get('text').editor as any,
|
||||
process: stringOverrideProcessor,
|
||||
settings: {
|
||||
placeholder: 'auto',
|
||||
placeholder: 'none',
|
||||
expandTemplateVars: true,
|
||||
},
|
||||
shouldApply: field => field.type !== FieldType.time,
|
||||
};
|
||||
|
||||
const unit: FieldPropertyEditorItem<string, StringFieldConfigSettings> = {
|
||||
const unit: FieldPropertyEditorItem<any, string, StringFieldConfigSettings> = {
|
||||
id: 'unit',
|
||||
name: 'Unit',
|
||||
description: 'Value units',
|
||||
@ -60,7 +60,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: field => field.type === FieldType.number,
|
||||
};
|
||||
|
||||
const min: FieldPropertyEditorItem<number, NumberFieldConfigSettings> = {
|
||||
const min: FieldPropertyEditorItem<any, number, NumberFieldConfigSettings> = {
|
||||
id: 'min',
|
||||
name: 'Min',
|
||||
description: 'Minimum expected value',
|
||||
@ -75,7 +75,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: field => field.type === FieldType.number,
|
||||
};
|
||||
|
||||
const max: FieldPropertyEditorItem<number, NumberFieldConfigSettings> = {
|
||||
const max: FieldPropertyEditorItem<any, number, NumberFieldConfigSettings> = {
|
||||
id: 'max',
|
||||
name: 'Max',
|
||||
description: 'Maximum expected value',
|
||||
@ -91,7 +91,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: field => field.type === FieldType.number,
|
||||
};
|
||||
|
||||
const decimals: FieldPropertyEditorItem<number, NumberFieldConfigSettings> = {
|
||||
const decimals: FieldPropertyEditorItem<any, number, NumberFieldConfigSettings> = {
|
||||
id: 'decimals',
|
||||
name: 'Decimals',
|
||||
description: 'Number of decimal to be shown for a value',
|
||||
@ -110,7 +110,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: field => field.type === FieldType.number,
|
||||
};
|
||||
|
||||
const thresholds: FieldPropertyEditorItem<ThresholdsConfig, ThresholdsFieldConfigSettings> = {
|
||||
const thresholds: FieldPropertyEditorItem<any, ThresholdsConfig, ThresholdsFieldConfigSettings> = {
|
||||
id: 'thresholds',
|
||||
name: 'Thresholds',
|
||||
description: 'Manage thresholds',
|
||||
@ -126,7 +126,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: field => field.type === FieldType.number,
|
||||
};
|
||||
|
||||
const mappings: FieldPropertyEditorItem<ValueMapping[], ValueMappingFieldConfigSettings> = {
|
||||
const mappings: FieldPropertyEditorItem<any, ValueMapping[], ValueMappingFieldConfigSettings> = {
|
||||
id: 'mappings',
|
||||
name: 'Value mappings',
|
||||
description: 'Manage value mappings',
|
||||
@ -141,7 +141,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: field => field.type === FieldType.number,
|
||||
};
|
||||
|
||||
const noValue: FieldPropertyEditorItem<string, StringFieldConfigSettings> = {
|
||||
const noValue: FieldPropertyEditorItem<any, string, StringFieldConfigSettings> = {
|
||||
id: 'noValue',
|
||||
name: 'No Value',
|
||||
description: 'What to show when there is no value',
|
||||
@ -157,7 +157,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: () => true,
|
||||
};
|
||||
|
||||
const links: FieldPropertyEditorItem<DataLink[], StringFieldConfigSettings> = {
|
||||
const links: FieldPropertyEditorItem<any, DataLink[], StringFieldConfigSettings> = {
|
||||
id: 'links',
|
||||
name: 'DataLinks',
|
||||
description: 'Manage date links',
|
||||
@ -170,7 +170,7 @@ export const getStandardFieldConfigs = () => {
|
||||
shouldApply: () => true,
|
||||
};
|
||||
|
||||
const color: FieldPropertyEditorItem<string, StringFieldConfigSettings> = {
|
||||
const color: FieldPropertyEditorItem<any, string, StringFieldConfigSettings> = {
|
||||
id: 'color',
|
||||
name: 'Color',
|
||||
description: 'Customise color',
|
||||
@ -217,7 +217,7 @@ export const getStandardOptionEditors = () => {
|
||||
description: 'Allows option selection',
|
||||
editor: props => (
|
||||
<Forms.Select
|
||||
defaultValue={props.value}
|
||||
value={props.value}
|
||||
onChange={e => props.onChange(e.value)}
|
||||
options={props.item.settings?.options}
|
||||
/>
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
standardFieldConfigEditorRegistry,
|
||||
PanelPlugin,
|
||||
SelectableValue,
|
||||
StandardFieldConfigProperties,
|
||||
} from '@grafana/data';
|
||||
import { Forms, fieldMatchersUI, ValuePicker, useTheme } from '@grafana/ui';
|
||||
import { getDataLinksVariableSuggestions } from '../../../panel/panellinks/link_srv';
|
||||
@ -17,7 +18,7 @@ import { css } from 'emotion';
|
||||
interface Props {
|
||||
plugin: PanelPlugin;
|
||||
config: FieldConfigSource;
|
||||
include?: string[]; // Ordered list of which fields should be shown/included
|
||||
include?: StandardFieldConfigProperties[]; // Ordered list of which fields should be shown/included
|
||||
onChange: (config: FieldConfigSource) => void;
|
||||
/* Helpful for IntelliSense */
|
||||
data: DataFrame[];
|
||||
@ -67,12 +68,15 @@ export const OverrideFieldConfigEditor: React.FC<Props> = props => {
|
||||
return null;
|
||||
}
|
||||
|
||||
let configPropertiesOptions = standardFieldConfigEditorRegistry.list().map(i => ({
|
||||
label: i.name,
|
||||
value: i.id,
|
||||
description: i.description,
|
||||
custom: false,
|
||||
}));
|
||||
let configPropertiesOptions = plugin.standardFieldConfigProperties.map(i => {
|
||||
const editor = standardFieldConfigEditorRegistry.get(i);
|
||||
return {
|
||||
label: editor.name,
|
||||
value: editor.id,
|
||||
description: editor.description,
|
||||
custom: false,
|
||||
};
|
||||
});
|
||||
|
||||
if (customFieldConfigs) {
|
||||
configPropertiesOptions = configPropertiesOptions.concat(
|
||||
@ -185,6 +189,9 @@ export const DefaultFieldConfigEditor: React.FC<Props> = ({ include, data, onCha
|
||||
);
|
||||
|
||||
const renderStandardConfigs = useCallback(() => {
|
||||
if (include && include.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (include) {
|
||||
return <>{include.map(f => renderEditor(standardFieldConfigEditorRegistry.get(f), false))}</>;
|
||||
}
|
||||
|
@ -60,6 +60,7 @@ export const OptionsPaneContent: React.FC<{
|
||||
plugin={plugin}
|
||||
onChange={onFieldConfigsChange}
|
||||
data={data.series}
|
||||
include={plugin.standardFieldConfigProperties}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { PanelModel } from './PanelModel';
|
||||
import { getPanelPlugin } from '../../plugins/__mocks__/pluginMocks';
|
||||
import { ConfigOverrideRule, PanelProps } from '@grafana/data';
|
||||
import { PanelProps, StandardFieldConfigProperties } from '@grafana/data';
|
||||
import { ComponentClass } from 'react';
|
||||
|
||||
class TablePanelCtrl {}
|
||||
@ -70,13 +70,6 @@ describe('PanelModel', () => {
|
||||
};
|
||||
|
||||
model = new PanelModel(modelJson);
|
||||
const overrideMock: ConfigOverrideRule = {
|
||||
matcher: {
|
||||
id: '2',
|
||||
options: {},
|
||||
},
|
||||
properties: [],
|
||||
};
|
||||
|
||||
const panelPlugin = getPanelPlugin(
|
||||
{
|
||||
@ -86,12 +79,9 @@ describe('PanelModel', () => {
|
||||
TablePanelCtrl // angular
|
||||
);
|
||||
panelPlugin.setDefaults(defaultOptionsMock);
|
||||
panelPlugin.setFieldConfigDefaults({
|
||||
defaults: {
|
||||
unit: 'flop',
|
||||
decimals: 2,
|
||||
},
|
||||
overrides: [overrideMock],
|
||||
panelPlugin.useStandardFieldConfig([StandardFieldConfigProperties.Unit, StandardFieldConfigProperties.Decimals], {
|
||||
[StandardFieldConfigProperties.Unit]: 'flop',
|
||||
[StandardFieldConfigProperties.Decimals]: 2,
|
||||
});
|
||||
model.pluginLoaded(panelPlugin);
|
||||
});
|
||||
@ -108,10 +98,6 @@ describe('PanelModel', () => {
|
||||
expect(model.getOptions().arrayWith2Values.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should merge override field config options', () => {
|
||||
expect(model.getFieldOverrideOptions().fieldOptions.overrides.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should apply field config defaults', () => {
|
||||
// default unit is overriden by model
|
||||
expect(model.getFieldOverrideOptions().fieldOptions.defaults.unit).toBe('mpg');
|
||||
|
@ -1,15 +1,14 @@
|
||||
import { sharedSingleStatPanelChangedHandler } from '@grafana/ui';
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { defaultStandardFieldConfigProperties, PanelPlugin } from '@grafana/data';
|
||||
import { BarGaugePanel } from './BarGaugePanel';
|
||||
import { BarGaugeOptions, defaults } from './types';
|
||||
import { standardFieldConfig, addStandardDataReduceOptions } from '../stat/types';
|
||||
import { standardFieldConfigDefaults, addStandardDataReduceOptions } from '../stat/types';
|
||||
import { BarGaugePanelEditor } from './BarGaugePanelEditor';
|
||||
import { barGaugePanelMigrationHandler } from './BarGaugeMigrations';
|
||||
|
||||
export const plugin = new PanelPlugin<BarGaugeOptions>(BarGaugePanel)
|
||||
.setDefaults(defaults)
|
||||
.setEditor(BarGaugePanelEditor)
|
||||
.setFieldConfigDefaults(standardFieldConfig)
|
||||
.setPanelOptions(builder => {
|
||||
addStandardDataReduceOptions(builder);
|
||||
|
||||
@ -33,4 +32,5 @@ export const plugin = new PanelPlugin<BarGaugeOptions>(BarGaugePanel)
|
||||
});
|
||||
})
|
||||
.setPanelChangeHandler(sharedSingleStatPanelChangedHandler)
|
||||
.setMigrationHandler(barGaugePanelMigrationHandler);
|
||||
.setMigrationHandler(barGaugePanelMigrationHandler)
|
||||
.useStandardFieldConfig(defaultStandardFieldConfigProperties, standardFieldConfigDefaults);
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { defaultStandardFieldConfigProperties, PanelPlugin } from '@grafana/data';
|
||||
import { GaugePanelEditor } from './GaugePanelEditor';
|
||||
import { GaugePanel } from './GaugePanel';
|
||||
import { GaugeOptions, defaults } from './types';
|
||||
import { standardFieldConfig, addStandardDataReduceOptions } from '../stat/types';
|
||||
import { standardFieldConfigDefaults, addStandardDataReduceOptions } from '../stat/types';
|
||||
import { gaugePanelMigrationHandler, gaugePanelChangedHandler } from './GaugeMigrations';
|
||||
|
||||
export const plugin = new PanelPlugin<GaugeOptions>(GaugePanel)
|
||||
.setDefaults(defaults)
|
||||
.setFieldConfigDefaults(standardFieldConfig)
|
||||
.setEditor(GaugePanelEditor)
|
||||
.setPanelOptions(builder => {
|
||||
addStandardDataReduceOptions(builder);
|
||||
@ -25,4 +24,5 @@ export const plugin = new PanelPlugin<GaugeOptions>(GaugePanel)
|
||||
});
|
||||
})
|
||||
.setPanelChangeHandler(gaugePanelChangedHandler)
|
||||
.setMigrationHandler(gaugePanelMigrationHandler);
|
||||
.setMigrationHandler(gaugePanelMigrationHandler)
|
||||
.useStandardFieldConfig(defaultStandardFieldConfigProperties, standardFieldConfigDefaults);
|
||||
|
@ -1,9 +1,11 @@
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { defaultStandardFieldConfigProperties, PanelPlugin, StandardFieldConfigProperties } from '@grafana/data';
|
||||
import { PieChartPanelEditor } from './PieChartPanelEditor';
|
||||
import { PieChartPanel } from './PieChartPanel';
|
||||
import { PieChartOptions, defaults } from './types';
|
||||
|
||||
export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel)
|
||||
.setDefaults(defaults)
|
||||
.setFieldConfigDefaults({ defaults: { unit: 'short' } })
|
||||
.useStandardFieldConfig(defaultStandardFieldConfigProperties, {
|
||||
[StandardFieldConfigProperties.Unit]: 'short',
|
||||
})
|
||||
.setEditor(PieChartPanelEditor);
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { sharedSingleStatMigrationHandler, sharedSingleStatPanelChangedHandler } from '@grafana/ui';
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { StatPanelOptions, defaults, standardFieldConfig, addStandardDataReduceOptions } from './types';
|
||||
import { defaultStandardFieldConfigProperties, PanelPlugin } from '@grafana/data';
|
||||
import { StatPanelOptions, defaults, standardFieldConfigDefaults, addStandardDataReduceOptions } from './types';
|
||||
import { StatPanel } from './StatPanel';
|
||||
import { StatPanelEditor } from './StatPanelEditor';
|
||||
|
||||
export const plugin = new PanelPlugin<StatPanelOptions>(StatPanel)
|
||||
.setDefaults(defaults)
|
||||
.setFieldConfigDefaults(standardFieldConfig)
|
||||
.setEditor(StatPanelEditor)
|
||||
.setPanelOptions(builder => {
|
||||
addStandardDataReduceOptions(builder);
|
||||
@ -48,4 +47,5 @@ export const plugin = new PanelPlugin<StatPanelOptions>(StatPanel)
|
||||
})
|
||||
.setNoPadding()
|
||||
.setPanelChangeHandler(sharedSingleStatPanelChangedHandler)
|
||||
.setMigrationHandler(sharedSingleStatMigrationHandler);
|
||||
.setMigrationHandler(sharedSingleStatMigrationHandler)
|
||||
.useStandardFieldConfig(defaultStandardFieldConfigProperties, standardFieldConfigDefaults);
|
||||
|
@ -4,9 +4,9 @@ import {
|
||||
ReducerID,
|
||||
ReduceDataOptions,
|
||||
SelectableValue,
|
||||
FieldConfigSource,
|
||||
ThresholdsMode,
|
||||
standardEditorsRegistry,
|
||||
StandardFieldConfigProperties,
|
||||
} from '@grafana/data';
|
||||
import { PanelOptionsEditorBuilder } from '@grafana/data/src/utils/OptionsUIBuilders';
|
||||
|
||||
@ -37,21 +37,18 @@ export const commonValueOptionDefaults: ReduceDataOptions = {
|
||||
calcs: [ReducerID.mean],
|
||||
};
|
||||
|
||||
export const standardFieldConfig: FieldConfigSource = {
|
||||
defaults: {
|
||||
thresholds: {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: [
|
||||
{ value: -Infinity, color: 'green' },
|
||||
{ value: 80, color: 'red' }, // 80%
|
||||
],
|
||||
},
|
||||
mappings: [],
|
||||
export const standardFieldConfigDefaults: Partial<Record<StandardFieldConfigProperties, any>> = {
|
||||
[StandardFieldConfigProperties.Thresholds]: {
|
||||
mode: ThresholdsMode.Absolute,
|
||||
steps: [
|
||||
{ value: -Infinity, color: 'green' },
|
||||
{ value: 80, color: 'red' }, // 80%
|
||||
],
|
||||
},
|
||||
overrides: [],
|
||||
[StandardFieldConfigProperties.Mappings]: [],
|
||||
};
|
||||
|
||||
export function addStandardDataReduceOptions(builder: PanelOptionsEditorBuilder) {
|
||||
export function addStandardDataReduceOptions(builder: PanelOptionsEditorBuilder<StatPanelOptions>) {
|
||||
builder.addRadio({
|
||||
id: 'reduceOptions.values',
|
||||
name: 'Show',
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { PanelPlugin } from '@grafana/data';
|
||||
import { TablePanel } from './TablePanel';
|
||||
import { Options, defaults } from './types';
|
||||
import { CustomFieldConfig, defaults, Options } from './types';
|
||||
|
||||
export const plugin = new PanelPlugin<Options>(TablePanel)
|
||||
export const plugin = new PanelPlugin<Options, CustomFieldConfig>(TablePanel)
|
||||
.setDefaults(defaults)
|
||||
.setCustomFieldOptions(builder => {
|
||||
builder
|
||||
@ -15,6 +15,7 @@ export const plugin = new PanelPlugin<Options>(TablePanel)
|
||||
min: 20,
|
||||
max: 300,
|
||||
},
|
||||
defaultValue: 1,
|
||||
})
|
||||
.addSelect({
|
||||
id: 'displayMode',
|
||||
|
@ -2,6 +2,11 @@ export interface Options {
|
||||
showHeader: boolean;
|
||||
}
|
||||
|
||||
export interface CustomFieldConfig {
|
||||
width: number;
|
||||
displayMode: string;
|
||||
}
|
||||
|
||||
export const defaults: Options = {
|
||||
showHeader: true,
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user