FieldConfig: set min/max automatically for gauge (#21073)

This commit is contained in:
Ryan McKinley 2019-12-13 08:36:49 -08:00 committed by GitHub
parent e27ab89aed
commit 6de4933a4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 72 additions and 61 deletions

View File

@ -79,6 +79,7 @@ export interface GetFieldDisplayValuesOptions {
replaceVariables: InterpolateFunction; replaceVariables: InterpolateFunction;
sparkline?: boolean; // Calculate the sparkline sparkline?: boolean; // Calculate the sparkline
theme: GrafanaTheme; theme: GrafanaTheme;
autoMinMax?: boolean;
} }
export const DEFAULT_FIELD_DISPLAY_VALUES_LIMIT = 25; export const DEFAULT_FIELD_DISPLAY_VALUES_LIMIT = 25;
@ -90,7 +91,7 @@ export const getFieldDisplayValues = (options: GetFieldDisplayValuesOptions): Fi
const values: FieldDisplay[] = []; const values: FieldDisplay[] = [];
if (options.data) { if (options.data) {
const data = applyFieldOverrides(options.data, fieldOptions, replaceVariables, options.theme); const data = applyFieldOverrides(options);
let hitLimit = false; let hitLimit = false;
const limit = fieldOptions.limit ? fieldOptions.limit : DEFAULT_FIELD_DISPLAY_VALUES_LIMIT; const limit = fieldOptions.limit ? fieldOptions.limit : DEFAULT_FIELD_DISPLAY_VALUES_LIMIT;

View File

@ -2,8 +2,35 @@ import { setFieldConfigDefaults, findNumericFieldMinMax, applyFieldOverrides } f
import { MutableDataFrame } from '../dataframe'; import { MutableDataFrame } from '../dataframe';
import { FieldConfig, FieldConfigSource, InterpolateFunction, GrafanaTheme } from '../types'; import { FieldConfig, FieldConfigSource, InterpolateFunction, GrafanaTheme } from '../types';
import { FieldMatcherID } from '../transformations'; import { FieldMatcherID } from '../transformations';
import { FieldDisplayOptions } from './fieldDisplay';
describe('FieldOverrides', () => { describe('FieldOverrides', () => {
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: [
{ path: 'decimals', value: 1 }, // Numeric
{ path: 'title', value: 'Kittens' }, // Text
],
},
],
};
it('will merge FieldConfig with default values', () => { it('will merge FieldConfig with default values', () => {
const field: FieldConfig = { const field: FieldConfig = {
min: 0, min: 0,
@ -22,46 +49,20 @@ describe('FieldOverrides', () => {
}); });
it('will apply field overrides', () => { it('will apply field overrides', () => {
const f0 = new MutableDataFrame(); const data = applyFieldOverrides({
f0.add({ title: 'AAA', value: 100, value2: 1234 }, true); data: [f0], // the frame
f0.add({ title: 'BBB', value: -20 }, true); fieldOptions: src as FieldDisplayOptions, // defaults + overrides
f0.add({ title: 'CCC', value: 200, value2: 1000 }, true); replaceVariables: (undefined as any) as InterpolateFunction,
expect(f0.length).toEqual(3); theme: (undefined as any) as GrafanaTheme,
})[0];
// 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: [
{ path: 'decimals', value: 1 }, // Numeric
{ path: 'title', value: 'Kittens' }, // Text
],
},
],
};
const data = applyFieldOverrides(
[f0], // the frame
src, // defaults + overrides
(undefined as any) as InterpolateFunction,
(undefined as any) as GrafanaTheme
)[0];
const valueColumn = data.fields[1]; const valueColumn = data.fields[1];
const config = valueColumn.config; const config = valueColumn.config;
// Keep max from the original setting // Keep max from the original setting
expect(config.max).toEqual(0); expect(config.max).toEqual(0);
// Automatically pick the min value // Don't Automatically pick the min value
expect(config.min).toEqual(-20); expect(config.min).toEqual(undefined);
// The default value applied // The default value applied
expect(config.unit).toEqual('xyz'); expect(config.unit).toEqual('xyz');
@ -72,6 +73,24 @@ describe('FieldOverrides', () => {
// The override applied // The override applied
expect(config.decimals).toEqual(1); expect(config.decimals).toEqual(1);
}); });
it('will apply set min/max when asked', () => {
const data = applyFieldOverrides({
data: [f0], // the frame
fieldOptions: src as FieldDisplayOptions, // 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);
});
}); });
describe('Global MinMax', () => { describe('Global MinMax', () => {

View File

@ -1,19 +1,11 @@
import set from 'lodash/set'; import set from 'lodash/set';
import { import { DynamicConfigValue, FieldConfig, InterpolateFunction, DataFrame, Field, FieldType } from '../types';
DynamicConfigValue,
FieldConfigSource,
FieldConfig,
InterpolateFunction,
GrafanaTheme,
DataFrame,
Field,
FieldType,
} from '../types';
import { fieldMatchers, ReducerID, reduceField } from '../transformations'; import { fieldMatchers, ReducerID, reduceField } from '../transformations';
import { FieldMatcher } from '../types/transformations'; import { FieldMatcher } from '../types/transformations';
import isNumber from 'lodash/isNumber'; import isNumber from 'lodash/isNumber';
import toNumber from 'lodash/toNumber'; import toNumber from 'lodash/toNumber';
import { getDisplayProcessor } from './displayProcessor'; import { getDisplayProcessor } from './displayProcessor';
import { GetFieldDisplayValuesOptions } from './fieldDisplay';
interface OverrideProps { interface OverrideProps {
match: FieldMatcher; match: FieldMatcher;
@ -50,15 +42,13 @@ export function findNumericFieldMinMax(data: DataFrame[]): GlobalMinMax {
/** /**
* Return a copy of the DataFrame with all rules applied * Return a copy of the DataFrame with all rules applied
*/ */
export function applyFieldOverrides( export function applyFieldOverrides(options: GetFieldDisplayValuesOptions): DataFrame[] {
data: DataFrame[], if (!options.data) {
source: FieldConfigSource, return [];
replaceVariables: InterpolateFunction, }
theme: GrafanaTheme, const source = options.fieldOptions;
isUtc?: boolean
): DataFrame[] {
if (!source) { if (!source) {
return data; return options.data;
} }
let range: GlobalMinMax | undefined = undefined; let range: GlobalMinMax | undefined = undefined;
@ -76,7 +66,7 @@ export function applyFieldOverrides(
} }
} }
return data.map((frame, index) => { return options.data.map((frame, index) => {
let name = frame.name; let name = frame.name;
if (!name) { if (!name) {
name = `Series[${index}]`; name = `Series[${index}]`;
@ -98,17 +88,17 @@ export function applyFieldOverrides(
config, config,
field, field,
data: frame, data: frame,
replaceVariables, replaceVariables: options.replaceVariables,
}); });
} }
} }
} }
// Set the Min/Max value automatically // Set the Min/Max value automatically
if (field.type === FieldType.number) { if (options.autoMinMax && field.type === FieldType.number) {
if (!isNumber(config.min) || !isNumber(config.max)) { if (!isNumber(config.min) || !isNumber(config.max)) {
if (!range) { if (!range) {
range = findNumericFieldMinMax(data); range = findNumericFieldMinMax(options.data!); // Global value
} }
if (!isNumber(config.min)) { if (!isNumber(config.min)) {
config.min = range.min; config.min = range.min;
@ -129,8 +119,7 @@ export function applyFieldOverrides(
processor: getDisplayProcessor({ processor: getDisplayProcessor({
type: field.type, type: field.type,
config: config, config: config,
theme, theme: options.theme,
isUtc,
}), }),
}; };
}); });

View File

@ -111,6 +111,7 @@ export const FieldPropertiesEditor: React.FC<Props> = ({ value, onChange, showMi
onChange={onMinChange} onChange={onMinChange}
onBlur={commitChanges} onBlur={commitChanges}
value={min} value={min}
placeholder="Auto"
type="number" type="number"
/> />
<FormField <FormField
@ -120,6 +121,7 @@ export const FieldPropertiesEditor: React.FC<Props> = ({ value, onChange, showMi
onBlur={commitChanges} onBlur={commitChanges}
value={max} value={max}
type="number" type="number"
placeholder="Auto"
/> />
</> </>
)} )}

View File

@ -57,6 +57,7 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
replaceVariables, replaceVariables,
theme: config.theme, theme: config.theme,
data: data.series, data: data.series,
autoMinMax: true,
}); });
}; };

View File

@ -48,6 +48,7 @@ export class GaugePanel extends PureComponent<PanelProps<GaugeOptions>> {
replaceVariables, replaceVariables,
theme: config.theme, theme: config.theme,
data: data.series, data: data.series,
autoMinMax: true,
}); });
}; };

View File

@ -27,8 +27,6 @@ export const standardFieldDisplayOptions: FieldDisplayOptions = {
values: false, values: false,
calcs: [ReducerID.mean], calcs: [ReducerID.mean],
defaults: { defaults: {
min: 0,
max: 100,
thresholds: [ thresholds: [
{ value: -Infinity, color: 'green' }, { value: -Infinity, color: 'green' },
{ value: 80, color: 'red' }, // 80% { value: 80, color: 'red' }, // 80%