diff --git a/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx b/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
index c73d19f7952..f8888a043f6 100644
--- a/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/ContactPoints.tsx
@@ -32,6 +32,7 @@ import { ContactPoint } from './ContactPoint';
import { NotificationTemplates } from './NotificationTemplates';
import { ContactPointsFilter } from './components/ContactPointsFilter';
import { GlobalConfigAlert } from './components/GlobalConfigAlert';
+import { ContactPointsFilterState, useContactPointsFilter } from './components/useContactPointsFilter';
import { useContactPointsWithStatus } from './useContactPoints';
import { useContactPointsSearch } from './useContactPointsSearch';
import { ALL_CONTACT_POINTS, useExportContactPoint } from './useExportContactPoint';
@@ -46,7 +47,8 @@ const DEFAULT_PAGE_SIZE = 10;
const ContactPointsTab = () => {
const { selectedAlertmanager } = useAlertmanager();
- const [queryParams] = useURLSearchParams();
+ const { filters } = useContactPointsFilter();
+ console.log(filters);
// If we're using the K8S API, then we don't need to fetch the policies info within the hook,
// as we get metadata about this from the API
@@ -69,8 +71,6 @@ const ContactPointsTab = () => {
const [ExportDrawer, showExportDrawer] = useExportContactPoint();
- const search = queryParams.get('search');
-
if (isLoading) {
return ;
}
@@ -129,7 +129,7 @@ const ContactPointsTab = () => {
{error && {stringifyErrorLike(error)}}
- {!error && }
+ {!error && }
{/* Grafana manager Alertmanager does not support global config, Mimir and Cortex do */}
{!isGrafanaManagedAlertmanager && }
{ExportDrawer}
@@ -235,12 +235,12 @@ export const ContactPointsPageContents = () => {
interface ContactPointsListProps {
contactPoints: ContactPointWithMetadata[];
- search?: string | null;
+ filters?: ContactPointsFilterState;
pageSize?: number;
}
-const ContactPointsList = ({ contactPoints, search, pageSize = DEFAULT_PAGE_SIZE }: ContactPointsListProps) => {
- const searchResults = useContactPointsSearch(contactPoints, search);
+const ContactPointsList = ({ contactPoints, filters, pageSize = DEFAULT_PAGE_SIZE }: ContactPointsListProps) => {
+ const searchResults = useContactPointsSearch(contactPoints, filters);
const { page, pageItems, numberOfPages, onPageChange } = usePagination(searchResults, 1, pageSize);
if (pageItems.length === 0) {
diff --git a/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx b/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx
index 61f0e07d402..7e3154efab0 100644
--- a/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/components/ContactPointsFilter.tsx
@@ -1,54 +1,36 @@
import { css } from '@emotion/css';
-import { useCallback, useDeferredValue, useEffect, useMemo, useState } from 'react';
+import { useMemo } from 'react';
import { SelectableValue } from '@grafana/data';
-import { Stack } from '@grafana/experimental';
-import { Button, Field, Icon, Input, Select, SelectCommonProps, Text, useStyles2 } from '@grafana/ui';
+import { Button, Field, Icon, Input, Select, SelectCommonProps, Stack, Text, useStyles2 } from '@grafana/ui';
import { alertmanagerApi } from '../../../api/alertmanagerApi';
-import { useURLSearchParams } from '../../../hooks/useURLSearchParams';
import { useAlertmanager } from '../../../state/AlertmanagerContext';
import { stringifyErrorLike } from '../../../utils/misc';
+import { useContactPointsFilter } from './useContactPointsFilter';
+
const useGrafanaNotifiers = alertmanagerApi.endpoints.grafanaNotifiers.useQuery;
const ContactPointsFilter = () => {
const styles = useStyles2(getStyles);
const { isGrafanaAlertmanager } = useAlertmanager();
-
- const [searchParams, setSearchParams] = useURLSearchParams();
- const [filters, setFilters] = useState({
- search: searchParams.get('search') ?? undefined,
- type: searchParams.get('type') ?? undefined,
- });
- const filtersDeferred = useDeferredValue(filters);
-
- const clear = useCallback(() => {
- setFilters({ search: '', type: '' });
- }, []);
-
- // when the filters are updated (deferred) update the search params
- useEffect(() => {
- setSearchParams(filtersDeferred, true);
- }, [filtersDeferred, setSearchParams]);
+ const { filters, updateFilter, clear } = useContactPointsFilter();
const hasFilters = Object.values(filters).some(Boolean);
return (
-
+
}
onChange={(event) => {
- setFilters({
- ...filters,
- search: event.currentTarget.value,
- });
+ updateFilter({ search: event.currentTarget.value });
}}
- value={filtersDeferred.search}
+ value={filters.search}
/>
{/* I don't feel like doing this for non-Grafana Alertmanagers right now */}
@@ -56,12 +38,9 @@ const ContactPointsFilter = () => {
{
- setFilters({
- ...filters,
- type: type.value,
- });
+ updateFilter({ type: type.value });
}}
/>
diff --git a/public/app/features/alerting/unified/components/contact-points/components/useContactPointsFilter.tsx b/public/app/features/alerting/unified/components/contact-points/components/useContactPointsFilter.tsx
new file mode 100644
index 00000000000..e5f18d54e45
--- /dev/null
+++ b/public/app/features/alerting/unified/components/contact-points/components/useContactPointsFilter.tsx
@@ -0,0 +1,44 @@
+import { useCallback, useDeferredValue, useEffect, useState } from 'react';
+
+import { useURLSearchParams } from '../../../hooks/useURLSearchParams';
+
+export type ContactPointsFilterState = {
+ search?: string;
+ type?: string;
+};
+
+export function useContactPointsFilter() {
+ const [searchParams, setSearchParams] = useURLSearchParams();
+ const [filters, setFilters] = useState({
+ search: searchParams.get('search') ?? undefined,
+ type: searchParams.get('type') ?? undefined,
+ });
+ const filtersDeferred = useDeferredValue(filters);
+
+ const clear = useCallback(() => {
+ setFilters({ search: '', type: '' });
+ }, []);
+
+ const updateFilter = useCallback((update: Partial) => {
+ setFilters((filters) => ({ ...filters, ...update }));
+ }, []);
+
+ // // when the filters are updated (deferred) update the search params
+ useEffect(() => {
+ setSearchParams(filtersDeferred, true);
+ }, [filtersDeferred, setSearchParams]);
+
+ // When URL params change, update filters
+ useEffect(() => {
+ setFilters({
+ search: searchParams.get('search') ?? undefined,
+ type: searchParams.get('type') ?? undefined,
+ });
+ }, [searchParams]);
+
+ return {
+ clear,
+ filters: filtersDeferred,
+ updateFilter,
+ };
+}
diff --git a/public/app/features/alerting/unified/components/contact-points/useContactPointsSearch.tsx b/public/app/features/alerting/unified/components/contact-points/useContactPointsSearch.tsx
index 7c09430fc4a..6cb207e0858 100644
--- a/public/app/features/alerting/unified/components/contact-points/useContactPointsSearch.tsx
+++ b/public/app/features/alerting/unified/components/contact-points/useContactPointsSearch.tsx
@@ -5,6 +5,8 @@ import { useMemo } from 'react';
import { RECEIVER_META_KEY } from 'app/features/alerting/unified/components/contact-points/constants';
import { ContactPointWithMetadata } from 'app/features/alerting/unified/components/contact-points/utils';
+import { ContactPointsFilterState } from './components/useContactPointsFilter';
+
const fuzzyFinder = new uFuzzy({
intraMode: 1,
intraIns: 1,
@@ -16,8 +18,11 @@ const fuzzyFinder = new uFuzzy({
// let's search in two different haystacks, the name of the contact point and the type of the receiver(s)
export const useContactPointsSearch = (
contactPoints: ContactPointWithMetadata[],
- search?: string | null
+ filters: ContactPointsFilterState = {}
): ContactPointWithMetadata[] => {
+ const hasFilters = Object.values(filters).some(Boolean);
+ const { search, type } = filters;
+
const nameHaystack = useMemo(() => {
return contactPoints.map((contactPoint) => contactPoint.name);
}, [contactPoints]);
@@ -29,14 +34,23 @@ export const useContactPointsSearch = (
);
}, [contactPoints]);
- if (!search) {
+ if (!hasFilters) {
return contactPoints;
}
- const nameHits = fuzzyFinder.filter(nameHaystack, search) ?? [];
- const typeHits = fuzzyFinder.filter(typeHaystack, search) ?? [];
+ const results: ContactPointWithMetadata[] = [];
- const hits = [...nameHits, ...typeHits];
+ if (search) {
+ fuzzyFinder.filter(nameHaystack, search)?.forEach((id) => {
+ results.push(contactPoints[id]);
+ });
+ }
+
+ if (type) {
+ fuzzyFinder.filter(typeHaystack, type)?.forEach((id) => {
+ results.push(contactPoints[id]);
+ });
+ }
- return uniq(hits).map((id) => contactPoints[id]) ?? [];
+ return uniq(results);
};