Show error when operations, but no stream selector (#47890)

pull/47897/head
Ivana Huckova 3 years ago committed by GitHub
parent 992c0604f9
commit 677327ea07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.test.tsx
  2. 17
      public/app/plugins/datasource/loki/querybuilder/components/LokiQueryBuilder.tsx
  3. 10
      public/app/plugins/datasource/prometheus/querybuilder/shared/LabelFilters.tsx
  4. 2
      public/app/plugins/datasource/prometheus/querybuilder/testUtils.ts

@ -3,7 +3,7 @@ import { render, screen, getAllByRole, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LokiQueryBuilder } from './LokiQueryBuilder';
import { LokiDatasource } from '../../datasource';
import { LokiVisualQuery } from '../types';
import { LokiOperationId, LokiVisualQuery } from '../types';
import { PanelData } from '@grafana/data';
const defaultQuery: LokiVisualQuery = {
@ -17,10 +17,20 @@ describe('LokiQueryBuilder', () => {
datasource.languageProvider.fetchSeriesLabels = jest.fn().mockReturnValue({ job: ['a'], instance: ['b'] });
userEvent.click(screen.getByLabelText('Add'));
const labels = screen.getByText(/Labels/);
const selects = getAllByRole(labels.parentElement!, 'combobox');
const selects = getAllByRole(labels.parentElement!.parentElement!.parentElement!, 'combobox');
userEvent.click(selects[3]);
await waitFor(() => expect(screen.getByText('job')).toBeInTheDocument());
});
it('shows error for query with operations and no stream selector', async () => {
setup({ labels: [], operations: [{ id: LokiOperationId.Logfmt, params: [] }] });
expect(screen.getByText('You need to specify at least 1 label filter (stream selector)')).toBeInTheDocument();
});
it('shows no error for query with empty __line_contains operation and no stream selector', async () => {
setup({ labels: [], operations: [{ id: LokiOperationId.LineContains, params: [''] }] });
expect(screen.queryByText('You need to specify at least 1 label filter (stream selector)')).not.toBeInTheDocument();
});
});
function setup(query: LokiVisualQuery = defaultQuery, data?: PanelData) {

@ -1,5 +1,5 @@
import React from 'react';
import { LokiVisualQuery } from '../types';
import React, { useMemo } from 'react';
import { LokiOperationId, LokiVisualQuery } from '../types';
import { LokiDatasource } from '../../datasource';
import { LabelFilters } from 'app/plugins/datasource/prometheus/querybuilder/shared/LabelFilters';
import { OperationList } from 'app/plugins/datasource/prometheus/querybuilder/shared/OperationList';
@ -57,6 +57,18 @@ export const LokiQueryBuilder = React.memo<Props>(({ datasource, query, nested,
return result[forLabelInterpolated] ?? [];
};
const labelFilterError: string | undefined = useMemo(() => {
const { labels, operations: op } = query;
if (!labels.length && op.length) {
// We don't want to show error for initial state with empty line contains operation
if (op.length === 1 && op[0].id === LokiOperationId.LineContains && op[0].params[0] === '') {
return undefined;
}
return 'You need to specify at least 1 label filter (stream selector)';
}
return undefined;
}, [query]);
return (
<>
<EditorRow>
@ -69,6 +81,7 @@ export const LokiQueryBuilder = React.memo<Props>(({ datasource, query, nested,
}
labelsFilters={query.labels}
onChange={onChangeLabels}
error={labelFilterError}
/>
</EditorRow>
<OperationsEditorRow>

@ -1,5 +1,6 @@
import { SelectableValue } from '@grafana/data';
import { EditorField, EditorFieldGroup, EditorList } from '@grafana/experimental';
import { EditorFieldGroup, EditorList } from '@grafana/experimental';
import { Field } from '@grafana/ui';
import { isEqual } from 'lodash';
import React, { useEffect, useState } from 'react';
import { QueryBuilderLabelFilter } from '../shared/types';
@ -10,9 +11,10 @@ export interface Props {
onChange: (labelFilters: QueryBuilderLabelFilter[]) => void;
onGetLabelNames: (forLabel: Partial<QueryBuilderLabelFilter>) => Promise<SelectableValue[]>;
onGetLabelValues: (forLabel: Partial<QueryBuilderLabelFilter>) => Promise<SelectableValue[]>;
error?: string;
}
export function LabelFilters({ labelsFilters, onChange, onGetLabelNames, onGetLabelValues }: Props) {
export function LabelFilters({ labelsFilters, onChange, onGetLabelNames, onGetLabelValues, error }: Props) {
const defaultOp = '=';
const [items, setItems] = useState<Array<Partial<QueryBuilderLabelFilter>>>([{ op: defaultOp }]);
@ -36,7 +38,7 @@ export function LabelFilters({ labelsFilters, onChange, onGetLabelNames, onGetLa
return (
<EditorFieldGroup>
<EditorField label="Labels">
<Field label="Labels" error={error} invalid={!!error}>
<EditorList
items={items}
onChange={onLabelsChange}
@ -51,7 +53,7 @@ export function LabelFilters({ labelsFilters, onChange, onGetLabelNames, onGetLa
/>
)}
/>
</EditorField>
</Field>
</EditorFieldGroup>
);
}

@ -2,7 +2,7 @@ import { screen, getAllByRole } from '@testing-library/react';
export function getLabelSelects(index = 0) {
const labels = screen.getByText(/Labels/);
const selects = getAllByRole(labels.parentElement!, 'combobox');
const selects = getAllByRole(labels.parentElement!.parentElement!.parentElement!, 'combobox');
return {
name: selects[3 * index],
value: selects[3 * index + 2],

Loading…
Cancel
Save