diff --git a/packages/grafana-data/src/field/overrides/processors.ts b/packages/grafana-data/src/field/overrides/processors.ts
index bff63a677f9..ea195ecca52 100644
--- a/packages/grafana-data/src/field/overrides/processors.ts
+++ b/packages/grafana-data/src/field/overrides/processors.ts
@@ -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);
}
diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts
index 43a488d7095..8581614c40e 100644
--- a/packages/grafana-data/src/index.ts
+++ b/packages/grafana-data/src/index.ts
@@ -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';
diff --git a/packages/grafana-data/src/panel/PanelPlugin.test.tsx b/packages/grafana-data/src/panel/PanelPlugin.test.tsx
index e9244813ed6..1b272d20759 100644
--- a/packages/grafana-data/src/panel/PanelPlugin.test.tsx
+++ b/packages/grafana-data/src/panel/PanelPlugin.test.tsx
@@ -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
Panel
;
@@ -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 Panel
;
+ });
+
+ 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: () => Editor
,
+ 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 Panel
;
+ });
+
+ 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 Panel
;
+ });
+
+ 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: () => Editor
,
+ override: () => Override editor
,
+ 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 Panel
;
+ });
+
+ 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 Panel
;
+ });
+
+ panel.useStandardFieldConfig();
+ expect(panel.standardFieldConfigProperties).toEqual(Array.from(standardFieldConfigProperties.keys()));
+ });
+
+ test('selected standard config', () => {
+ const panel = new PanelPlugin(() => {
+ return Panel
;
+ });
+
+ panel.useStandardFieldConfig([StandardFieldConfigProperties.Min, StandardFieldConfigProperties.Thresholds]);
+ expect(panel.standardFieldConfigProperties).toEqual(['min', 'thresholds']);
+ });
+
+ describe('default values', () => {
+ test('setting default values', () => {
+ const panel = new PanelPlugin(() => {
+ return Panel
;
+ });
+
+ 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 Panel
;
+ });
+
+ panel.useStandardFieldConfig([StandardFieldConfigProperties.Color], {
+ [StandardFieldConfigProperties.Color]: '#ff00ff',
+ [StandardFieldConfigProperties.Min]: 10,
+ });
+
+ expect(panel.standardFieldConfigProperties).toEqual(['color']);
+
+ expect(panel.fieldConfigDefaults).toEqual({
+ defaults: {
+ color: '#ff00ff',
+ },
+ overrides: [],
+ });
+ });
+ });
+ });
+ });
});
diff --git a/packages/grafana-data/src/panel/PanelPlugin.ts b/packages/grafana-data/src/panel/PanelPlugin.ts
index 0ebf536585b..89c64721da6 100644
--- a/packages/grafana-data/src/panel/PanelPlugin.ts
+++ b/packages/grafana-data/src/panel/PanelPlugin.ts
@@ -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 extends GrafanaPlugin {
- 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>;
- editor?: ComponentClass>;
- defaults?: TOptions;
- fieldConfigDefaults?: FieldConfigSource = {
+export class PanelPlugin extends GrafanaPlugin<
+ PanelPluginMeta
+> {
+ private _defaults?: TOptions;
+ private _standardFieldConfigProperties?: Map;
+
+ private _fieldConfigDefaults: FieldConfigSource = {
defaults: {},
overrides: [],
};
+ private _customFieldConfigs?: FieldConfigEditorRegistry;
+ private customFieldConfigsUIBuilder = new FieldConfigEditorBuilder();
+ private registerCustomFieldConfigs?: (builder: FieldConfigEditorBuilder) => void;
+
+ private _optionEditors?: PanelOptionEditorsRegistry;
+ private optionsUIBuilder = new PanelOptionsEditorBuilder();
+ private registerOptionEditors?: (builder: PanelOptionsEditorBuilder) => void;
+
+ panel: ComponentType>;
+ editor?: ComponentClass>;
onPanelMigration?: PanelMigrationHandler;
onPanelTypeChanged?: PanelTypeChangedHandler;
noPadding?: boolean;
@@ -42,6 +64,66 @@ export class PanelPlugin extends GrafanaPlugin
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 {
+ 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 extends GrafanaPlugin
return this;
}
- setDefaults(defaults: TOptions) {
- this.defaults = defaults;
- return this;
- }
-
setNoPadding() {
this.noPadding = true;
return this;
@@ -134,7 +211,7 @@ export class PanelPlugin extends GrafanaPlugin
*
* @public
**/
- setCustomFieldOptions(builder: (builder: FieldConfigEditorBuilder) => void) {
+ setCustomFieldOptions(builder: (builder: FieldConfigEditorBuilder) => void) {
// builder is applied lazily when custom field configs are accessed
this.registerCustomFieldConfigs = builder;
return this;
@@ -170,22 +247,63 @@ export class PanelPlugin extends GrafanaPlugin
*
* @public
**/
- setPanelOptions(builder: (builder: PanelOptionsEditorBuilder) => void) {
+ setPanelOptions(builder: (builder: PanelOptionsEditorBuilder) => 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(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(ShapePanel)
+ * .useStandardFieldConfig([StandardFieldConfigProperties.Min, StandardFieldConfigProperties.Max, StandardFieldConfigProperties.Links]);
+ *
+ * // when standard option's default value needs to be provided
+ * export const plugin = new PanelPlugin(ShapePanel)
+ * .useStandardFieldConfig([StandardFieldConfigProperties.Min, StandardFieldConfigProperties.Max], {
+ * [StandardFieldConfigProperties.Min]: 20,
+ * [StandardFieldConfigProperties.Max]: 100
+ * });
+ *
+ * ```
+ *
+ * @public
*/
- setFieldConfigDefaults(defaultConfig: Partial) {
- this.fieldConfigDefaults = {
- defaults: {},
- overrides: [],
- ...defaultConfig,
- };
+ useStandardFieldConfig(
+ properties?: StandardFieldConfigProperties[],
+ defauls?: Partial>
+ ) {
+ 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;
}
}
diff --git a/packages/grafana-data/src/types/OptionsUIRegistryBuilder.ts b/packages/grafana-data/src/types/OptionsUIRegistryBuilder.ts
index 7f7a575f9e5..87990e7ba73 100644
--- a/packages/grafana-data/src/types/OptionsUIRegistryBuilder.ts
+++ b/packages/grafana-data/src/types/OptionsUIRegistryBuilder.ts
@@ -5,52 +5,59 @@ import { NumberFieldConfigSettings, SelectFieldConfigSettings, StringFieldConfig
/**
* Option editor registry item
*/
-export interface OptionsEditorItem extends RegistryItem {
+export interface OptionsEditorItem extends RegistryItem {
+ id: (keyof TOptions & string) | string;
editor: ComponentType;
settings?: TSettings;
+ defaultValue?: TValue;
}
/**
* Configuration of option editor registry item
*/
-interface OptionEditorConfig {
- id: string;
+interface OptionEditorConfig {
+ id: keyof TOptions & string;
name: string;
description: string;
settings?: TSettings;
+ defaultValue?: TValue;
}
/**
* Describes an API for option editors UI builder
*/
-export interface OptionsUIRegistryBuilderAPI> {
+export interface OptionsUIRegistryBuilderAPI<
+ TOptions,
+ TEditorProps,
+ T extends OptionsEditorItem
+> {
addNumberInput?(
- config: OptionEditorConfig
+ config: OptionEditorConfig
): this;
addTextInput?(
- config: OptionEditorConfig
+ config: OptionEditorConfig
): this;
addSelect?>(
- config: OptionEditorConfig
+ config: OptionEditorConfig
): this;
addRadio? = SelectFieldConfigSettings>(
- config: OptionEditorConfig
+ config: OptionEditorConfig
): this;
- addBooleanSwitch?(config: OptionEditorConfig): this;
+ addBooleanSwitch?(config: OptionEditorConfig): this;
- addUnitPicker?(config: OptionEditorConfig): this;
+ addUnitPicker?(config: OptionEditorConfig): this;
- addColorPicker?(config: OptionEditorConfig): this;
+ addColorPicker?(config: OptionEditorConfig): this;
/**
* Enables custom editor definition
* @param config
*/
- addCustomEditor(config: OptionsEditorItem): this;
+ addCustomEditor(config: OptionsEditorItem): this;
/**
* Returns registry of option editors
@@ -58,11 +65,14 @@ export interface OptionsUIRegistryBuilderAPI Registry;
}
-export abstract class OptionsUIRegistryBuilder>
- implements OptionsUIRegistryBuilderAPI {
+export abstract class OptionsUIRegistryBuilder<
+ TOptions,
+ TEditorProps,
+ T extends OptionsEditorItem
+> implements OptionsUIRegistryBuilderAPI {
private properties: T[] = [];
- addCustomEditor(config: T & OptionsEditorItem): this {
+ addCustomEditor(config: T & OptionsEditorItem): this {
this.properties.push(config);
return this;
}
diff --git a/packages/grafana-data/src/types/dataFrame.ts b/packages/grafana-data/src/types/dataFrame.ts
index c01543fa1cf..8d120f5df95 100644
--- a/packages/grafana-data/src/types/dataFrame.ts
+++ b/packages/grafana-data/src/types/dataFrame.ts
@@ -21,7 +21,7 @@ export enum FieldType {
*
* Plugins may extend this with additional properties. Something like series overrides
*/
-export interface FieldConfig {
+export interface FieldConfig {
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;
+ custom?: TOptions;
scopedVars?: ScopedVars;
}
diff --git a/packages/grafana-data/src/types/fieldOverrides.ts b/packages/grafana-data/src/types/fieldOverrides.ts
index 26e14751af6..7b1816acc49 100644
--- a/packages/grafana-data/src/types/fieldOverrides.ts
+++ b/packages/grafana-data/src/types/fieldOverrides.ts
@@ -25,9 +25,9 @@ export interface ConfigOverrideRule {
properties: DynamicConfigValue[];
}
-export interface FieldConfigSource {
+export interface FieldConfigSource {
// Defatuls applied to all numeric fields
- defaults: FieldConfig;
+ defaults: FieldConfig;
// Rules to override individual values
overrides: ConfigOverrideRule[];
@@ -54,16 +54,17 @@ export interface FieldOverrideEditorProps extends Omit {
- id: string;
+export interface FieldConfigEditorConfig {
+ id: (keyof TOptions & string) | string;
name: string;
description: string;
settings?: TSettings;
shouldApply?: (field: Field) => boolean;
+ defaultValue?: TValue;
}
-export interface FieldPropertyEditorItem
- extends OptionsEditorItem> {
+export interface FieldPropertyEditorItem
+ extends OptionsEditorItem, TValue> {
// An editor that can be filled in with context info (template variables etc)
override: ComponentType>;
@@ -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',
+}
diff --git a/packages/grafana-data/src/types/panel.ts b/packages/grafana-data/src/types/panel.ts
index 37defee1989..c2d1c488c6f 100644
--- a/packages/grafana-data/src/types/panel.ts
+++ b/packages/grafana-data/src/types/panel.ts
@@ -115,14 +115,15 @@ export type PanelOptionEditorsRegistry = Registry;
export interface PanelOptionsEditorProps extends StandardEditorProps {}
-export interface PanelOptionsEditorItem
- extends OptionsEditorItem> {}
+export interface PanelOptionsEditorItem
+ extends OptionsEditorItem, TValue> {}
-export interface PanelOptionsEditorConfig {
- id: string;
+export interface PanelOptionsEditorConfig {
+ id: (keyof TOptions & string) | string;
name: string;
description: string;
settings?: TSettings;
+ defaultValue?: TValue;
}
export interface PanelMenuItem {
diff --git a/packages/grafana-data/src/utils/OptionsUIBuilders.ts b/packages/grafana-data/src/utils/OptionsUIBuilders.ts
index f6c0f5e15bb..726d90bae6e 100644
--- a/packages/grafana-data/src/utils/OptionsUIBuilders.ts
+++ b/packages/grafana-data/src/utils/OptionsUIBuilders.ts
@@ -26,11 +26,12 @@ import {
/**
* Fluent API for declarative creation of field config option editors
*/
-export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
+export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
+ TOptions,
FieldConfigEditorProps,
- FieldPropertyEditorItem
+ FieldPropertyEditorItem
> {
- addNumberInput(config: FieldConfigEditorConfig) {
+ addNumberInput(config: FieldConfigEditorConfig) {
return this.addCustomEditor({
...config,
override: standardEditorsRegistry.get('number').editor as any,
@@ -41,7 +42,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
});
}
- addTextInput(config: FieldConfigEditorConfig) {
+ addTextInput(config: FieldConfigEditorConfig) {
return this.addCustomEditor({
...config,
override: standardEditorsRegistry.get('text').editor as any,
@@ -52,7 +53,9 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
});
}
- addSelect(config: FieldConfigEditorConfig>) {
+ addSelect>(
+ config: FieldConfigEditorConfig
+ ) {
return this.addCustomEditor({
...config,
override: standardEditorsRegistry.get('select').editor as any,
@@ -64,7 +67,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
});
}
- addRadio(config: FieldConfigEditorConfig>) {
+ addRadio(config: FieldConfigEditorConfig) {
return this.addCustomEditor({
...config,
override: standardEditorsRegistry.get('radio').editor as any,
@@ -76,7 +79,7 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
});
}
- addBooleanSwitch(config: FieldConfigEditorConfig) {
+ addBooleanSwitch(config: FieldConfigEditorConfig) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('boolean').editor as any,
@@ -87,7 +90,9 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
});
}
- addColorPicker(config: FieldConfigEditorConfig) {
+ addColorPicker(
+ config: FieldConfigEditorConfig
+ ) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('color').editor as any,
@@ -98,7 +103,9 @@ export class FieldConfigEditorBuilder extends OptionsUIRegistryBuilder<
});
}
- addUnitPicker(config: FieldConfigEditorConfig) {
+ addUnitPicker(
+ config: FieldConfigEditorConfig
+ ) {
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 {
- addNumberInput(config: PanelOptionsEditorConfig) {
+export class PanelOptionsEditorBuilder extends OptionsUIRegistryBuilder<
+ TOptions,
+ StandardEditorProps,
+ PanelOptionsEditorItem
+> {
+ addNumberInput(config: PanelOptionsEditorConfig) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('number').editor as any,
});
}
- addTextInput(config: PanelOptionsEditorConfig) {
+ addTextInput(config: PanelOptionsEditorConfig) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('text').editor as any,
});
}
- addSelect(config: PanelOptionsEditorConfig>) {
+ addSelect>(
+ config: PanelOptionsEditorConfig
+ ) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('select').editor as any,
});
}
- addRadio(config: PanelOptionsEditorConfig>) {
+ addRadio>(
+ config: PanelOptionsEditorConfig
+ ) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('radio').editor as any,
});
}
- addBooleanSwitch(config: PanelOptionsEditorConfig) {
+ addBooleanSwitch(config: PanelOptionsEditorConfig) {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('boolean').editor as any,
});
}
- addColorPicker(config: PanelOptionsEditorConfig): this {
+ addColorPicker(
+ config: PanelOptionsEditorConfig
+ ): this {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('color').editor as any,
@@ -157,7 +174,9 @@ export class PanelOptionsEditorBuilder extends OptionsUIRegistryBuilder(config: PanelOptionsEditorConfig): this {
+ addUnitPicker(
+ config: PanelOptionsEditorConfig
+ ): this {
return this.addCustomEditor({
...config,
editor: standardEditorsRegistry.get('unit').editor as any,
diff --git a/packages/grafana-data/src/utils/deprecationWarning.ts b/packages/grafana-data/src/utils/deprecationWarning.ts
index 8ba62595d0a..b959ccd1e18 100644
--- a/packages/grafana-data/src/utils/deprecationWarning.ts
+++ b/packages/grafana-data/src/utils/deprecationWarning.ts
@@ -6,7 +6,7 @@ const history: KeyValue = {};
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];
diff --git a/packages/grafana-ui/src/components/OptionsUI/string.tsx b/packages/grafana-ui/src/components/OptionsUI/string.tsx
index b0b460b9f7d..d4abc1428f5 100644
--- a/packages/grafana-ui/src/components/OptionsUI/string.tsx
+++ b/packages/grafana-ui/src/components/OptionsUI/string.tsx
@@ -5,6 +5,13 @@ import Forms from '../Forms';
export const StringValueEditor: React.FC> = ({
value,
onChange,
+ item,
}) => {
- return onChange(e.currentTarget.value)} />;
+ return (
+ onChange(e.currentTarget.value)}
+ />
+ );
};
diff --git a/packages/grafana-ui/src/utils/standardEditors.tsx b/packages/grafana-ui/src/utils/standardEditors.tsx
index b04e3776991..271787b46aa 100644
--- a/packages/grafana-ui/src/utils/standardEditors.tsx
+++ b/packages/grafana-ui/src/utils/standardEditors.tsx
@@ -30,7 +30,7 @@ import { StatsPickerEditor } from '../components/OptionsUI/stats';
* Returns collection of common field config properties definitions
*/
export const getStandardFieldConfigs = () => {
- const title: FieldPropertyEditorItem = {
+ const title: FieldPropertyEditorItem = {
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 = {
+ const unit: FieldPropertyEditorItem = {
id: 'unit',
name: 'Unit',
description: 'Value units',
@@ -60,7 +60,7 @@ export const getStandardFieldConfigs = () => {
shouldApply: field => field.type === FieldType.number,
};
- const min: FieldPropertyEditorItem = {
+ const min: FieldPropertyEditorItem = {
id: 'min',
name: 'Min',
description: 'Minimum expected value',
@@ -75,7 +75,7 @@ export const getStandardFieldConfigs = () => {
shouldApply: field => field.type === FieldType.number,
};
- const max: FieldPropertyEditorItem = {
+ const max: FieldPropertyEditorItem = {
id: 'max',
name: 'Max',
description: 'Maximum expected value',
@@ -91,7 +91,7 @@ export const getStandardFieldConfigs = () => {
shouldApply: field => field.type === FieldType.number,
};
- const decimals: FieldPropertyEditorItem = {
+ const decimals: FieldPropertyEditorItem = {
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 = {
+ const thresholds: FieldPropertyEditorItem = {
id: 'thresholds',
name: 'Thresholds',
description: 'Manage thresholds',
@@ -126,7 +126,7 @@ export const getStandardFieldConfigs = () => {
shouldApply: field => field.type === FieldType.number,
};
- const mappings: FieldPropertyEditorItem = {
+ const mappings: FieldPropertyEditorItem = {
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 = {
+ const noValue: FieldPropertyEditorItem = {
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 = {
+ const links: FieldPropertyEditorItem = {
id: 'links',
name: 'DataLinks',
description: 'Manage date links',
@@ -170,7 +170,7 @@ export const getStandardFieldConfigs = () => {
shouldApply: () => true,
};
- const color: FieldPropertyEditorItem = {
+ const color: FieldPropertyEditorItem = {
id: 'color',
name: 'Color',
description: 'Customise color',
@@ -217,7 +217,7 @@ export const getStandardOptionEditors = () => {
description: 'Allows option selection',
editor: props => (
props.onChange(e.value)}
options={props.item.settings?.options}
/>
diff --git a/public/app/features/dashboard/components/PanelEditor/FieldConfigEditor.tsx b/public/app/features/dashboard/components/PanelEditor/FieldConfigEditor.tsx
index 59ea82ae67e..2421d88c4ad 100644
--- a/public/app/features/dashboard/components/PanelEditor/FieldConfigEditor.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/FieldConfigEditor.tsx
@@ -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 => {
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 = ({ include, data, onCha
);
const renderStandardConfigs = useCallback(() => {
+ if (include && include.length === 0) {
+ return null;
+ }
if (include) {
return <>{include.map(f => renderEditor(standardFieldConfigEditorRegistry.get(f), false))}>;
}
diff --git a/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx b/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx
index 98fd49b6b09..5b11503a86e 100644
--- a/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx
+++ b/public/app/features/dashboard/components/PanelEditor/OptionsPaneContent.tsx
@@ -60,6 +60,7 @@ export const OptionsPaneContent: React.FC<{
plugin={plugin}
onChange={onFieldConfigsChange}
data={data.series}
+ include={plugin.standardFieldConfigProperties}
/>
);
diff --git a/public/app/features/dashboard/state/PanelModel.test.ts b/public/app/features/dashboard/state/PanelModel.test.ts
index 16058904db3..4248ad85e94 100644
--- a/public/app/features/dashboard/state/PanelModel.test.ts
+++ b/public/app/features/dashboard/state/PanelModel.test.ts
@@ -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');
diff --git a/public/app/plugins/panel/bargauge/module.tsx b/public/app/plugins/panel/bargauge/module.tsx
index ff207a65608..b4f4a99d3f8 100644
--- a/public/app/plugins/panel/bargauge/module.tsx
+++ b/public/app/plugins/panel/bargauge/module.tsx
@@ -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(BarGaugePanel)
.setDefaults(defaults)
.setEditor(BarGaugePanelEditor)
- .setFieldConfigDefaults(standardFieldConfig)
.setPanelOptions(builder => {
addStandardDataReduceOptions(builder);
@@ -33,4 +32,5 @@ export const plugin = new PanelPlugin(BarGaugePanel)
});
})
.setPanelChangeHandler(sharedSingleStatPanelChangedHandler)
- .setMigrationHandler(barGaugePanelMigrationHandler);
+ .setMigrationHandler(barGaugePanelMigrationHandler)
+ .useStandardFieldConfig(defaultStandardFieldConfigProperties, standardFieldConfigDefaults);
diff --git a/public/app/plugins/panel/gauge/module.tsx b/public/app/plugins/panel/gauge/module.tsx
index 894c600b7d1..9b4159b0058 100644
--- a/public/app/plugins/panel/gauge/module.tsx
+++ b/public/app/plugins/panel/gauge/module.tsx
@@ -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(GaugePanel)
.setDefaults(defaults)
- .setFieldConfigDefaults(standardFieldConfig)
.setEditor(GaugePanelEditor)
.setPanelOptions(builder => {
addStandardDataReduceOptions(builder);
@@ -25,4 +24,5 @@ export const plugin = new PanelPlugin(GaugePanel)
});
})
.setPanelChangeHandler(gaugePanelChangedHandler)
- .setMigrationHandler(gaugePanelMigrationHandler);
+ .setMigrationHandler(gaugePanelMigrationHandler)
+ .useStandardFieldConfig(defaultStandardFieldConfigProperties, standardFieldConfigDefaults);
diff --git a/public/app/plugins/panel/piechart/module.tsx b/public/app/plugins/panel/piechart/module.tsx
index 5782ecc2131..1ff9e6885d1 100644
--- a/public/app/plugins/panel/piechart/module.tsx
+++ b/public/app/plugins/panel/piechart/module.tsx
@@ -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(PieChartPanel)
.setDefaults(defaults)
- .setFieldConfigDefaults({ defaults: { unit: 'short' } })
+ .useStandardFieldConfig(defaultStandardFieldConfigProperties, {
+ [StandardFieldConfigProperties.Unit]: 'short',
+ })
.setEditor(PieChartPanelEditor);
diff --git a/public/app/plugins/panel/stat/module.tsx b/public/app/plugins/panel/stat/module.tsx
index e6eb90f0cc3..799ff473e2d 100644
--- a/public/app/plugins/panel/stat/module.tsx
+++ b/public/app/plugins/panel/stat/module.tsx
@@ -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(StatPanel)
.setDefaults(defaults)
- .setFieldConfigDefaults(standardFieldConfig)
.setEditor(StatPanelEditor)
.setPanelOptions(builder => {
addStandardDataReduceOptions(builder);
@@ -48,4 +47,5 @@ export const plugin = new PanelPlugin(StatPanel)
})
.setNoPadding()
.setPanelChangeHandler(sharedSingleStatPanelChangedHandler)
- .setMigrationHandler(sharedSingleStatMigrationHandler);
+ .setMigrationHandler(sharedSingleStatMigrationHandler)
+ .useStandardFieldConfig(defaultStandardFieldConfigProperties, standardFieldConfigDefaults);
diff --git a/public/app/plugins/panel/stat/types.ts b/public/app/plugins/panel/stat/types.ts
index 3d990d74c51..e2e9ff11c05 100644
--- a/public/app/plugins/panel/stat/types.ts
+++ b/public/app/plugins/panel/stat/types.ts
@@ -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> = {
+ [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) {
builder.addRadio({
id: 'reduceOptions.values',
name: 'Show',
diff --git a/public/app/plugins/panel/table2/module.tsx b/public/app/plugins/panel/table2/module.tsx
index ee4839dbeaf..5fb17e3108e 100644
--- a/public/app/plugins/panel/table2/module.tsx
+++ b/public/app/plugins/panel/table2/module.tsx
@@ -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(TablePanel)
+export const plugin = new PanelPlugin(TablePanel)
.setDefaults(defaults)
.setCustomFieldOptions(builder => {
builder
@@ -15,6 +15,7 @@ export const plugin = new PanelPlugin(TablePanel)
min: 20,
max: 300,
},
+ defaultValue: 1,
})
.addSelect({
id: 'displayMode',
diff --git a/public/app/plugins/panel/table2/types.ts b/public/app/plugins/panel/table2/types.ts
index 6814ce6a60c..d927f72e07a 100644
--- a/public/app/plugins/panel/table2/types.ts
+++ b/public/app/plugins/panel/table2/types.ts
@@ -2,6 +2,11 @@ export interface Options {
showHeader: boolean;
}
+export interface CustomFieldConfig {
+ width: number;
+ displayMode: string;
+}
+
export const defaults: Options = {
showHeader: true,
};