Commit cab08243 by Marcus Andersson Committed by GitHub

Fix: prevents the BarGauge from exploding when the datasource returns empty result. (#21791)

* Fixed issue where gauge throw error on empty result.

* Some refactorings to improve the code.

* Added some tests to make sure this doesn't happen again.
parent 8aed8739
import { Vector } from '../types/vector'; import { Vector } from '../types/vector';
import { DataFrame } from '../types/dataFrame'; import { DataFrame } from '../types/dataFrame';
import { DisplayProcessor } from '../types';
/** /**
* This abstraction will present the contents of a DataFrame as if * This abstraction will present the contents of a DataFrame as if
...@@ -55,6 +56,20 @@ export class DataFrameView<T = any> implements Vector<T> { ...@@ -55,6 +56,20 @@ export class DataFrameView<T = any> implements Vector<T> {
return this.data.length; return this.data.length;
} }
getFieldDisplayProcessor(colIndex: number): DisplayProcessor | null {
if (!this.dataFrame || !this.dataFrame.fields) {
return null;
}
const field = this.dataFrame.fields[colIndex];
if (!field || !field.display) {
return null;
}
return field.display;
}
get(idx: number) { get(idx: number) {
this.index = idx; this.index = idx;
return this.obj; return this.obj;
......
...@@ -131,7 +131,8 @@ export class BarGauge extends PureComponent<Props> { ...@@ -131,7 +131,8 @@ export class BarGauge extends PureComponent<Props> {
}; };
} }
const color = display(positionValue).color; const color = display ? display(positionValue).color : null;
if (color) { if (color) {
// if we are past real value the cell is not "on" // if we are past real value the cell is not "on"
if (value === null || (positionValue !== null && positionValue > value.numeric)) { if (value === null || (positionValue !== null && positionValue > value.numeric)) {
......
import React from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { PanelData, dateMath, TimeRange, VizOrientation, PanelProps } from '@grafana/data';
import { BarGaugeDisplayMode } from '@grafana/ui';
import { BarGaugePanel } from './BarGaugePanel';
import { BarGaugeOptions } from './types';
describe('BarGaugePanel', () => {
describe('when empty result is rendered', () => {
const wrapper = createBarGaugePanelWithData({
series: [],
timeRange: null,
state: null,
});
it('should render with title "No data"', () => {
const displayValue = wrapper.find('div.bar-gauge__value').text();
expect(displayValue).toBe('No data');
});
});
});
function createBarGaugePanelWithData(data: PanelData): ReactWrapper<PanelProps<BarGaugeOptions>> {
const timeRange: TimeRange = {
from: dateMath.parse('now-6h'),
to: dateMath.parse('now'),
raw: { from: 'now-6h', to: 'now' },
};
const options: BarGaugeOptions = {
displayMode: BarGaugeDisplayMode.Lcd,
fieldOptions: {
calcs: ['mean'],
defaults: {},
values: false,
overrides: [],
},
orientation: VizOrientation.Horizontal,
showUnfilled: true,
};
return mount<BarGaugePanel>(
<BarGaugePanel
id={1}
data={data}
timeRange={timeRange}
timeZone={'utc'}
options={options}
onOptionsChange={() => {}}
onChangeTimeRange={() => {}}
replaceVariables={s => s}
renderCounter={0}
width={532}
transparent={false}
height={250}
/>
);
}
...@@ -24,7 +24,6 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> { ...@@ -24,7 +24,6 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
): JSX.Element => { ): JSX.Element => {
const { options } = this.props; const { options } = this.props;
const { field, display, view, colIndex } = value; const { field, display, view, colIndex } = value;
const f = view.dataFrame.fields[colIndex];
return ( return (
<DataLinksContextMenu links={getFieldLinksSupplier(value)}> <DataLinksContextMenu links={getFieldLinksSupplier(value)}>
...@@ -36,7 +35,7 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> { ...@@ -36,7 +35,7 @@ export class BarGaugePanel extends PureComponent<PanelProps<BarGaugeOptions>> {
height={height} height={height}
orientation={options.orientation} orientation={options.orientation}
field={field} field={field}
display={f.display!} display={view?.getFieldDisplayProcessor(colIndex)}
theme={config.theme} theme={config.theme}
itemSpacing={this.getItemSpacing()} itemSpacing={this.getItemSpacing()}
displayMode={options.displayMode} displayMode={options.displayMode}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment