diff --git a/client/src/hooks/forms/UseInitNotificationsChannelForm.tsx b/client/src/hooks/forms/UseInitNotificationsChannelForm.tsx index c0b1ba95c..e215d6f52 100644 --- a/client/src/hooks/forms/UseInitNotificationsChannelForm.tsx +++ b/client/src/hooks/forms/UseInitNotificationsChannelForm.tsx @@ -1,4 +1,4 @@ -import { notificationChannelSchema } from "@/validation/zod"; +import { notificationChannelSchema } from "@/validation"; import { useMemo } from "react"; import { z } from "zod"; diff --git a/client/src/pages/infrastructure/InfraConfig.tsx b/client/src/pages/infrastructure/InfraConfig.tsx index 0d640e416..e0d0956d5 100644 --- a/client/src/pages/infrastructure/InfraConfig.tsx +++ b/client/src/pages/infrastructure/InfraConfig.tsx @@ -1,4 +1,3 @@ -import { monitorSchemaInfra } from "@/validation"; import { useGet, usePatch } from "@/hooks/UseApi"; import { InfraForm } from "@/pages/infrastructure/InfraForm"; diff --git a/client/src/pages/notification-channels/NotificationChannelsConfig.tsx b/client/src/pages/notification-channels/NotificationChannelsConfig.tsx index 5b71fd47a..7cb12d9c4 100644 --- a/client/src/pages/notification-channels/NotificationChannelsConfig.tsx +++ b/client/src/pages/notification-channels/NotificationChannelsConfig.tsx @@ -5,7 +5,7 @@ import { useNavigate } from "react-router"; import { z } from "zod"; import { usePatch, useGet } from "@/hooks/UseApi"; import type { ApiResponse } from "@/types/api"; -import { notificationChannelSchema } from "@/validation/zod"; +import { notificationChannelSchema } from "@/validation"; import type { INotificationChannel } from "@/types/notification-channel"; type FormValues = z.infer; diff --git a/client/src/pages/notification-channels/NotificationChannelsCreate.tsx b/client/src/pages/notification-channels/NotificationChannelsCreate.tsx index 0890f410b..bbfc0c0cc 100644 --- a/client/src/pages/notification-channels/NotificationChannelsCreate.tsx +++ b/client/src/pages/notification-channels/NotificationChannelsCreate.tsx @@ -3,7 +3,7 @@ import { NotificationChannelsForm } from "./NotificationChannelsForm"; import { useNavigate } from "react-router"; import { z } from "zod"; import { usePost } from "@/hooks/UseApi"; -import { notificationChannelSchema } from "@/validation/zod"; +import { notificationChannelSchema } from "@/validation"; import type { INotificationChannel } from "@/types/notification-channel"; type FormValues = z.infer; diff --git a/client/src/pages/notification-channels/NotificationChannelsForm.tsx b/client/src/pages/notification-channels/NotificationChannelsForm.tsx index 422c6dd6c..155106b83 100644 --- a/client/src/pages/notification-channels/NotificationChannelsForm.tsx +++ b/client/src/pages/notification-channels/NotificationChannelsForm.tsx @@ -10,7 +10,7 @@ import { ChannelTypes } from "@/types/notification-channel"; import { zodResolver } from "@hookform/resolvers/zod"; import { useTranslation } from "react-i18next"; import { z } from "zod"; -import { notificationChannelSchema } from "@/validation/zod"; +import { notificationChannelSchema } from "@/validation"; import { useForm, Controller, type SubmitHandler } from "react-hook-form"; import { useEffect } from "react"; import { useInitForm } from "@/hooks/forms/UseInitNotificationsChannelForm"; @@ -79,6 +79,7 @@ export const NotificationChannelsForm = ({ ( { + const { type, config } = data; + if (!config.url && !config.emailAddress) { + ctx.addIssue({ + code: "custom", + message: "Either a URL or an email address must be provided.", + path: ["config"], + }); + } + + if (type === "email" && !config.emailAddress) { + ctx.addIssue({ + code: "custom", + message: "Email address is required for email-type channels.", + path: ["config", "emailAddress"], + }); + } else if (type !== "email" && !config.url) { + ctx.addIssue({ + code: "custom", + message: "URL is required for non-email-type channels.", + path: ["config", "url"], + }); + } + }); diff --git a/client/src/validation/zod.ts b/client/src/validation/zod.ts index c7378636e..b2e0f17a2 100644 --- a/client/src/validation/zod.ts +++ b/client/src/validation/zod.ts @@ -1,10 +1,8 @@ import { z } from "zod"; // humanInterval moved to split schema files -import { ChannelTypes } from "@/types/notification-channel"; import { MaintenanceRepeats } from "@/types/maintenance"; -const urlRegex = - /^(https?:\/\/)?(localhost|([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}|[a-zA-Z0-9-]+|(\d{1,3}\.){3}\d{1,3})(:\d{1,5})?(\/.*)?$/; +// urlRegex moved to client/src/validation/utils.ts // monitor duration schema moved to client/src/validation/monitor.ts // pagespeed duration schema moved to client/src/validation/pagespeed.ts @@ -41,46 +39,7 @@ export const inviteSchema = z.object({ orgRoleId: z.string().optional(), }); -export const notificationChannelSchema = z - .object({ - name: z.string().min(1, "Channel name is required"), - type: z.enum(ChannelTypes, { error: "Invalid channel type" }), - config: z.object({ - url: z - .string() - .regex(urlRegex, "Invalid URL") - .or(z.literal("")) - .optional(), - emailAddress: z - .email("Invalid email address") - .or(z.literal("")) - .optional(), - }), - }) - .superRefine((data, ctx) => { - const { type, config } = data; - if (!config.url && !config.emailAddress) { - ctx.addIssue({ - code: "custom", - message: "Either a URL or an email address must be provided.", - path: ["config"], - }); - } - - if (type === "email" && !config.emailAddress) { - ctx.addIssue({ - code: "custom", - message: "Email address is required for email-type channels.", - path: ["config", "emailAddress"], - }); - } else if (type !== "email" && !config.url) { - ctx.addIssue({ - code: "custom", - message: "URL is required for non-email-type channels.", - path: ["config", "url"], - }); - } - }); +// moved to client/src/validation/notification-channel.ts export const maintenanceSchema = z .object({