Alerting: Refactor placeholder email detection into shared utility
- Extract duplicate placeholder email detection logic into reusable functions - Add hasPlaceholderEmail() for single channel checks - Add receiverHasPlaceholderEmail() for receiver list checks - Centralize PLACEHOLDER_EMAILS constant in receiver-form.ts - Update ChannelSubForm, TestContactPointModal, and actions to use utilities - Reduces code duplication by 44 lines
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
GrafanaChannelValues,
|
||||
ReceiverFormValues,
|
||||
} from '../../../types/receiver-form';
|
||||
import { hasPlaceholderEmail } from '../../../utils/receiver-form';
|
||||
import { OnCallIntegrationType } from '../grafanaAppReceivers/onCall/useOnCallIntegration';
|
||||
|
||||
import { ChannelOptions } from './ChannelOptions';
|
||||
@@ -71,15 +72,8 @@ export function ChannelSubForm<R extends ChannelValues>({
|
||||
const isTestAvailable = onCallIntegrationType !== OnCallIntegrationType.NewIntegration;
|
||||
|
||||
// Check if email integration has placeholder addresses
|
||||
const emailAddresses = watch(`${settingsFieldPath}.addresses`);
|
||||
const hasPlaceholderEmail = useMemo(() => {
|
||||
if (selectedType !== 'email' || !emailAddresses) {
|
||||
return false;
|
||||
}
|
||||
const placeholders = ['<example@email.com>', 'example@email.com'];
|
||||
const addresses = typeof emailAddresses === 'string' ? [emailAddresses] : emailAddresses;
|
||||
return addresses.some((addr: string) => placeholders.includes(addr?.trim()));
|
||||
}, [selectedType, emailAddresses]);
|
||||
const channelValues = getValues(channelFieldPath) as GrafanaChannelValues | undefined;
|
||||
const isPlaceholderEmail = hasPlaceholderEmail(channelValues);
|
||||
|
||||
useEffect(() => {
|
||||
register(`${channelFieldPath}.__id`);
|
||||
@@ -242,14 +236,14 @@ export function ChannelSubForm<R extends ChannelValues>({
|
||||
<div className={styles.buttons}>
|
||||
{isTestable && onTest && isTestAvailable && (
|
||||
<Button
|
||||
disabled={hasPlaceholderEmail}
|
||||
disabled={isPlaceholderEmail}
|
||||
size="xs"
|
||||
variant="secondary"
|
||||
type="button"
|
||||
onClick={() => handleTest()}
|
||||
icon="message"
|
||||
tooltip={
|
||||
hasPlaceholderEmail
|
||||
isPlaceholderEmail
|
||||
? t(
|
||||
'alerting.channel-sub-form.test-disabled-placeholder',
|
||||
'Please configure a valid email address before testing'
|
||||
@@ -283,7 +277,7 @@ export function ChannelSubForm<R extends ChannelValues>({
|
||||
</div>
|
||||
{notifier && (
|
||||
<div className={styles.innerContent}>
|
||||
{hasPlaceholderEmail && (
|
||||
{isPlaceholderEmail && (
|
||||
<Alert
|
||||
title={t(
|
||||
'alerting.contact-points.email.placeholder-warning-title',
|
||||
|
||||
+6
-16
@@ -1,5 +1,5 @@
|
||||
import { css } from '@emotion/css';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
import { FormProvider, useForm } from 'react-hook-form';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
@@ -12,6 +12,7 @@ import { useTestIntegrationMutation } from '../../../api/receiversApi';
|
||||
import { GrafanaChannelValues } from '../../../types/receiver-form';
|
||||
import { defaultAnnotations } from '../../../utils/constants';
|
||||
import { stringifyErrorLike } from '../../../utils/misc';
|
||||
import { hasPlaceholderEmail } from '../../../utils/receiver-form';
|
||||
import AnnotationsStep from '../../rule-editor/AnnotationsStep';
|
||||
import LabelsField from '../../rule-editor/labels/LabelsField';
|
||||
|
||||
@@ -58,18 +59,7 @@ export const TestContactPointModal = ({
|
||||
const [testIntegration, { isLoading, error, isSuccess }] = useTestIntegrationMutation();
|
||||
|
||||
// Check if email integration has placeholder addresses
|
||||
const hasPlaceholderEmail = useMemo(() => {
|
||||
if (!channelValues || channelValues.type !== 'email') {
|
||||
return false;
|
||||
}
|
||||
const addresses = channelValues.settings?.addresses;
|
||||
if (!addresses) {
|
||||
return false;
|
||||
}
|
||||
const placeholders = ['<example@email.com>', 'example@email.com'];
|
||||
const addressList = typeof addresses === 'string' ? [addresses] : addresses;
|
||||
return addressList.some((addr: string) => placeholders.includes(addr?.trim()));
|
||||
}, [channelValues]);
|
||||
const isPlaceholderEmail = hasPlaceholderEmail(channelValues);
|
||||
|
||||
const onSubmit = async (data: FormFields) => {
|
||||
let alert: TestReceiversAlert | undefined;
|
||||
@@ -114,7 +104,7 @@ export const TestContactPointModal = ({
|
||||
/>
|
||||
)}
|
||||
|
||||
{hasPlaceholderEmail && (
|
||||
{isPlaceholderEmail && (
|
||||
<div className={styles.section}>
|
||||
<Alert
|
||||
title={t(
|
||||
@@ -171,9 +161,9 @@ export const TestContactPointModal = ({
|
||||
<Modal.ButtonRow>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isLoading || hasPlaceholderEmail}
|
||||
disabled={isLoading || isPlaceholderEmail}
|
||||
tooltip={
|
||||
hasPlaceholderEmail
|
||||
isPlaceholderEmail
|
||||
? t(
|
||||
'alerting.test-contact-point-modal.test-disabled-placeholder',
|
||||
'Please configure a valid email address before testing'
|
||||
|
||||
@@ -30,6 +30,7 @@ import { FetchRulerRulesFilter, fetchRulerRules } from '../api/ruler';
|
||||
import { addDefaultsToAlertmanagerConfig } from '../utils/alertmanager';
|
||||
import { getAllRulesSourceNames } from '../utils/datasource';
|
||||
import { makeAMLink } from '../utils/misc';
|
||||
import { receiverHasPlaceholderEmail } from '../utils/receiver-form';
|
||||
import { withAppEvents, withSerializedError } from '../utils/redux';
|
||||
import { getAlertInfo } from '../utils/rules';
|
||||
import { safeParsePrometheusDuration } from '../utils/time';
|
||||
@@ -272,27 +273,10 @@ interface TestReceiversOptions {
|
||||
alert?: TestReceiversAlert;
|
||||
}
|
||||
|
||||
// Check if a receiver uses placeholder email addresses
|
||||
function hasPlaceholderEmail(receivers: Receiver[]): boolean {
|
||||
const placeholderEmails = ['<example@email.com>', 'example@email.com'];
|
||||
|
||||
return receivers.some((receiver) =>
|
||||
receiver.grafana_managed_receiver_configs?.some((config) => {
|
||||
if (config.type === 'email' && config.settings?.addresses) {
|
||||
const addresses = config.settings.addresses;
|
||||
// addresses can be a string or array
|
||||
const addressList = typeof addresses === 'string' ? [addresses] : addresses;
|
||||
return addressList.some((addr: string) => placeholderEmails.includes(addr.trim()));
|
||||
}
|
||||
return false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export const testReceiversAction = createAsyncThunk(
|
||||
'unifiedalerting/testReceivers',
|
||||
async ({ alertManagerSourceName, receivers, alert }: TestReceiversOptions): Promise<void> => {
|
||||
const usesPlaceholder = hasPlaceholderEmail(receivers);
|
||||
const usesPlaceholder = receiverHasPlaceholderEmail(receivers);
|
||||
|
||||
if (usesPlaceholder) {
|
||||
// Handle placeholder email case with custom warning message
|
||||
|
||||
@@ -304,3 +304,42 @@ export function omitTemporaryIdentifiers<T>(object: Readonly<T>): T {
|
||||
|
||||
return objectCopy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Placeholder emails that ship with the default grafana-default-email contact point.
|
||||
* These should not trigger actual email sends or throw errors.
|
||||
*/
|
||||
const PLACEHOLDER_EMAILS = ['<example@email.com>', 'example@email.com'];
|
||||
|
||||
/**
|
||||
* Check if a single channel/integration has placeholder email addresses.
|
||||
* Used in UI components to disable test buttons and show warnings.
|
||||
*/
|
||||
export function hasPlaceholderEmail(channelValues?: GrafanaChannelValues): boolean {
|
||||
if (!channelValues || channelValues.type !== 'email') {
|
||||
return false;
|
||||
}
|
||||
const addresses = channelValues.settings?.addresses;
|
||||
if (!addresses) {
|
||||
return false;
|
||||
}
|
||||
const addressList = typeof addresses === 'string' ? [addresses] : addresses;
|
||||
return addressList.some((addr: string) => PLACEHOLDER_EMAILS.includes(addr?.trim()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if any receiver in a list has placeholder email addresses.
|
||||
* Used in actions to determine if warning messages should be shown.
|
||||
*/
|
||||
export function receiverHasPlaceholderEmail(receivers: Receiver[]): boolean {
|
||||
return receivers.some((receiver) =>
|
||||
receiver.grafana_managed_receiver_configs?.some((config) => {
|
||||
if (config.type === 'email' && config.settings?.addresses) {
|
||||
const addresses = config.settings.addresses;
|
||||
const addressList = typeof addresses === 'string' ? [addresses] : addresses;
|
||||
return addressList.some((addr: string) => PLACEHOLDER_EMAILS.includes(addr.trim()));
|
||||
}
|
||||
return false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user