The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/public/app/features/dashboard/state/getPanelOptionsWithDefaults...

419 lines
11 KiB

import {
ConfigOverrideRule,
FieldColorModeId,
FieldConfig,
FieldConfigProperty,
FieldConfigSource,
PanelPlugin,
standardEditorsRegistry,
standardFieldConfigEditorRegistry,
StandardOptionConfig,
ThresholdsMode,
} from '@grafana/data';
import { getPanelPlugin } from 'app/features/plugins/__mocks__/pluginMocks';
import { mockStandardFieldConfigOptions } from 'test/helpers/fieldConfig';
import { getPanelOptionsWithDefaults, restoreCustomOverrideRules } from './getPanelOptionsWithDefaults';
standardFieldConfigEditorRegistry.setInit(() => mockStandardFieldConfigOptions());
standardEditorsRegistry.setInit(() => mockStandardFieldConfigOptions());
const pluginA = getPanelPlugin({ id: 'graph' });
pluginA.useFieldConfig({
useCustomConfig: (builder) => {
builder.addBooleanSwitch({
name: 'Hide lines',
path: 'hideLines',
defaultValue: false,
});
},
});
pluginA.setPanelOptions((builder) => {
builder.addBooleanSwitch({
name: 'Show thresholds',
path: 'showThresholds',
defaultValue: true,
});
builder.addTextInput({
name: 'Name',
path: 'name',
defaultValue: 'hello',
});
builder.addNumberInput({
name: 'Number',
path: 'number',
defaultValue: 10,
});
});
describe('getPanelOptionsWithDefaults', () => {
describe('When panel plugin has no options', () => {
it('Should set defaults', () => {
const result = runScenario({
plugin: getPanelPlugin({ id: 'graph' }),
options: {},
defaults: {},
overrides: [],
});
expect(result).toMatchInlineSnapshot(`
Object {
"fieldConfig": Object {
"defaults": Object {},
"overrides": Array [],
},
"options": Object {},
}
`);
});
});
describe('When current options are emtpy', () => {
it('Should set defaults', () => {
const result = getPanelOptionsWithDefaults({
plugin: pluginA,
currentOptions: {},
currentFieldConfig: {
defaults: {},
overrides: [],
},
isAfterPluginChange: false,
});
expect(result).toMatchInlineSnapshot(`
Object {
"fieldConfig": Object {
"defaults": Object {
"custom": Object {
"hideLines": false,
},
"thresholds": Object {
"mode": "absolute",
"steps": Array [
Object {
"color": "green",
"value": -Infinity,
},
Object {
"color": "red",
"value": 80,
},
],
},
},
"overrides": Array [],
},
"options": Object {
"name": "hello",
"number": 10,
"showThresholds": true,
},
}
`);
});
});
describe('When there are current options and overrides', () => {
it('Should set defaults', () => {
const result = getPanelOptionsWithDefaults({
plugin: pluginA,
currentOptions: {
number: 20,
showThresholds: false,
},
currentFieldConfig: {
defaults: {
unit: 'bytes',
decimals: 2,
},
overrides: [],
},
isAfterPluginChange: true,
});
expect(result).toMatchInlineSnapshot(`
Object {
"fieldConfig": Object {
"defaults": Object {
"custom": Object {
"hideLines": false,
},
"decimals": 2,
"thresholds": Object {
"mode": "absolute",
"steps": Array [
Object {
"color": "green",
"value": -Infinity,
},
Object {
"color": "red",
"value": 80,
},
],
},
"unit": "bytes",
},
"overrides": Array [],
},
"options": Object {
"name": "hello",
"number": 20,
"showThresholds": false,
},
}
`);
});
});
describe('when changing panel type to one that does not support by value color mode', () => {
it('should change color mode', () => {
const plugin = getPanelPlugin({ id: 'graph' }).useFieldConfig({
standardOptions: {
[FieldConfigProperty.Color]: {
settings: {
byValueSupport: false,
},
},
},
});
const result = getPanelOptionsWithDefaults({
plugin,
currentOptions: {},
currentFieldConfig: {
defaults: {
color: { mode: FieldColorModeId.Thresholds },
},
overrides: [],
},
isAfterPluginChange: true,
});
expect(result.fieldConfig.defaults.color!.mode).toBe(FieldColorModeId.PaletteClassic);
});
});
describe('when changing panel type from one not supporting by value color mode to one that supports it', () => {
it('should keep supported mode', () => {
const result = runScenario({
defaults: {
color: { mode: FieldColorModeId.PaletteClassic },
},
standardOptions: {
[FieldConfigProperty.Color]: {
settings: {
byValueSupport: true,
},
},
},
});
expect(result.fieldConfig.defaults.color!.mode).toBe(FieldColorModeId.PaletteClassic);
});
it('should change to thresholds mode when it prefers to', () => {
const result = runScenario({
defaults: {
color: { mode: FieldColorModeId.PaletteClassic },
},
standardOptions: {
[FieldConfigProperty.Color]: {
settings: {
byValueSupport: true,
preferThresholdsMode: true,
},
},
},
isAfterPluginChange: true,
});
expect(result.fieldConfig.defaults.color!.mode).toBe(FieldColorModeId.Thresholds);
});
});
describe('when changing panel type to one that does not use standard field config', () => {
it('should clean defaults', () => {
const plugin = getPanelPlugin({ id: 'graph' });
const result = getPanelOptionsWithDefaults({
plugin,
currentOptions: {},
currentFieldConfig: {
defaults: {
color: { mode: FieldColorModeId.Thresholds },
thresholds: {
mode: ThresholdsMode.Absolute,
steps: [],
},
},
overrides: [],
},
isAfterPluginChange: true,
});
expect(result.fieldConfig.defaults.thresholds).toBeUndefined();
});
});
describe('when applying defaults clean properties that are no longer part of the registry', () => {
it('should remove custom defaults that no longer exist', () => {
const result = runScenario({
defaults: {
unit: 'bytes',
custom: {
customProp: 20,
customPropNoExist: true,
nested: {
nestedA: 'A',
nestedB: 'B',
},
},
},
});
expect(result.fieldConfig.defaults).toMatchInlineSnapshot(`
Object {
"custom": Object {
"customProp": 20,
"nested": Object {
"nestedA": "A",
},
},
"thresholds": Object {
"mode": "absolute",
"steps": Array [
Object {
"color": "green",
"value": -Infinity,
},
Object {
"color": "red",
"value": 80,
},
],
},
"unit": "bytes",
}
`);
});
it('should remove custom overrides that no longer exist', () => {
const result = runScenario({
defaults: {},
overrides: [
{
matcher: { id: 'byName', options: 'D-series' },
properties: [
{
id: 'custom.customPropNoExist',
value: 'google',
},
],
},
{
matcher: { id: 'byName', options: 'D-series' },
properties: [
{
id: 'custom.customProp',
value: 30,
},
],
},
],
});
expect(result.fieldConfig.overrides.length).toBe(1);
expect(result.fieldConfig.overrides[0].properties[0].id).toBe('custom.customProp');
});
});
});
describe('restoreCustomOverrideRules', () => {
it('should add back custom rules', () => {
const current = {
defaults: {},
overrides: [
{
matcher: { id: 'byName', options: 'SeriesA' },
properties: [
{
id: 'decimals',
value: 2,
},
],
},
],
};
const old = {
defaults: {},
overrides: [
{
matcher: { id: 'byName', options: 'SeriesA' },
properties: [
{
id: 'custom.propName',
value: 10,
},
],
},
{
matcher: { id: 'byName', options: 'SeriesB' },
properties: [
{
id: 'custom.propName',
value: 20,
},
],
},
],
};
const result = restoreCustomOverrideRules(current, old);
expect(result.overrides.length).toBe(2);
expect(result.overrides[0].properties[0].id).toBe('decimals');
expect(result.overrides[0].properties[1].id).toBe('custom.propName');
expect(result.overrides[1].properties.length).toBe(1);
expect(result.overrides[1].matcher.options).toBe('SeriesB');
});
});
interface ScenarioOptions {
defaults?: FieldConfig<any>;
overrides?: ConfigOverrideRule[];
disabledStandardOptions?: FieldConfigProperty[];
standardOptions?: Partial<Record<FieldConfigProperty, StandardOptionConfig>>;
plugin?: PanelPlugin;
options?: any;
isAfterPluginChange?: boolean;
}
function runScenario(options: ScenarioOptions) {
const fieldConfig: FieldConfigSource = {
defaults: options.defaults || {},
overrides: options.overrides || [],
};
const plugin =
options.plugin ??
getPanelPlugin({ id: 'graph' }).useFieldConfig({
standardOptions: options.standardOptions,
useCustomConfig: (builder) => {
builder.addNumberInput({
name: 'Custom prop',
path: 'customProp',
defaultValue: 10,
});
builder.addTextInput({
name: 'Nested prop',
path: 'nested.nestedA',
});
},
});
return getPanelOptionsWithDefaults({
plugin,
currentOptions: options.options || {},
currentFieldConfig: fieldConfig,
isAfterPluginChange: !!options.isAfterPluginChange,
});
}