mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
BarChart: Use new data error view component to show actions in panel edit (#42474)
This commit is contained in:
parent
a0333c1545
commit
8828d5e8d7
@ -12,6 +12,7 @@ export interface PanelDataErrorViewProps {
|
||||
data: PanelData;
|
||||
needsTimeField?: boolean;
|
||||
needsNumberField?: boolean;
|
||||
needsStringField?: boolean;
|
||||
// suggestions?: VisualizationSuggestion[]; <<< for sure optional
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ export function PanelDataErrorView(props: PanelDataErrorViewProps) {
|
||||
}
|
||||
|
||||
function getMessageFor(
|
||||
{ data, message, needsNumberField, needsTimeField }: PanelDataErrorViewProps,
|
||||
{ data, message, needsNumberField, needsTimeField, needsStringField }: PanelDataErrorViewProps,
|
||||
dataSummary: PanelDataSummary
|
||||
): string {
|
||||
if (message) {
|
||||
@ -68,6 +68,10 @@ function getMessageFor(
|
||||
return 'No data';
|
||||
}
|
||||
|
||||
if (needsStringField && !dataSummary.hasStringField) {
|
||||
return 'Data is missing a string field';
|
||||
}
|
||||
|
||||
if (needsNumberField && !dataSummary.hasNumberField) {
|
||||
return 'Data is missing a number field';
|
||||
}
|
||||
|
@ -5,16 +5,17 @@ import { measureText, TooltipPlugin, UPLOT_AXIS_FONT_SIZE, useTheme2 } from '@gr
|
||||
import { BarChartOptions } from './types';
|
||||
import { BarChart } from './BarChart';
|
||||
import { prepareGraphableFrames } from './utils';
|
||||
import { PanelDataErrorView } from '@grafana/runtime';
|
||||
|
||||
interface Props extends PanelProps<BarChartOptions> {}
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
export const BarChartPanel: React.FunctionComponent<Props> = ({ data, options, width, height, timeZone }) => {
|
||||
export const BarChartPanel: React.FunctionComponent<Props> = ({ data, options, width, height, timeZone, id }) => {
|
||||
const theme = useTheme2();
|
||||
|
||||
const { frames, warn } = useMemo(() => prepareGraphableFrames(data?.series, theme, options), [data, theme, options]);
|
||||
const frames = useMemo(() => prepareGraphableFrames(data?.series, theme, options), [data, theme, options]);
|
||||
const orientation = useMemo(() => {
|
||||
if (!options.orientation || options.orientation === VizOrientation.Auto) {
|
||||
return width < height ? VizOrientation.Horizontal : VizOrientation.Vertical;
|
||||
@ -48,12 +49,8 @@ export const BarChartPanel: React.FunctionComponent<Props> = ({ data, options, w
|
||||
return options.tooltip;
|
||||
}, [options.tooltip, options.stacking]);
|
||||
|
||||
if (!frames || warn) {
|
||||
return (
|
||||
<div className="panel-empty">
|
||||
<p>{warn ?? 'No data found in response'}</p>
|
||||
</div>
|
||||
);
|
||||
if (!frames) {
|
||||
return <PanelDataErrorView panelId={id} data={data} needsStringField={true} needsNumberField={true} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -147,7 +147,7 @@ describe('BarChart utils', () => {
|
||||
describe('prepareGraphableFrames', () => {
|
||||
it('will warn when there is no data in the response', () => {
|
||||
const result = prepareGraphableFrames([], createTheme(), { stacking: StackingMode.None } as any);
|
||||
expect(result.warn).toEqual('No data in response');
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('will warn when there is no string field in the response', () => {
|
||||
@ -158,8 +158,7 @@ describe('BarChart utils', () => {
|
||||
],
|
||||
});
|
||||
const result = prepareGraphableFrames([df], createTheme(), { stacking: StackingMode.None } as any);
|
||||
expect(result.warn).toEqual('Bar charts requires a string field');
|
||||
expect(result.frames).toBeUndefined();
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('will warn when there are no numeric fields in the response', () => {
|
||||
@ -170,8 +169,7 @@ describe('BarChart utils', () => {
|
||||
],
|
||||
});
|
||||
const result = prepareGraphableFrames([df], createTheme(), { stacking: StackingMode.None } as any);
|
||||
expect(result.warn).toEqual('No numeric fields found');
|
||||
expect(result.frames).toBeUndefined();
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
it('will convert NaN and Infinty to nulls', () => {
|
||||
@ -181,9 +179,9 @@ describe('BarChart utils', () => {
|
||||
{ name: 'value', values: [-10, NaN, 10, -Infinity, +Infinity] },
|
||||
],
|
||||
});
|
||||
const result = prepareGraphableFrames([df], createTheme(), { stacking: StackingMode.None } as any);
|
||||
const frames = prepareGraphableFrames([df], createTheme(), { stacking: StackingMode.None } as any)!;
|
||||
|
||||
const field = result.frames![0].fields[1];
|
||||
const field = frames[0].fields[1];
|
||||
expect(field!.values.toArray()).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
-10,
|
||||
@ -205,21 +203,23 @@ describe('BarChart utils', () => {
|
||||
],
|
||||
});
|
||||
|
||||
const resultAsc = prepareGraphableFrames([frame], createTheme(), {
|
||||
const framesAsc = prepareGraphableFrames([frame], createTheme(), {
|
||||
legend: { sortBy: 'Min', sortDesc: false },
|
||||
} as any);
|
||||
expect(resultAsc.frames![0].fields[0].type).toBe(FieldType.string);
|
||||
expect(resultAsc.frames![0].fields[1].name).toBe('a');
|
||||
expect(resultAsc.frames![0].fields[2].name).toBe('c');
|
||||
expect(resultAsc.frames![0].fields[3].name).toBe('b');
|
||||
} as any)!;
|
||||
|
||||
const resultDesc = prepareGraphableFrames([frame], createTheme(), {
|
||||
expect(framesAsc[0].fields[0].type).toBe(FieldType.string);
|
||||
expect(framesAsc[0].fields[1].name).toBe('a');
|
||||
expect(framesAsc[0].fields[2].name).toBe('c');
|
||||
expect(framesAsc[0].fields[3].name).toBe('b');
|
||||
|
||||
const framesDesc = prepareGraphableFrames([frame], createTheme(), {
|
||||
legend: { sortBy: 'Min', sortDesc: true },
|
||||
} as any);
|
||||
expect(resultDesc.frames![0].fields[0].type).toBe(FieldType.string);
|
||||
expect(resultDesc.frames![0].fields[1].name).toBe('b');
|
||||
expect(resultDesc.frames![0].fields[2].name).toBe('c');
|
||||
expect(resultDesc.frames![0].fields[3].name).toBe('a');
|
||||
} as any)!;
|
||||
|
||||
expect(framesDesc[0].fields[0].type).toBe(FieldType.string);
|
||||
expect(framesDesc[0].fields[1].name).toBe('b');
|
||||
expect(framesDesc[0].fields[2].name).toBe('c');
|
||||
expect(framesDesc[0].fields[3].name).toBe('a');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -298,24 +298,20 @@ export function prepareGraphableFrames(
|
||||
series: DataFrame[],
|
||||
theme: GrafanaTheme2,
|
||||
options: BarChartOptions
|
||||
): { frames?: DataFrame[]; warn?: string } {
|
||||
): DataFrame[] | null {
|
||||
if (!series?.length) {
|
||||
return { warn: 'No data in response' };
|
||||
return null;
|
||||
}
|
||||
|
||||
const frames: DataFrame[] = [];
|
||||
const firstFrame = series[0];
|
||||
|
||||
if (!firstFrame.fields.some((f) => f.type === FieldType.string)) {
|
||||
return {
|
||||
warn: 'Bar charts requires a string field',
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!firstFrame.fields.some((f) => f.type === FieldType.number)) {
|
||||
return {
|
||||
warn: 'No numeric fields found',
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
const legendOrdered = isLegendOrdered(options.legend);
|
||||
@ -384,7 +380,7 @@ export function prepareGraphableFrames(
|
||||
});
|
||||
}
|
||||
|
||||
return { frames };
|
||||
return frames;
|
||||
}
|
||||
|
||||
export const isLegendOrdered = (options: VizLegendOptions) => Boolean(options?.sortBy && options.sortDesc !== null);
|
||||
|
Loading…
Reference in New Issue
Block a user