diff --git a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx
index 5138f5a8bfa..cc019e7c86c 100644
--- a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.test.tsx
@@ -1,6 +1,5 @@
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import lodash from 'lodash'; // eslint-disable-line lodash/import-scope
import React from 'react';
import * as analytics from '../../Analytics';
@@ -10,18 +9,11 @@ import { MatcherFilter } from './MatcherFilter';
const logInfoSpy = jest.spyOn(analytics, 'logInfo');
describe('Analytics', () => {
- beforeEach(() => {
- lodash.debounce = jest.fn().mockImplementation((fn) => {
- fn.cancel = () => {};
- return fn;
- });
- });
-
it('Sends log info when filtering alert instances by label', async () => {
render();
const searchInput = screen.getByTestId('search-query-input');
- await userEvent.type(searchInput, 'job=');
+ await userEvent.type(searchInput, 'job=', { delay: 600 }); // Delay waits for the MatcherFilter debounce
expect(logInfoSpy).toHaveBeenCalledWith(analytics.LogMessages.filterByLabel);
});
@@ -32,7 +24,7 @@ describe('Analytics', () => {
render();
const searchInput = screen.getByTestId('search-query-input');
- await userEvent.type(searchInput, '=bar');
+ await userEvent.type(searchInput, '=bar', { delay: 600 }); // Delay waits for the MatcherFilter debounce
expect(onFilterMock).toHaveBeenLastCalledWith('foo=bar');
});
diff --git a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx
index 4f8a2745173..dc87bb2fd58 100644
--- a/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx
+++ b/public/app/features/alerting/unified/components/alert-groups/MatcherFilter.tsx
@@ -1,6 +1,6 @@
import { css } from '@emotion/css';
-import { debounce } from 'lodash';
-import React, { FormEvent, useEffect, useMemo } from 'react';
+import React from 'react';
+import { useDebounce } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { Field, Icon, Input, Label, Stack, Tooltip, useStyles2 } from '@grafana/ui';
@@ -16,17 +16,16 @@ interface Props {
export const MatcherFilter = ({ onFilterChange, defaultQueryString }: Props) => {
const styles = useStyles2(getStyles);
- const onSearchInputChanged = useMemo(
- () =>
- debounce((e: FormEvent) => {
- logInfo(LogMessages.filterByLabel);
- const target = e.currentTarget;
- onFilterChange(target.value);
- }, 600),
- [onFilterChange]
- );
+ const [filterQuery, setFilterQuery] = React.useState(defaultQueryString ?? '');
- useEffect(() => onSearchInputChanged.cancel(), [onSearchInputChanged]);
+ useDebounce(
+ () => {
+ logInfo(LogMessages.filterByLabel);
+ onFilterChange(filterQuery);
+ },
+ 600,
+ [filterQuery]
+ );
const searchIcon = ;
const inputInvalid = defaultQueryString ? parseMatchers(defaultQueryString).length === 0 : false;
@@ -63,8 +62,8 @@ export const MatcherFilter = ({ onFilterChange, defaultQueryString }: Props) =>
>
setFilterQuery(e.currentTarget.value)}
data-testid="search-query-input"
prefix={searchIcon}
className={styles.inputWidth}