Alerting: Make receiver optional in routing preview and handle fallback case (#104639)

This commit is contained in:
Tom Ratcliffe
2025-04-30 13:51:38 +01:00
committed by GitHub
parent f413721435
commit 77a2b34b02
5 changed files with 69 additions and 24 deletions
@@ -73,14 +73,13 @@ function NotificationPreviewByAlertManager({
if (!route) {
return null;
}
if (!receiver) {
throw new Error('Receiver not found');
}
return (
<NotificationRoute
instanceMatches={instanceMatches}
route={route}
receiver={receiver}
// If we can't find a receiver, it might just be because the user doesn't have access
receiver={receiver ? receiver : undefined}
receiverNameFromRoute={route?.receiver ? route.receiver : undefined}
key={routeId}
routesByIdMap={routesByIdMap}
alertManagerSourceName={alertManagerSource.name}
@@ -18,25 +18,34 @@ import { Spacer } from '../../Spacer';
import { NotificationPolicyMatchers } from './NotificationPolicyMatchers';
import { NotificationRouteDetailsModal } from './NotificationRouteDetailsModal';
import UnknownContactPointDetails from './UnknownContactPointDetails';
import { RouteWithPath } from './route';
function NotificationRouteHeader({
route,
receiver,
routesByIdMap,
instancesCount,
alertManagerSourceName,
expandRoute,
onExpandRouteClick,
}: {
export interface ReceiverNameProps {
/** Receiver name taken from route definition. Used as a fallback when full receiver details cannot be found (in case of RBAC restrictions) */
receiverNameFromRoute?: string;
}
interface NotificationRouteHeaderProps extends ReceiverNameProps {
route: RouteWithPath;
receiver: Receiver;
receiver?: Receiver;
routesByIdMap: Map<string, RouteWithPath>;
instancesCount: number;
alertManagerSourceName: string;
expandRoute: boolean;
onExpandRouteClick: (expand: boolean) => void;
}) {
}
function NotificationRouteHeader({
route,
receiver,
receiverNameFromRoute,
routesByIdMap,
instancesCount,
alertManagerSourceName,
expandRoute,
onExpandRouteClick,
}: NotificationRouteHeaderProps) {
const styles = useStyles2(getStyles);
const [showDetails, setShowDetails] = useState(false);
@@ -76,7 +85,7 @@ function NotificationRouteHeader({
<span className={styles.textMuted}>
<Trans i18nKey="alerting.notification-route-header.delivered-to">@ Delivered to</Trans>
</span>{' '}
{receiver.name}
{receiver ? receiver.name : <UnknownContactPointDetails receiverName={receiverNameFromRoute} />}
</div>
<div className={styles.verticalBar} />
@@ -92,6 +101,7 @@ function NotificationRouteHeader({
onClose={() => setShowDetails(false)}
route={route}
receiver={receiver}
receiverNameFromRoute={receiverNameFromRoute}
routesByIdMap={routesByIdMap}
alertManagerSourceName={alertManagerSourceName}
/>
@@ -100,9 +110,9 @@ function NotificationRouteHeader({
);
}
interface NotificationRouteProps {
interface NotificationRouteProps extends ReceiverNameProps {
route: RouteWithPath;
receiver: Receiver;
receiver?: Receiver;
instanceMatches: AlertInstanceMatch[];
routesByIdMap: Map<string, RouteWithPath>;
alertManagerSourceName: string;
@@ -112,6 +122,7 @@ export function NotificationRoute({
route,
instanceMatches,
receiver,
receiverNameFromRoute,
routesByIdMap,
alertManagerSourceName,
}: NotificationRouteProps) {
@@ -126,6 +137,7 @@ export function NotificationRoute({
<NotificationRouteHeader
route={route}
receiver={receiver}
receiverNameFromRoute={receiverNameFromRoute}
routesByIdMap={routesByIdMap}
instancesCount={instanceMatches.length}
alertManagerSourceName={alertManagerSourceName}
@@ -14,6 +14,8 @@ import { createContactPointSearchLink } from '../../../utils/misc';
import { Authorize } from '../../Authorize';
import { Matchers } from '../../notification-policies/Matchers';
import { ReceiverNameProps } from './NotificationRoute';
import UnknownContactPointDetails from './UnknownContactPointDetails';
import { RouteWithPath, hasEmptyMatchers, isDefaultPolicy } from './route';
interface Props {
@@ -51,10 +53,10 @@ function PolicyPath({ route, routesByIdMap, matcherFormatter }: Props) {
);
}
interface NotificationRouteDetailsModalProps {
interface NotificationRouteDetailsModalProps extends ReceiverNameProps {
onClose: () => void;
route: RouteWithPath;
receiver: Receiver;
receiver?: Receiver;
routesByIdMap: Map<string, RouteWithPath>;
alertManagerSourceName: string;
}
@@ -63,6 +65,7 @@ export function NotificationRouteDetailsModal({
onClose,
route,
receiver,
receiverNameFromRoute,
routesByIdMap,
alertManagerSourceName,
}: NotificationRouteDetailsModalProps) {
@@ -107,13 +110,17 @@ export function NotificationRouteDetailsModal({
<Stack gap={1} direction="column">
<Trans i18nKey="alerting.notification-route-details-modal.contact-point">Contact point</Trans>
<span className={styles.textMuted}>{receiver.name}</span>
<span className={styles.textMuted}>
{receiver ? receiver.name : <UnknownContactPointDetails receiverName={receiverNameFromRoute} />}
</span>
</Stack>
<Authorize actions={[AlertmanagerAction.UpdateContactPoint]}>
<Stack gap={1} direction="row" alignItems="center">
<TextLink href={createContactPointSearchLink(receiver.name, alertManagerSourceName)} external>
<Trans i18nKey="alerting.notification-route-details-modal.see-details-link">See details</Trans>
</TextLink>
{receiver ? (
<TextLink href={createContactPointSearchLink(receiver.name, alertManagerSourceName)} external>
<Trans i18nKey="alerting.notification-route-details-modal.see-details-link">See details</Trans>
</TextLink>
) : null}
</Stack>
</Authorize>
</div>
@@ -0,0 +1,23 @@
import { Tooltip } from '@grafana/ui';
import { Trans, t } from 'app/core/internationalization';
const UnknownContactPointDetails = ({ receiverName }: { receiverName?: string }) => (
<span style={{ cursor: 'help' }}>
<Tooltip
content={t(
'alerting.unknown-contact-point-details.unknown-contact-point-tooltip',
'Details could not be found. This may be because you do not have access to the contact point'
)}
>
<span>
{receiverName ? (
receiverName
) : (
<Trans i18nKey="alerting.unknown-contact-point-details.unknown-contact-point">Unknown contact point</Trans>
)}
</span>
</Tooltip>
</span>
);
export default UnknownContactPointDetails;
+4
View File
@@ -2353,6 +2353,10 @@
"type-selector-button": {
"add-expression": "Add expression"
},
"unknown-contact-point-details": {
"unknown-contact-point": "Unknown contact point",
"unknown-contact-point-tooltip": "Details could not be found. This may be because you do not have access to the contact point"
},
"unknown-rule-list-item": {
"title-unknown-rule-type": "Unknown rule type"
},