mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Show error when operations, but no stream selector (#47890)
This commit is contained in:
parent
992c0604f9
commit
677327ea07
@ -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…
Reference in New Issue
Block a user