Merge pull request #2617 from career-yashaswee/bug/2603-url-validation-email-format

(fix): implemented email and webhook url validation with proper error and toast creation
This commit is contained in:
Alexander Holliday
2025-07-16 09:16:12 -07:00
committed by GitHub
3 changed files with 71 additions and 28 deletions

View File

@@ -65,12 +65,19 @@ const CreateNotifications = () => {
const [isOpen, setIsOpen] = useState(false);
const getNotificationTypeValue = (typeId) => {
return NOTIFICATION_TYPES.find((type) => type._id === typeId)?.value || "email";
};
const extractError = (error, field) =>
error?.details.find((d) => d.path.includes(field))?.message;
// handlers
const onSubmit = (e) => {
e.preventDefault();
const form = {
...notification,
type: NOTIFICATION_TYPES.find((type) => type._id === notification.type).value,
type: getNotificationTypeValue(notification.type),
};
let error = null;
@@ -84,7 +91,7 @@ const CreateNotifications = () => {
});
console.log(JSON.stringify(newErrors));
console.log(JSON.stringify(form, null, 2));
createToast({ body: "Please check the form for errors." });
createToast({ body: Object.values(newErrors)[0] });
setErrors(newErrors);
return;
}
@@ -98,22 +105,32 @@ const CreateNotifications = () => {
const onChange = (e) => {
const { name, value } = e.target;
let rawNotification = { ...notification, [name]: value };
let newNotification = {
...rawNotification,
type: getNotificationTypeValue(rawNotification.type),
};
const newNotification = { ...notification, [name]: value };
const { error } = notificationValidation.validate(newNotification, {
abortEarly: false,
});
let validationError = { ...errors };
const { error } = notificationValidation.extract(name).validate(value);
setErrors((prev) => ({
...prev,
[name]: error?.message,
}));
if (name === "type") {
validationError["type"] = extractError(error, "type");
validationError["address"] = extractError(error, "address");
} else {
validationError[name] = extractError(error, name);
}
setNotification(newNotification);
setNotification(rawNotification);
setErrors(validationError);
};
const onTestNotification = () => {
const form = {
...notification,
type: NOTIFICATION_TYPES.find((type) => type._id === notification.type).value,
type: getNotificationTypeValue(notification.type),
};
let error = null;
@@ -125,7 +142,7 @@ const CreateNotifications = () => {
error.details.forEach((err) => {
newErrors[err.path[0]] = err.message;
});
createToast({ body: "Please check the form for errors." });
createToast({ body: Object.values(newErrors)[0] });
setErrors(newErrors);
return;
}
@@ -139,7 +156,7 @@ const CreateNotifications = () => {
}
};
const type = NOTIFICATION_TYPES.find((type) => type._id === notification.type).value;
const type = getNotificationTypeValue(notification.type);
return (
<Stack gap={theme.spacing(10)}>
<Breadcrumbs list={BREADCRUMBS} />

View File

@@ -410,14 +410,33 @@ const notificationValidation = joi.object({
"string.empty": "Notification name is required",
"any.required": "Notification name is required",
}),
address: joi.string().required().messages({
"string.empty": "This field cannot be empty",
"string.base": "This field must be a string",
"any.required": "This field is required",
}),
type: joi.string().required().messages({
"string.empty": "This field is required",
"any.required": "This field is required",
type: joi
.string()
.valid("email", "webhook", "slack", "discord", "pager_duty")
.required()
.messages({
"string.empty": "Notification type is required",
"any.required": "Notification type is required",
"any.only": "Notification type must be email, webhook, or pager_duty",
}),
address: joi.when("type", {
is: "email",
then: joi
.string()
.email({ tlds: { allow: false } })
.required()
.messages({
"string.empty": "E-mail address cannot be empty",
"any.required": "E-mail address is required",
"string.email": "Please enter a valid e-mail address",
}),
otherwise: joi.string().uri().required().messages({
"string.empty": "Webhook URL cannot be empty",
"any.required": "Webhook URL is required",
"string.uri": "Please enter a valid Webhook URL",
}),
}),
});

View File

@@ -577,14 +577,7 @@ const createNotificationBodyValidation = joi.object({
"string.empty": "Notification name is required",
"any.required": "Notification name is required",
}),
address: joi.when("type", {
is: "email",
then: joi.string().email().required().messages({
"string.empty": "E-mail address cannot be empty",
"any.required": "E-mail address is required",
"string.email": "Please enter a valid e-mail address",
}),
}),
type: joi
.string()
.valid("email", "webhook", "slack", "discord", "pager_duty")
@@ -594,6 +587,20 @@ const createNotificationBodyValidation = joi.object({
"any.required": "Notification type is required",
"any.only": "Notification type must be email, webhook, or pager_duty",
}),
address: joi.when("type", {
is: "email",
then: joi.string().email().required().messages({
"string.empty": "E-mail address cannot be empty",
"any.required": "E-mail address is required",
"string.email": "Please enter a valid e-mail address",
}),
otherwise: joi.string().uri().required().messages({
"string.empty": "Webhook URL cannot be empty",
"any.required": "Webhook URL is required",
"string.uri": "Please enter a valid Webhook URL",
}),
}),
});
//****************************************