mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
QueryEditorRow: Render frame warnings in QueryEditorRow (#50116)
This commit is contained in:
parent
14edc6f1db
commit
3ab410de0b
@ -1,6 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import { DataQueryRequest, dateTime, LoadingState, PanelData, toDataFrame } from '@grafana/data';
|
||||
|
||||
import { filterPanelDataToQuery } from './QueryEditorRow';
|
||||
import { filterPanelDataToQuery, QueryEditorRow } from './QueryEditorRow';
|
||||
|
||||
function makePretendRequest(requestId: string, subRequests?: DataQueryRequest[]): DataQueryRequest {
|
||||
return {
|
||||
@ -108,3 +110,77 @@ describe('filterPanelDataToQuery', () => {
|
||||
expect(panelDataA?.state).toBe(LoadingState.Loading);
|
||||
});
|
||||
});
|
||||
|
||||
describe('frame results with warnings', () => {
|
||||
const meta = {
|
||||
notices: [
|
||||
{
|
||||
severity: 'warning',
|
||||
text: 'Reduce operation is not needed. Input query or expression A is already reduced data.',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dataWithWarnings: PanelData = {
|
||||
state: LoadingState.Done,
|
||||
series: [
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B1' }],
|
||||
meta,
|
||||
}),
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B2' }],
|
||||
meta,
|
||||
}),
|
||||
],
|
||||
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||
};
|
||||
|
||||
const dataWithoutWarnings: PanelData = {
|
||||
state: LoadingState.Done,
|
||||
series: [
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B1' }],
|
||||
meta: {},
|
||||
}),
|
||||
toDataFrame({
|
||||
refId: 'B',
|
||||
fields: [{ name: 'B2' }],
|
||||
meta: {},
|
||||
}),
|
||||
],
|
||||
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||
};
|
||||
|
||||
it('should show a warning badge and de-duplicate warning messages', () => {
|
||||
// @ts-ignore: there are _way_ too many props to inject here :(
|
||||
const editorRow = new QueryEditorRow({
|
||||
data: dataWithWarnings,
|
||||
query: {
|
||||
refId: 'B',
|
||||
},
|
||||
});
|
||||
|
||||
const warningsComponent = editorRow.renderWarnings();
|
||||
expect(warningsComponent).not.toBe(null);
|
||||
|
||||
render(warningsComponent!);
|
||||
expect(screen.getByText('1 warning')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not show a warning badge when there are no warnings', () => {
|
||||
// @ts-ignore: there are _way_ too many props to inject here :(
|
||||
const editorRow = new QueryEditorRow({
|
||||
data: dataWithoutWarnings,
|
||||
query: {
|
||||
refId: 'B',
|
||||
},
|
||||
});
|
||||
|
||||
const warningsComponent = editorRow.renderWarnings();
|
||||
expect(warningsComponent).toBe(null);
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Libraries
|
||||
import classNames from 'classnames';
|
||||
import { cloneDeep, has } from 'lodash';
|
||||
import { cloneDeep, filter, has, uniqBy } from 'lodash';
|
||||
import pluralize from 'pluralize';
|
||||
import React, { PureComponent, ReactNode } from 'react';
|
||||
|
||||
// Utils & Services
|
||||
@ -15,12 +16,13 @@ import {
|
||||
LoadingState,
|
||||
PanelData,
|
||||
PanelEvents,
|
||||
QueryResultMetaNotice,
|
||||
TimeRange,
|
||||
toLegacyResponseData,
|
||||
} from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
||||
import { ErrorBoundaryAlert, HorizontalGroup } from '@grafana/ui';
|
||||
import { Badge, ErrorBoundaryAlert, HorizontalGroup } from '@grafana/ui';
|
||||
import { OperationRowHelp } from 'app/core/components/QueryOperationRow/OperationRowHelp';
|
||||
import { QueryOperationAction } from 'app/core/components/QueryOperationRow/QueryOperationAction';
|
||||
import {
|
||||
@ -307,9 +309,46 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
||||
return null;
|
||||
}
|
||||
|
||||
renderWarnings = (): JSX.Element | null => {
|
||||
const { data, query } = this.props;
|
||||
const dataFilteredByRefId = filterPanelDataToQuery(data, query.refId)?.series ?? [];
|
||||
|
||||
const allWarnings = dataFilteredByRefId.reduce((acc: QueryResultMetaNotice[], serie) => {
|
||||
if (!serie.meta?.notices) {
|
||||
return acc;
|
||||
}
|
||||
|
||||
const warnings = filter(serie.meta.notices, { severity: 'warning' }) ?? [];
|
||||
return acc.concat(warnings);
|
||||
}, []);
|
||||
|
||||
const uniqueWarnings = uniqBy(allWarnings, 'text');
|
||||
|
||||
const hasWarnings = uniqueWarnings.length > 0;
|
||||
if (!hasWarnings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const serializedWarnings = uniqueWarnings.map((warning) => warning.text).join('\n');
|
||||
|
||||
return (
|
||||
<Badge
|
||||
color="orange"
|
||||
icon="exclamation-triangle"
|
||||
text={
|
||||
<>
|
||||
{uniqueWarnings.length} {pluralize('warning', uniqueWarnings.length)}
|
||||
</>
|
||||
}
|
||||
tooltip={serializedWarnings}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderExtraActions = () => {
|
||||
const { query, queries, data, onAddQuery, dataSource } = this.props;
|
||||
return RowActionComponents.getAllExtraRenderAction()
|
||||
|
||||
const extraActions = RowActionComponents.getAllExtraRenderAction()
|
||||
.map((action, index) =>
|
||||
action({
|
||||
query,
|
||||
@ -321,6 +360,10 @@ export class QueryEditorRow<TQuery extends DataQuery> extends PureComponent<Prop
|
||||
})
|
||||
)
|
||||
.filter(Boolean);
|
||||
|
||||
extraActions.push(this.renderWarnings());
|
||||
|
||||
return extraActions;
|
||||
};
|
||||
|
||||
renderActions = (props: QueryOperationRowRenderProps) => {
|
||||
|
Loading…
Reference in New Issue
Block a user