Alerting: fix filtering in notification policies (#57824)
This commit is contained in:
+18
-2
@@ -12,9 +12,14 @@ import { MatcherFilter } from './MatcherFilter';
|
|||||||
jest.mock('@grafana/runtime');
|
jest.mock('@grafana/runtime');
|
||||||
|
|
||||||
describe('Analytics', () => {
|
describe('Analytics', () => {
|
||||||
it('Sends log info when filtering alert instances by label', async () => {
|
beforeEach(() => {
|
||||||
lodash.debounce = jest.fn().mockImplementation((fn) => fn);
|
lodash.debounce = jest.fn().mockImplementation((fn) => {
|
||||||
|
fn.cancel = () => {};
|
||||||
|
return fn;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Sends log info when filtering alert instances by label', async () => {
|
||||||
render(<MatcherFilter onFilterChange={jest.fn()} />);
|
render(<MatcherFilter onFilterChange={jest.fn()} />);
|
||||||
|
|
||||||
const searchInput = screen.getByTestId('search-query-input');
|
const searchInput = screen.getByTestId('search-query-input');
|
||||||
@@ -22,4 +27,15 @@ describe('Analytics', () => {
|
|||||||
|
|
||||||
expect(logInfo).toHaveBeenCalledWith(LogMessages.filterByLabel);
|
expect(logInfo).toHaveBeenCalledWith(LogMessages.filterByLabel);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should call onChange handler', async () => {
|
||||||
|
const onFilterMock = jest.fn();
|
||||||
|
|
||||||
|
render(<MatcherFilter defaultQueryString="foo" onFilterChange={onFilterMock} />);
|
||||||
|
|
||||||
|
const searchInput = screen.getByTestId('search-query-input');
|
||||||
|
await userEvent.type(searchInput, '=bar');
|
||||||
|
|
||||||
|
expect(onFilterMock).toHaveBeenLastCalledWith('foo=bar');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import React, { FormEvent } from 'react';
|
import React, { FormEvent, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/experimental';
|
||||||
@@ -11,20 +11,28 @@ import { LogMessages } from '../../Analytics';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string;
|
className?: string;
|
||||||
queryString?: string;
|
|
||||||
defaultQueryString?: string;
|
defaultQueryString?: string;
|
||||||
onFilterChange: (filterString: string) => void;
|
onFilterChange: (filterString: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MatcherFilter = ({ className, onFilterChange, defaultQueryString, queryString }: Props) => {
|
export const MatcherFilter = ({ className, onFilterChange, defaultQueryString }: Props) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const handleSearchChange = debounce((e: FormEvent<HTMLInputElement>) => {
|
|
||||||
logInfo(LogMessages.filterByLabel);
|
|
||||||
|
|
||||||
const target = e.target as HTMLInputElement;
|
const onSearchInputChanged = useMemo(
|
||||||
onFilterChange(target.value);
|
() =>
|
||||||
}, 600);
|
debounce((e: FormEvent<HTMLInputElement>) => {
|
||||||
|
logInfo(LogMessages.filterByLabel);
|
||||||
|
|
||||||
|
const target = e.target as HTMLInputElement;
|
||||||
|
onFilterChange(target.value);
|
||||||
|
}, 600),
|
||||||
|
[onFilterChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => onSearchInputChanged.cancel(), [onSearchInputChanged]);
|
||||||
|
|
||||||
const searchIcon = <Icon name={'search'} />;
|
const searchIcon = <Icon name={'search'} />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Label>
|
<Label>
|
||||||
@@ -45,8 +53,7 @@ export const MatcherFilter = ({ className, onFilterChange, defaultQueryString, q
|
|||||||
<Input
|
<Input
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
defaultValue={defaultQueryString}
|
defaultValue={defaultQueryString}
|
||||||
value={queryString}
|
onChange={onSearchInputChanged}
|
||||||
onChange={handleSearchChange}
|
|
||||||
data-testid="search-query-input"
|
data-testid="search-query-input"
|
||||||
prefix={searchIcon}
|
prefix={searchIcon}
|
||||||
className={styles.inputWidth}
|
className={styles.inputWidth}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ export const AmSpecificRouting: FC<AmSpecificRoutingProps> = ({
|
|||||||
onFilterChange={(filter) =>
|
onFilterChange={(filter) =>
|
||||||
setFilters((currentFilters) => ({ ...currentFilters, queryString: filter }))
|
setFilters((currentFilters) => ({ ...currentFilters, queryString: filter }))
|
||||||
}
|
}
|
||||||
queryString={filters.queryString ?? ''}
|
defaultQueryString={filters.queryString ?? ''}
|
||||||
className={styles.filterInput}
|
className={styles.filterInput}
|
||||||
/>
|
/>
|
||||||
<div className={styles.filterInput}>
|
<div className={styles.filterInput}>
|
||||||
|
|||||||
Reference in New Issue
Block a user