mirror of https://github.com/grafana/grafana
FieldConfig: Unify the custom and standard registry (#23307)
* FieldConfig: Unifying standard and custom registry * Adding path to option items to make id be prefixed for custom options * Code updates progress * Add docs back * Fix TS * ld overrides tests from ui to data * Refactor - rename * Gauge and table cleanup * F-I-X e2e Co-authored-by: Dominik Prokop <dominik.prokop@grafana.com>pull/23374/head
parent
6347a1f1eb
commit
b10392733d
@ -0,0 +1,4 @@ |
|||||||
|
import { Registry } from '../utils'; |
||||||
|
import { FieldPropertyEditorItem } from '../types'; |
||||||
|
|
||||||
|
export class FieldConfigOptionsRegistry extends Registry<FieldPropertyEditorItem> {} |
||||||
@ -0,0 +1,170 @@ |
|||||||
|
import { identityOverrideProcessor } from '../../field'; |
||||||
|
import { ThresholdsMode } from '../../types'; |
||||||
|
|
||||||
|
export const mockStandardProperties = () => { |
||||||
|
const title = { |
||||||
|
id: 'title', |
||||||
|
path: 'title', |
||||||
|
name: 'Title', |
||||||
|
description: "Field's title", |
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
settings: { |
||||||
|
placeholder: 'none', |
||||||
|
expandTemplateVars: true, |
||||||
|
}, |
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const unit = { |
||||||
|
id: 'unit', |
||||||
|
path: 'unit', |
||||||
|
name: 'Unit', |
||||||
|
description: 'Value units', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
|
||||||
|
settings: { |
||||||
|
placeholder: 'none', |
||||||
|
}, |
||||||
|
|
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const min = { |
||||||
|
id: 'min', |
||||||
|
path: 'min', |
||||||
|
name: 'Min', |
||||||
|
description: 'Minimum expected value', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
|
||||||
|
settings: { |
||||||
|
placeholder: 'auto', |
||||||
|
}, |
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const max = { |
||||||
|
id: 'max', |
||||||
|
path: 'max', |
||||||
|
name: 'Max', |
||||||
|
description: 'Maximum expected value', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
|
||||||
|
settings: { |
||||||
|
placeholder: 'auto', |
||||||
|
}, |
||||||
|
|
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const decimals = { |
||||||
|
id: 'decimals', |
||||||
|
path: 'decimals', |
||||||
|
name: 'Decimals', |
||||||
|
description: 'Number of decimal to be shown for a value', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
|
||||||
|
settings: { |
||||||
|
placeholder: 'auto', |
||||||
|
min: 0, |
||||||
|
max: 15, |
||||||
|
integer: true, |
||||||
|
}, |
||||||
|
|
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const thresholds = { |
||||||
|
id: 'thresholds', |
||||||
|
path: 'thresholds', |
||||||
|
name: 'Thresholds', |
||||||
|
description: 'Manage thresholds', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
settings: {}, |
||||||
|
defaultValue: { |
||||||
|
mode: ThresholdsMode.Absolute, |
||||||
|
steps: [ |
||||||
|
{ value: -Infinity, color: 'green' }, |
||||||
|
{ value: 80, color: 'red' }, |
||||||
|
], |
||||||
|
}, |
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const mappings = { |
||||||
|
id: 'mappings', |
||||||
|
path: 'mappings', |
||||||
|
name: 'Value mappings', |
||||||
|
description: 'Manage value mappings', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
settings: {}, |
||||||
|
defaultValue: [], |
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const noValue = { |
||||||
|
id: 'noValue', |
||||||
|
path: 'noValue', |
||||||
|
name: 'No Value', |
||||||
|
description: 'What to show when there is no value', |
||||||
|
|
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
|
||||||
|
settings: { |
||||||
|
placeholder: '-', |
||||||
|
}, |
||||||
|
// ??? any optionsUi with no value
|
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const links = { |
||||||
|
id: 'links', |
||||||
|
path: 'links', |
||||||
|
name: 'DataLinks', |
||||||
|
description: 'Manage date links', |
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
settings: { |
||||||
|
placeholder: '-', |
||||||
|
}, |
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
const color = { |
||||||
|
id: 'color', |
||||||
|
path: 'color', |
||||||
|
name: 'Color', |
||||||
|
description: 'Customise color', |
||||||
|
editor: () => null, |
||||||
|
override: () => null, |
||||||
|
process: identityOverrideProcessor, |
||||||
|
settings: { |
||||||
|
placeholder: '-', |
||||||
|
}, |
||||||
|
shouldApply: () => true, |
||||||
|
}; |
||||||
|
|
||||||
|
return [unit, min, max, decimals, title, noValue, thresholds, mappings, links, color]; |
||||||
|
}; |
||||||
@ -1,126 +0,0 @@ |
|||||||
import { |
|
||||||
FieldConfig, |
|
||||||
FieldConfigSource, |
|
||||||
InterpolateFunction, |
|
||||||
GrafanaTheme, |
|
||||||
FieldMatcherID, |
|
||||||
MutableDataFrame, |
|
||||||
DataFrame, |
|
||||||
FieldType, |
|
||||||
applyFieldOverrides, |
|
||||||
toDataFrame, |
|
||||||
standardFieldConfigEditorRegistry, |
|
||||||
standardEditorsRegistry, |
|
||||||
} from '@grafana/data'; |
|
||||||
|
|
||||||
import { getTheme } from '../../themes'; |
|
||||||
import { getStandardFieldConfigs, getStandardOptionEditors } from '../../utils'; |
|
||||||
|
|
||||||
describe('FieldOverrides', () => { |
|
||||||
beforeAll(() => { |
|
||||||
standardEditorsRegistry.setInit(getStandardOptionEditors); |
|
||||||
standardFieldConfigEditorRegistry.setInit(getStandardFieldConfigs); |
|
||||||
}); |
|
||||||
|
|
||||||
const f0 = new MutableDataFrame(); |
|
||||||
f0.add({ title: 'AAA', value: 100, value2: 1234 }, true); |
|
||||||
f0.add({ title: 'BBB', value: -20 }, true); |
|
||||||
f0.add({ title: 'CCC', value: 200, value2: 1000 }, true); |
|
||||||
expect(f0.length).toEqual(3); |
|
||||||
|
|
||||||
// Hardcode the max value
|
|
||||||
f0.fields[1].config.max = 0; |
|
||||||
f0.fields[1].config.decimals = 6; |
|
||||||
|
|
||||||
const src: FieldConfigSource = { |
|
||||||
defaults: { |
|
||||||
unit: 'xyz', |
|
||||||
decimals: 2, |
|
||||||
}, |
|
||||||
overrides: [ |
|
||||||
{ |
|
||||||
matcher: { id: FieldMatcherID.numeric }, |
|
||||||
properties: [ |
|
||||||
{ prop: 'decimals', value: 1 }, // Numeric
|
|
||||||
{ prop: 'title', value: 'Kittens' }, // Text
|
|
||||||
], |
|
||||||
}, |
|
||||||
], |
|
||||||
}; |
|
||||||
|
|
||||||
it('will merge FieldConfig with default values', () => { |
|
||||||
const field: FieldConfig = { |
|
||||||
min: 0, |
|
||||||
max: 100, |
|
||||||
}; |
|
||||||
const f1 = { |
|
||||||
unit: 'ms', |
|
||||||
dateFormat: '', // should be ignored
|
|
||||||
max: parseFloat('NOPE'), // should be ignored
|
|
||||||
min: null, // should alo be ignored!
|
|
||||||
}; |
|
||||||
|
|
||||||
const f: DataFrame = toDataFrame({ |
|
||||||
fields: [{ type: FieldType.number, name: 'x', config: field, values: [] }], |
|
||||||
}); |
|
||||||
const processed = applyFieldOverrides({ |
|
||||||
data: [f], |
|
||||||
standard: standardFieldConfigEditorRegistry, |
|
||||||
fieldOptions: { |
|
||||||
defaults: f1 as FieldConfig, |
|
||||||
overrides: [], |
|
||||||
}, |
|
||||||
replaceVariables: v => v, |
|
||||||
theme: getTheme(), |
|
||||||
})[0]; |
|
||||||
const out = processed.fields[0].config; |
|
||||||
|
|
||||||
expect(out.min).toEqual(0); |
|
||||||
expect(out.max).toEqual(100); |
|
||||||
expect(out.unit).toEqual('ms'); |
|
||||||
}); |
|
||||||
|
|
||||||
it('will apply field overrides', () => { |
|
||||||
const data = applyFieldOverrides({ |
|
||||||
data: [f0], // the frame
|
|
||||||
fieldOptions: src as FieldConfigSource, // defaults + overrides
|
|
||||||
replaceVariables: (undefined as any) as InterpolateFunction, |
|
||||||
theme: (undefined as any) as GrafanaTheme, |
|
||||||
})[0]; |
|
||||||
const valueColumn = data.fields[1]; |
|
||||||
const config = valueColumn.config; |
|
||||||
|
|
||||||
// Keep max from the original setting
|
|
||||||
expect(config.max).toEqual(0); |
|
||||||
|
|
||||||
// Don't Automatically pick the min value
|
|
||||||
expect(config.min).toEqual(undefined); |
|
||||||
|
|
||||||
// The default value applied
|
|
||||||
expect(config.unit).toEqual('xyz'); |
|
||||||
|
|
||||||
// The default value applied
|
|
||||||
expect(config.title).toEqual('Kittens'); |
|
||||||
|
|
||||||
// The override applied
|
|
||||||
expect(config.decimals).toEqual(1); |
|
||||||
}); |
|
||||||
|
|
||||||
it('will apply set min/max when asked', () => { |
|
||||||
const data = applyFieldOverrides({ |
|
||||||
data: [f0], // the frame
|
|
||||||
fieldOptions: src as FieldConfigSource, // defaults + overrides
|
|
||||||
replaceVariables: (undefined as any) as InterpolateFunction, |
|
||||||
theme: (undefined as any) as GrafanaTheme, |
|
||||||
autoMinMax: true, |
|
||||||
})[0]; |
|
||||||
const valueColumn = data.fields[1]; |
|
||||||
const config = valueColumn.config; |
|
||||||
|
|
||||||
// Keep max from the original setting
|
|
||||||
expect(config.max).toEqual(0); |
|
||||||
|
|
||||||
// Don't Automatically pick the min value
|
|
||||||
expect(config.min).toEqual(-20); |
|
||||||
}); |
|
||||||
}); |
|
||||||
@ -1,11 +1,8 @@ |
|||||||
import { PanelPlugin, FieldConfigProperty } from '@grafana/data'; |
import { PanelPlugin } from '@grafana/data'; |
||||||
import { PieChartPanelEditor } from './PieChartPanelEditor'; |
import { PieChartPanelEditor } from './PieChartPanelEditor'; |
||||||
import { PieChartPanel } from './PieChartPanel'; |
import { PieChartPanel } from './PieChartPanel'; |
||||||
import { PieChartOptions, defaults } from './types'; |
import { PieChartOptions, defaults } from './types'; |
||||||
|
|
||||||
export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel) |
export const plugin = new PanelPlugin<PieChartOptions>(PieChartPanel) |
||||||
.setDefaults(defaults) |
.setDefaults(defaults) |
||||||
.useStandardFieldConfig(null, { |
|
||||||
[FieldConfigProperty.Unit]: 'short', |
|
||||||
}) |
|
||||||
.setEditor(PieChartPanelEditor); |
.setEditor(PieChartPanelEditor); |
||||||
|
|||||||
Loading…
Reference in new issue