Alerting: Add contact point filter to Active Notifications page (#109775)
This commit is contained in:
@@ -12,6 +12,7 @@ import { getFiltersFromUrlParams } from '../../utils/misc';
|
||||
import { AlertStateFilter } from './AlertStateFilter';
|
||||
import { GroupBy } from './GroupBy';
|
||||
import { MatcherFilter } from './MatcherFilter';
|
||||
import { ReceiverFilter } from './ReceiverFilter';
|
||||
|
||||
interface Props {
|
||||
groups: AlertmanagerGroup[];
|
||||
@@ -20,7 +21,7 @@ interface Props {
|
||||
export const AlertGroupFilter = ({ groups }: Props) => {
|
||||
const [filterKey, setFilterKey] = useState<number>(Math.floor(Math.random() * 100));
|
||||
const [queryParams, setQueryParams] = useQueryParams();
|
||||
const { groupBy = [], queryString, alertState } = getFiltersFromUrlParams(queryParams);
|
||||
const { groupBy = [], queryString, alertState, receivers = [] } = getFiltersFromUrlParams(queryParams);
|
||||
const matcherFilterKey = `matcher-${filterKey}`;
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
@@ -31,11 +32,12 @@ export const AlertGroupFilter = ({ groups }: Props) => {
|
||||
queryString: null,
|
||||
alertState: null,
|
||||
contactPoint: null,
|
||||
receivers: null,
|
||||
});
|
||||
setTimeout(() => setFilterKey(filterKey + 1), 100);
|
||||
};
|
||||
|
||||
const showClearButton = !!(groupBy.length > 0 || queryString || alertState);
|
||||
const showClearButton = !!(groupBy.length > 0 || queryString || alertState || receivers.length > 0);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
@@ -50,6 +52,13 @@ export const AlertGroupFilter = ({ groups }: Props) => {
|
||||
groupBy={groupBy}
|
||||
onGroupingChange={(keys) => setQueryParams({ groupBy: keys.length ? keys.join(',') : null })}
|
||||
/>
|
||||
<ReceiverFilter
|
||||
groups={groups}
|
||||
receivers={receivers}
|
||||
onReceiversChange={(receivers) =>
|
||||
setQueryParams({ receivers: receivers.length ? receivers.join(',') : null })
|
||||
}
|
||||
/>
|
||||
<AlertStateFilter
|
||||
stateFilter={alertState as AlertState}
|
||||
onStateFilterChange={(value) => setQueryParams({ alertState: value ? value : null })}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import { uniq } from 'lodash';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { Trans, t } from '@grafana/i18n';
|
||||
import { Icon, Label, MultiSelect, Tooltip } from '@grafana/ui';
|
||||
import { AlertmanagerGroup } from 'app/plugins/datasource/alertmanager/types';
|
||||
|
||||
const collator = new Intl.Collator('en', { sensitivity: 'accent' });
|
||||
|
||||
interface Props {
|
||||
groups: AlertmanagerGroup[];
|
||||
receivers: string[];
|
||||
onReceiversChange: (receivers: string[]) => void;
|
||||
}
|
||||
|
||||
export const ReceiverFilter = ({ groups, receivers, onReceiversChange }: Props) => {
|
||||
const receiverOptions = uniq(groups.map((group) => group.receiver.name))
|
||||
.map<SelectableValue<string>>((receiverName) => ({
|
||||
label: receiverName === 'NONE' ? t('alerting.receiver-filter.no-grouping', 'No grouping') : receiverName,
|
||||
value: receiverName,
|
||||
}))
|
||||
.sort((a, b) => collator.compare(a.label || '', b.label || ''));
|
||||
|
||||
return (
|
||||
<div data-testid={'receiver-filter-container'}>
|
||||
<Label>
|
||||
<span>
|
||||
<Trans i18nKey="alerting.receiver-filter.contact-point">Contact point</Trans>
|
||||
</span>
|
||||
<Tooltip
|
||||
content={
|
||||
<Trans i18nKey="alerting.receiver-filter.tooltip-contact-point">
|
||||
Filter notifications by the contact point they are being delivered to.
|
||||
</Trans>
|
||||
}
|
||||
>
|
||||
<Icon name="info-circle" size="sm" />
|
||||
</Tooltip>
|
||||
</Label>
|
||||
<MultiSelect<string>
|
||||
aria-label={t('alerting.receiver-filter.aria-label-contact-points', 'Filter by contact points')}
|
||||
value={receivers}
|
||||
placeholder={t('alerting.receiver-filter.placeholder-contact-point', 'Filter by contact point')}
|
||||
prefix={<Icon name="at" />}
|
||||
onChange={(items) => {
|
||||
onReceiversChange(items.map(({ value }) => value).filter((v): v is string => v !== undefined));
|
||||
}}
|
||||
options={receiverOptions}
|
||||
width={34}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -9,12 +9,19 @@ import { getFiltersFromUrlParams } from '../utils/misc';
|
||||
|
||||
export const useFilteredAmGroups = (groups: AlertmanagerGroup[]) => {
|
||||
const [queryParams] = useQueryParams();
|
||||
const { queryString, alertState } = getFiltersFromUrlParams(queryParams);
|
||||
const { queryString, alertState, receivers } = getFiltersFromUrlParams(queryParams);
|
||||
|
||||
return useMemo(() => {
|
||||
const matchers = queryString ? parsePromQLStyleMatcherLooseSafe(queryString) : [];
|
||||
|
||||
return groups.reduce((filteredGroup: AlertmanagerGroup[], group) => {
|
||||
// Filter by receiver if specified
|
||||
const receiverMatches = receivers && receivers.length > 0 ? receivers.includes(group.receiver.name) : true;
|
||||
|
||||
if (!receiverMatches) {
|
||||
return filteredGroup;
|
||||
}
|
||||
|
||||
const alerts = group.alerts.filter(({ labels, status }) => {
|
||||
const labelsMatch = labelsMatchMatchers(labels, matchers);
|
||||
const filtersMatch = alertState ? status.state === alertState : true;
|
||||
@@ -30,5 +37,5 @@ export const useFilteredAmGroups = (groups: AlertmanagerGroup[]) => {
|
||||
}
|
||||
return filteredGroup;
|
||||
}, []);
|
||||
}, [queryString, groups, alertState]);
|
||||
}, [queryString, groups, alertState, receivers]);
|
||||
};
|
||||
|
||||
@@ -134,7 +134,8 @@ export const getFiltersFromUrlParams = (queryParams: UrlQueryMap): FilterState =
|
||||
const dataSource = queryParams.dataSource === undefined ? undefined : String(queryParams.dataSource);
|
||||
const ruleType = queryParams.ruleType === undefined ? undefined : String(queryParams.ruleType);
|
||||
const groupBy = queryParams.groupBy === undefined ? undefined : String(queryParams.groupBy).split(',');
|
||||
return { queryString, alertState, dataSource, groupBy, ruleType };
|
||||
const receivers = queryParams.receivers === undefined ? undefined : String(queryParams.receivers).split(',');
|
||||
return { queryString, alertState, dataSource, groupBy, ruleType, receivers };
|
||||
};
|
||||
|
||||
export const getNotificationPoliciesFilters = (searchParams: URLSearchParams) => {
|
||||
|
||||
@@ -272,6 +272,7 @@ export interface FilterState {
|
||||
alertState?: string;
|
||||
groupBy?: string[];
|
||||
ruleType?: string;
|
||||
receivers?: string[];
|
||||
}
|
||||
|
||||
export interface SilenceFilterState {
|
||||
|
||||
@@ -2221,6 +2221,13 @@
|
||||
"preview": "Preview",
|
||||
"previewCondition": "Preview alert rule condition"
|
||||
},
|
||||
"receiver-filter": {
|
||||
"aria-label-contact-points": "Filter by contact points",
|
||||
"contact-point": "Contact point",
|
||||
"no-grouping": "No grouping",
|
||||
"placeholder-contact-point": "Filter by contact point",
|
||||
"tooltip-contact-point": "Filter notifications by the contact point they are being delivered to."
|
||||
},
|
||||
"receiver-form": {
|
||||
"add-contact-point-integration": "Add contact point integration",
|
||||
"body-attention": "Because there is no default policy configured yet, this contact point will automatically be set as default.",
|
||||
|
||||
Reference in New Issue
Block a user