mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Fix UI toggles and search input synchronization (#64751)
* Fix UI toggles and search input synchronization * Fix lint
This commit is contained in:
parent
4583fe58f3
commit
51974c54d7
@ -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');
|
||||
|
||||
|
@ -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) => {
|
||||
|
Loading…
Reference in New Issue
Block a user