mirror of
https://github.com/grafana/grafana.git
synced 2024-11-29 12:14:08 -06:00
Table: Fix case where undefined data crashes the visualization (#80498)
This commit is contained in:
parent
a7b58a7cdb
commit
cd2abce914
@ -179,6 +179,9 @@ exports[`better eslint`] = {
|
||||
"packages/grafana-data/src/themes/createColors.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
"packages/grafana-data/src/transformations/fieldReducer.test.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
"packages/grafana-data/src/transformations/matchers/valueMatchers/types.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "1"]
|
||||
|
@ -124,7 +124,7 @@ describe('Global MinMax', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when value values are zeo', () => {
|
||||
describe('when values are zero', () => {
|
||||
it('then global min max should be correct', () => {
|
||||
const frame = toDataFrame({
|
||||
fields: [
|
||||
|
@ -3,7 +3,7 @@ import { difference } from 'lodash';
|
||||
import { createDataFrame, guessFieldTypeFromValue } from '../dataframe/processDataFrame';
|
||||
import { Field, FieldType, NullValueMode } from '../types/index';
|
||||
|
||||
import { fieldReducers, ReducerID, reduceField } from './fieldReducer';
|
||||
import { fieldReducers, ReducerID, reduceField, defaultCalcs } from './fieldReducer';
|
||||
|
||||
/**
|
||||
* Run a reducer and get back the value
|
||||
@ -63,6 +63,16 @@ describe('Stats Calculators', () => {
|
||||
expect(stats.count).toEqual(2);
|
||||
});
|
||||
|
||||
it('should handle undefined field data without crashing', () => {
|
||||
// eslint-ignore @typescript-eslint/no-explicit-any
|
||||
const stats = reduceField({
|
||||
field: { name: 'a', values: undefined as any, config: {}, type: FieldType.number },
|
||||
reducers: [ReducerID.first, ReducerID.last, ReducerID.mean, ReducerID.count],
|
||||
});
|
||||
|
||||
expect(stats).toEqual(defaultCalcs);
|
||||
});
|
||||
|
||||
it('should support a single stat also', () => {
|
||||
basicTable.fields[0].state = undefined; // clear the cache
|
||||
const stats = reduceField({
|
||||
|
@ -84,7 +84,7 @@ export function reduceField(options: ReduceFieldOptions): FieldCalcs {
|
||||
// Return early for empty series
|
||||
// This lets the concrete implementations assume at least one row
|
||||
const data = field.values;
|
||||
if (data.length < 1) {
|
||||
if (data && data.length < 1) {
|
||||
const calcs: FieldCalcs = { ...field.state.calcs };
|
||||
for (const reducer of queue) {
|
||||
calcs[reducer.id] = reducer.emptyInputResult !== null ? reducer.emptyInputResult : null;
|
||||
@ -271,33 +271,41 @@ export const fieldReducers = new Registry<FieldReducerInfo>(() => [
|
||||
},
|
||||
]);
|
||||
|
||||
export function doStandardCalcs(field: Field, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||
const calcs: FieldCalcs = {
|
||||
sum: 0,
|
||||
max: -Number.MAX_VALUE,
|
||||
min: Number.MAX_VALUE,
|
||||
logmin: Number.MAX_VALUE,
|
||||
mean: null,
|
||||
last: null,
|
||||
first: null,
|
||||
lastNotNull: null,
|
||||
firstNotNull: null,
|
||||
count: 0,
|
||||
nonNullCount: 0,
|
||||
allIsNull: true,
|
||||
allIsZero: true,
|
||||
range: null,
|
||||
diff: null,
|
||||
delta: 0,
|
||||
step: Number.MAX_VALUE,
|
||||
diffperc: 0,
|
||||
// Used for test cases
|
||||
export const defaultCalcs: FieldCalcs = {
|
||||
sum: 0,
|
||||
max: -Number.MAX_VALUE,
|
||||
min: Number.MAX_VALUE,
|
||||
logmin: Number.MAX_VALUE,
|
||||
mean: null,
|
||||
last: null,
|
||||
first: null,
|
||||
lastNotNull: null,
|
||||
firstNotNull: null,
|
||||
count: 0,
|
||||
nonNullCount: 0,
|
||||
allIsNull: true,
|
||||
allIsZero: true,
|
||||
range: null,
|
||||
diff: null,
|
||||
delta: 0,
|
||||
step: Number.MAX_VALUE,
|
||||
diffperc: 0,
|
||||
|
||||
// Just used for calculations -- not exposed as a stat
|
||||
previousDeltaUp: true,
|
||||
};
|
||||
// Just used for calculations -- not exposed as a stat
|
||||
previousDeltaUp: true,
|
||||
};
|
||||
|
||||
export function doStandardCalcs(field: Field, ignoreNulls: boolean, nullAsZero: boolean): FieldCalcs {
|
||||
const calcs: FieldCalcs = { ...defaultCalcs };
|
||||
|
||||
const data = field.values;
|
||||
|
||||
// early return for undefined / empty series
|
||||
if (!data) {
|
||||
return calcs;
|
||||
}
|
||||
|
||||
const isNumberField = field.type === FieldType.number || field.type === FieldType.time;
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
Loading…
Reference in New Issue
Block a user