Alerting: Fix UI toggles and search input synchronization (#64751)

* Fix UI toggles and search input synchronization

* Fix lint
This commit is contained in:
Konrad Lalik 2023-03-15 09:17:50 +01:00 committed by GitHub
parent 4583fe58f3
commit 51974c54d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 70 additions and 17 deletions

View File

@ -1,10 +1,13 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byLabelText, byRole } from 'testing-library-selector';
import { logInfo } from '@grafana/runtime';
import { locationService, logInfo, setDataSourceSrv } from '@grafana/runtime';
import { LogMessages } from '../../Analytics';
import { MockDataSourceSrv } from '../../mocks';
import RulesFilter from './RulesFilter';
@ -13,23 +16,68 @@ jest.mock('@grafana/runtime', () => {
return {
...original,
logInfo: jest.fn(),
DataSourcePicker: () => <></>,
};
});
jest.mock('react-router-dom', () => ({
useLocation: () => ({
pathname: 'localhost:3000/example/path',
}),
}));
setDataSourceSrv(new MockDataSourceSrv({}));
jest.mock('../../utils/misc', () => ({
getFiltersFromUrlParams: jest.fn(() => ({ dataSource: {}, alertState: {}, queryString: '', ruleType: '' })),
}));
const ui = {
stateFilter: {
firing: byRole('radio', { name: 'Firing' }),
normal: byRole('radio', { name: 'Normal' }),
},
ruleType: {
alert: byRole('radio', { name: 'Alert' }),
},
health: {
ok: byRole('radio', { name: 'Ok' }),
},
searchInput: byLabelText('Search'),
};
beforeEach(() => {
locationService.replace({ search: '' });
});
describe('RulesFilter', () => {
it('Should apply state filter to the search input', async () => {
const user = userEvent.setup();
render(<RulesFilter />, { wrapper: TestProvider });
await user.click(ui.stateFilter.firing.get());
expect(ui.searchInput.get()).toHaveValue('state:firing');
});
it('Should apply multiple UI-based filters to the search input', async () => {
const user = userEvent.setup();
render(<RulesFilter />, { wrapper: TestProvider });
await user.click(ui.health.ok.get());
await user.click(ui.ruleType.alert.get());
await user.click(ui.stateFilter.normal.get());
expect(ui.searchInput.get()).toHaveValue('health:ok type:alerting state:inactive');
});
it('Should combine UI filters and typed expressions', async () => {
const user = userEvent.setup();
render(<RulesFilter />, { wrapper: TestProvider });
await user.type(ui.searchInput.get(), 'cpu{Enter}');
await user.click(ui.health.ok.get());
await user.type(ui.searchInput.get(), ' usage');
expect(ui.searchInput.get()).toHaveValue('cpu health:ok usage');
});
});
describe('Analytics', () => {
it('Sends log info when clicking alert state filters', async () => {
render(<RulesFilter />);
render(<RulesFilter />, { wrapper: TestProvider });
const button = screen.getByText('Pending');

View File

@ -1,5 +1,5 @@
import { css } from '@emotion/css';
import React, { useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { DataSourceInstanceSettings, GrafanaTheme2, SelectableValue } from '@grafana/data';
@ -69,6 +69,14 @@ const RulesFilter = ({ onFilterCleared = () => undefined }: RulesFilerProps) =>
const dataSourceKey = `dataSource-${filterKey}`;
const queryStringKey = `queryString-${filterKey}`;
const searchQueryRef = useRef<HTMLInputElement | null>(null);
const { handleSubmit, register, setValue } = useForm<{ searchQuery: string }>({ defaultValues: { searchQuery } });
const { ref, ...rest } = register('searchQuery');
useEffect(() => {
setValue('searchQuery', searchQuery);
}, [searchQuery, setValue]);
const handleDataSourceChange = (dataSourceValue: DataSourceInstanceSettings) => {
updateFilters({ ...filterState, dataSourceName: dataSourceValue.name });
setFilterKey((key) => key + 1);
@ -106,10 +114,6 @@ const RulesFilter = ({ onFilterCleared = () => undefined }: RulesFilerProps) =>
setTimeout(() => setFilterKey(filterKey + 1), 100);
};
const searchQueryRef = useRef<HTMLInputElement | null>(null);
const { handleSubmit, register } = useForm<{ searchQuery: string }>({ defaultValues: { searchQuery } });
const { ref, ...rest } = register('searchQuery');
const searchIcon = <Icon name={'search'} />;
return (
<div className={styles.container}>
@ -158,7 +162,7 @@ const RulesFilter = ({ onFilterCleared = () => undefined }: RulesFilerProps) =>
>
<Field
label={
<Label>
<Label htmlFor="rulesSearchInput">
<Stack gap={0.5}>
<span>Search</span>
<HoverCard content={<SearchQueryHelp />}>
@ -169,6 +173,7 @@ const RulesFilter = ({ onFilterCleared = () => undefined }: RulesFilerProps) =>
}
>
<Input
id="rulesSearchInput"
key={queryStringKey}
prefix={searchIcon}
ref={(e) => {