+
- {label} {operator} {value}
+ {matcherFormatter[formatter](matcher)}
);
diff --git a/public/app/features/alerting/unified/components/notification-policies/Modals.tsx b/public/app/features/alerting/unified/components/notification-policies/Modals.tsx
index 099642f87d3..9985b7261f3 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Modals.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Modals.tsx
@@ -11,6 +11,7 @@ import {
} from 'app/plugins/datasource/alertmanager/types';
import { FormAmRoute } from '../../types/amroutes';
+import { MatcherFormatter } from '../../utils/matchers';
import { AlertGroup } from '../alert-groups/AlertGroup';
import { useGetAmRouteReceiverWithGrafanaAppTypes } from '../receivers/grafanaAppReceivers/grafanaApp';
@@ -210,6 +211,7 @@ const useAlertGroupsModal = (): [
const [showModal, setShowModal] = useState(false);
const [alertGroups, setAlertGroups] = useState
([]);
const [matchers, setMatchers] = useState([]);
+ const [formatter, setFormatter] = useState('default');
const handleDismiss = useCallback(() => {
setShowModal(false);
@@ -217,13 +219,19 @@ const useAlertGroupsModal = (): [
setMatchers([]);
}, []);
- const handleShow = useCallback((alertGroups: AlertmanagerGroup[], matchers?: ObjectMatcher[]) => {
- setAlertGroups(alertGroups);
- if (matchers) {
- setMatchers(matchers);
- }
- setShowModal(true);
- }, []);
+ const handleShow = useCallback(
+ (alertGroups: AlertmanagerGroup[], matchers?: ObjectMatcher[], formatter?: MatcherFormatter) => {
+ setAlertGroups(alertGroups);
+ if (matchers) {
+ setMatchers(matchers);
+ }
+ if (formatter) {
+ setFormatter(formatter);
+ }
+ setShowModal(true);
+ },
+ []
+ );
const instancesByState = useMemo(() => {
const instances = alertGroups.flatMap((group) => group.alerts);
@@ -242,7 +250,7 @@ const useAlertGroupsModal = (): [
Matchers
-
+
}
>
@@ -265,7 +273,7 @@ const useAlertGroupsModal = (): [
),
- [alertGroups, handleDismiss, instancesByState, matchers, showModal]
+ [alertGroups, handleDismiss, instancesByState, matchers, formatter, showModal]
);
return [modalElement, handleShow, handleDismiss];
diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
index b6ba61d28c5..c2069f80cf7 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
@@ -32,7 +32,8 @@ import { ReceiversState } from 'app/types';
import { AlertmanagerAction, useAlertmanagerAbilities, useAlertmanagerAbility } from '../../hooks/useAbilities';
import { INTEGRATION_ICONS } from '../../types/contact-points';
-import { normalizeMatchers } from '../../utils/matchers';
+import { getAmMatcherFormatter } from '../../utils/alertmanager';
+import { MatcherFormatter, normalizeMatchers } from '../../utils/matchers';
import { createContactPointLink, createMuteTimingLink } from '../../utils/misc';
import { InheritableProperties, getInheritedProperties } from '../../utils/notification-policies';
import { Authorize } from '../Authorize';
@@ -55,7 +56,6 @@ interface PolicyComponentProps {
provisioned?: boolean;
inheritedProperties?: Partial;
routesMatchingFilters?: RouteWithID[];
- // routeAlertGroupsMap?: Map;
matchingInstancesPreview?: { groupsMap?: Map; enabled: boolean };
@@ -65,7 +65,11 @@ interface PolicyComponentProps {
onEditPolicy: (route: RouteWithID, isDefault?: boolean, isAutogenerated?: boolean) => void;
onAddPolicy: (route: RouteWithID) => void;
onDeletePolicy: (route: RouteWithID) => void;
- onShowAlertInstances: (alertGroups: AlertmanagerGroup[], matchers?: ObjectMatcher[]) => void;
+ onShowAlertInstances: (
+ alertGroups: AlertmanagerGroup[],
+ matchers?: ObjectMatcher[],
+ formatter?: MatcherFormatter
+ ) => void;
isAutoGenerated?: boolean;
}
@@ -194,7 +198,7 @@ const Policy = (props: PolicyComponentProps) => {
)
) : hasMatchers ? (
-
+
) : (
No matchers
)}
@@ -325,7 +329,11 @@ interface MetadataRowProps {
matchingAlertGroups?: AlertmanagerGroup[];
matchers?: ObjectMatcher[];
isDefaultPolicy: boolean;
- onShowAlertInstances: (alertGroups: AlertmanagerGroup[], matchers?: ObjectMatcher[]) => void;
+ onShowAlertInstances: (
+ alertGroups: AlertmanagerGroup[],
+ matchers?: ObjectMatcher[],
+ formatter?: MatcherFormatter
+ ) => void;
}
function MetadataRow({
@@ -361,7 +369,8 @@ function MetadataRow({
{
- matchingAlertGroups && onShowAlertInstances(matchingAlertGroups, matchers);
+ matchingAlertGroups &&
+ onShowAlertInstances(matchingAlertGroups, matchers, getAmMatcherFormatter(alertManagerSourceName));
}}
data-testid="matching-instances"
>
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
index a7a5ef32199..e1f56127f28 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/AlertRuleForm.tsx
@@ -1,11 +1,11 @@
import { css } from '@emotion/css';
import React, { useEffect, useMemo, useState } from 'react';
-import { FormProvider, SubmitErrorHandler, useForm, UseFormWatch } from 'react-hook-form';
+import { FormProvider, SubmitErrorHandler, UseFormWatch, useForm } from 'react-hook-form';
import { Link, useParams } from 'react-router-dom';
import { GrafanaTheme2 } from '@grafana/data';
import { config } from '@grafana/runtime';
-import { Button, ConfirmModal, CustomScrollbar, HorizontalGroup, Spinner, useStyles2, Stack } from '@grafana/ui';
+import { Button, ConfirmModal, CustomScrollbar, HorizontalGroup, Spinner, Stack, useStyles2 } from '@grafana/ui';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { useAppNotification } from 'app/core/copy/appNotification';
import { contextSrv } from 'app/core/core';
@@ -14,17 +14,18 @@ import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { useDispatch } from 'app/types';
import { RuleWithLocation } from 'app/types/unified-alerting';
-import { logInfo, LogMessages, trackNewAlerRuleFormError } from '../../../Analytics';
+import { LogMessages, logInfo, trackNewAlerRuleFormError } from '../../../Analytics';
import { useUnifiedAlertingSelector } from '../../../hooks/useUnifiedAlertingSelector';
import { deleteRuleAction, saveRuleFormAction } from '../../../state/actions';
import { RuleFormType, RuleFormValues } from '../../../types/rule-form';
import { initialAsyncRequestState } from '../../../utils/redux';
import {
+ MANUAL_ROUTING_KEY,
+ MINUTE,
formValuesFromExistingRule,
getDefaultFormValues,
getDefaultQueries,
ignoreHiddenQueries,
- MINUTE,
normalizeDefaultAnnotations,
} from '../../../utils/rule-form';
import * as ruleId from '../../../utils/rule-id';
@@ -108,6 +109,14 @@ export const AlertRuleForm = ({ existing, prefill }: Props) => {
notifyApp.error(conditionErrorMsg);
return;
}
+ // when creating a new rule, we save the manual routing setting in local storage
+ if (!existing) {
+ if (values.manualRouting) {
+ localStorage.setItem(MANUAL_ROUTING_KEY, 'true');
+ } else {
+ localStorage.setItem(MANUAL_ROUTING_KEY, 'false');
+ }
+ }
dispatch(
saveRuleFormAction({
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx
index 4ec14cd359a..94ee0b3be3f 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/AlertManagerRouting.tsx
@@ -1,8 +1,10 @@
import { css } from '@emotion/css';
import React, { useState } from 'react';
+import { useFormContext } from 'react-hook-form';
import { GrafanaTheme2 } from '@grafana/data';
import { Alert, CollapsableSection, LoadingPlaceholder, Stack, useStyles2 } from '@grafana/ui';
+import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form';
import { AlertManagerDataSource } from 'app/features/alerting/unified/utils/datasource';
import { ContactPointReceiverSummary } from '../../../contact-points/ContactPoints';
@@ -22,7 +24,12 @@ export function AlertManagerManualRouting({ alertManager }: AlertManagerManualRo
const styles = useStyles2(getStyles);
const alertManagerName = alertManager.name;
- const { isLoading, error: errorInContactPointStatus, contactPoints, refetchReceivers } = useContactPointsWithStatus();
+ const {
+ isLoading,
+ error: errorInContactPointStatus,
+ contactPoints,
+ refetchReceivers,
+ } = useContactPointsWithStatus({ includePoliciesCount: false });
const [selectedContactPointWithMetadata, setSelectedContactPointWithMetadata] = useState<
ContactPointWithMetadata | undefined
>();
@@ -31,6 +38,12 @@ export function AlertManagerManualRouting({ alertManager }: AlertManagerManualRo
setSelectedContactPointWithMetadata(contactPoint);
};
+ const { watch } = useFormContext();
+ const hasRouteSettings =
+ watch(`contactPoints.${alertManagerName}.overrideGrouping`) ||
+ watch(`contactPoints.${alertManagerName}.overrideTimings`) ||
+ watch(`contactPoints.${alertManagerName}.muteTimeIntervals`)?.length > 0;
+
const options = contactPoints.map((receiver) => {
const integrations = receiver?.grafana_managed_receiver_configs;
const description = ;
@@ -69,7 +82,7 @@ export function AlertManagerManualRouting({ alertManager }: AlertManagerManualRo
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx
index 70728a041d7..ddb93051902 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/MuteTimingFields.tsx
@@ -1,9 +1,11 @@
import React from 'react';
import { useFormContext } from 'react-hook-form';
+import { SelectableValue } from '@grafana/data';
import { Field, InputControl, MultiSelect, useStyles2 } from '@grafana/ui';
-import { useMuteTimingOptions } from 'app/features/alerting/unified/hooks/useMuteTimingOptions';
+import { alertmanagerApi } from 'app/features/alerting/unified/api/alertmanagerApi';
import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form';
+import { timeIntervalToString } from 'app/features/alerting/unified/utils/alertmanager';
import { mapMultiSelectValueToStrings } from 'app/features/alerting/unified/utils/amroutes';
import { getFormStyles } from '../../../../notification-policies/formStyles';
@@ -19,7 +21,7 @@ export function MuteTimingFields({ alertManager }: MuteTimingFieldsProps) {
formState: { errors },
} = useFormContext();
- const muteTimingOptions = useMuteTimingOptions();
+ const muteTimingOptions = useSelectableMuteTimings();
return (
);
}
+
+function useSelectableMuteTimings(): Array> {
+ const fetchGrafanaMuteTimings = alertmanagerApi.endpoints.getMuteTimingList.useQuery(undefined, {
+ refetchOnFocus: true,
+ refetchOnReconnect: true,
+ selectFromResult: (result) => ({
+ ...result,
+ mutetimings: result.data
+ ? result.data.map((value) => ({
+ value: value.name,
+ label: value.name,
+ description: value.time_intervals.map((interval) => timeIntervalToString(interval)).join(', AND '),
+ }))
+ : [],
+ }),
+ });
+ return fetchGrafanaMuteTimings.mutetimings;
+}
diff --git a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx
index 298239dc15d..900ca46a35c 100644
--- a/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/alert-rule-form/simplifiedRouting/route-settings/RouteSettings.tsx
@@ -1,8 +1,8 @@
import { css } from '@emotion/css';
-import React, { useState } from 'react';
+import React, { useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
-import { GrafanaTheme2 } from '@grafana/data';
+import { GrafanaTheme2, SelectableValue } from '@grafana/data';
import {
Field,
FieldValidationMessage,
@@ -14,8 +14,7 @@ import {
Text,
useStyles2,
} from '@grafana/ui';
-import { useAlertmanagerConfig } from 'app/features/alerting/unified/hooks/useAlertmanagerConfig';
-import { useAlertmanager } from 'app/features/alerting/unified/state/AlertmanagerContext';
+import { MultiValueRemove, MultiValueRemoveProps } from '@grafana/ui/src/components/Select/MultiValue';
import { RuleFormValues } from 'app/features/alerting/unified/types/rule-form';
import {
commonGroupByOptions,
@@ -29,6 +28,15 @@ import { TIMING_OPTIONS_DEFAULTS } from '../../../../notification-policies/timin
import { RouteTimings } from './RouteTimings';
+const REQUIRED_FIELDS_IN_GROUPBY = ['grafana_folder', 'alertname'];
+
+const DEFAULTS_TIMINGS = {
+ groupWaitValue: TIMING_OPTIONS_DEFAULTS.group_wait,
+ groupIntervalValue: TIMING_OPTIONS_DEFAULTS.group_interval,
+ repeatIntervalValue: TIMING_OPTIONS_DEFAULTS.repeat_interval,
+};
+const DISABLE_GROUPING = '...';
+
export interface RoutingSettingsProps {
alertManager: string;
}
@@ -42,12 +50,18 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
formState: { errors },
} = useFormContext();
const [groupByOptions, setGroupByOptions] = useState(stringsToSelectableValues([]));
- const { groupBy, groupIntervalValue, groupWaitValue, repeatIntervalValue } = useGetDefaultsForRoutingSettings();
+ const { groupIntervalValue, groupWaitValue, repeatIntervalValue } = DEFAULTS_TIMINGS;
const overrideGrouping = watch(`contactPoints.${alertManager}.overrideGrouping`);
const overrideTimings = watch(`contactPoints.${alertManager}.overrideTimings`);
- const requiredFieldsInGroupBy = ['grafana_folder', 'alertname'];
- const disableGrouping = '...';
+ const groupByCount = watch(`contactPoints.${alertManager}.groupBy`)?.length ?? 0;
+
const styles = useStyles2(getStyles);
+ useEffect(() => {
+ if (overrideGrouping && groupByCount === 0) {
+ setValue(`contactPoints.${alertManager}.groupBy`, REQUIRED_FIELDS_IN_GROUPBY);
+ }
+ }, [overrideGrouping, setValue, alertManager, groupByCount]);
+
return (
@@ -56,7 +70,7 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
{!overrideGrouping && (
- Grouping: {groupBy.join(', ')}
+ Grouping: {REQUIRED_FIELDS_IN_GROUPBY.join(', ')}
)}
@@ -74,14 +88,13 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
if (!value || value.length === 0) {
return 'At least one group by option is required.';
}
- // if value includes only the allowedSingleFieldInGroupBy, it is valid
- if (value.length === 1 && value[0] === disableGrouping) {
+ if (value.length === 1 && value[0] === DISABLE_GROUPING) {
return true;
}
// we need to make sure that the required fields are included
- const requiredFieldsIncluded = requiredFieldsInGroupBy.every((field) => value.includes(field));
+ const requiredFieldsIncluded = REQUIRED_FIELDS_IN_GROUPBY.every((field) => value.includes(field));
if (!requiredFieldsIncluded) {
- return `Group by must include ${requiredFieldsInGroupBy.join(', ')}`;
+ return `Group by must include ${REQUIRED_FIELDS_IN_GROUPBY.join(', ')}`;
}
return true;
},
@@ -99,8 +112,30 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
// @ts-ignore-check: react-hook-form made me do this
setValue(`contactPoints.${alertManager}.groupBy`, [...field.value, opt]);
}}
- onChange={(value) => onChange(mapMultiSelectValueToStrings(value))}
+ onChange={(value) => {
+ return onChange(mapMultiSelectValueToStrings(value));
+ }}
options={[...commonGroupByOptions, ...groupByOptions]}
+ components={{
+ MultiValueRemove(
+ props: React.PropsWithChildren<
+ MultiValueRemoveProps &
+ Array> & {
+ data: {
+ label: string;
+ value: string;
+ isFixed: boolean;
+ };
+ }
+ >
+ ) {
+ const { data } = props;
+ if (data.isFixed) {
+ return null;
+ }
+ return MultiValueRemove(props);
+ },
+ }}
/>
{error && {error.message}}
>
@@ -131,20 +166,6 @@ export const RoutingSettings = ({ alertManager }: RoutingSettingsProps) => {
);
};
-function useGetDefaultsForRoutingSettings() {
- const { selectedAlertmanager } = useAlertmanager();
- const { currentData } = useAlertmanagerConfig(selectedAlertmanager);
- const config = currentData?.alertmanager_config;
- return React.useMemo(() => {
- return {
- groupWaitValue: TIMING_OPTIONS_DEFAULTS.group_wait,
- groupIntervalValue: TIMING_OPTIONS_DEFAULTS.group_interval,
- repeatIntervalValue: TIMING_OPTIONS_DEFAULTS.repeat_interval,
- groupBy: config?.route?.group_by ?? [],
- };
- }, [config]);
-}
-
const getStyles = (theme: GrafanaTheme2) => ({
switchElement: css({
flexFlow: 'row-reverse',
@@ -153,5 +174,6 @@ const getStyles = (theme: GrafanaTheme2) => ({
}),
optionalContent: css({
marginLeft: '49px',
+ marginBottom: theme.spacing(1),
}),
});
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx
index ad459deedb0..cb7c4492d1c 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationPolicyMatchers.tsx
@@ -4,18 +4,24 @@ import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
+import { MatcherFormatter } from '../../../utils/matchers';
import { Matchers } from '../../notification-policies/Matchers';
import { hasEmptyMatchers, isDefaultPolicy, RouteWithPath } from './route';
-export function NotificationPolicyMatchers({ route }: { route: RouteWithPath }) {
+interface Props {
+ route: RouteWithPath;
+ matcherFormatter: MatcherFormatter;
+}
+
+export function NotificationPolicyMatchers({ route, matcherFormatter }: Props) {
const styles = useStyles2(getStyles);
if (isDefaultPolicy(route)) {
return Default policy
;
} else if (hasEmptyMatchers(route)) {
return No matchers
;
} else {
- return ;
+ return ;
}
}
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx
index 1a7f9a13944..a95e1bbb8a6 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRoute.tsx
@@ -9,6 +9,7 @@ import { Button, getTagColorIndexFromName, TagList, useStyles2 } from '@grafana/
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types';
import { Stack } from '../../../../../../plugins/datasource/parca/QueryEditor/Stack';
+import { getAmMatcherFormatter } from '../../../utils/alertmanager';
import { AlertInstanceMatch } from '../../../utils/notification-policies';
import { CollapseToggle } from '../../CollapseToggle';
import { MetaText } from '../../MetaText';
@@ -58,7 +59,10 @@ function NotificationRouteHeader({
onExpandRouteClick(!expandRoute)} className={styles.expandable}>
Notification policy
-
+
diff --git a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx
index f66e525f8a1..8de20bc227d 100644
--- a/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx
+++ b/public/app/features/alerting/unified/components/rule-editor/notificaton-preview/NotificationRouteDetailsModal.tsx
@@ -3,20 +3,26 @@ import { compact } from 'lodash';
import React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
-import { Button, Icon, Modal, useStyles2 } from '@grafana/ui';
+import { Button, Icon, Modal, Stack, useStyles2 } from '@grafana/ui';
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types';
-import { Stack } from '../../../../../../plugins/datasource/parca/QueryEditor/Stack';
import { AlertmanagerAction } from '../../../hooks/useAbilities';
import { AlertmanagerProvider } from '../../../state/AlertmanagerContext';
-import { GRAFANA_DATASOURCE_NAME } from '../../../utils/datasource';
+import { getAmMatcherFormatter } from '../../../utils/alertmanager';
+import { MatcherFormatter } from '../../../utils/matchers';
import { makeAMLink } from '../../../utils/misc';
import { Authorize } from '../../Authorize';
import { Matchers } from '../../notification-policies/Matchers';
import { hasEmptyMatchers, isDefaultPolicy, RouteWithPath } from './route';
-function PolicyPath({ route, routesByIdMap }: { routesByIdMap: Map; route: RouteWithPath }) {
+interface Props {
+ routesByIdMap: Map;
+ route: RouteWithPath;
+ matcherFormatter: MatcherFormatter;
+}
+
+function PolicyPath({ route, routesByIdMap, matcherFormatter }: Props) {
const styles = useStyles2(getStyles);
const routePathIds = route.path?.slice(1) ?? [];
const routePathObjects = [...compact(routePathIds.map((id) => routesByIdMap.get(id))), route];
@@ -31,7 +37,7 @@ function PolicyPath({ route, routesByIdMap }: { routesByIdMap: MapNo matchers
) : (
-
+
)}
@@ -60,7 +66,7 @@ export function NotificationRouteDetailsModal({
const isDefault = isDefaultPolicy(route);
return (
-