diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/channel-form.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/channel-form.schema.ts index f9359c40..13779243 100644 --- a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/channel-form.schema.ts +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/channel-form.schema.ts @@ -1,26 +1,69 @@ import {z} from "zod"; +import {SlackChannelConfigSchema} from "./providers/notifications/forms/slack.schema"; +import {SmtpChannelConfigSchema} from "./providers/notifications/forms/smtp.schema"; +import {DiscordChannelConfigSchema} from "./providers/notifications/forms/discord.schema"; +import {TelegramChannelConfigSchema} from "./providers/notifications/forms/telegram.schema"; +import {GotifyChannelConfigSchema} from "./providers/notifications/forms/gotify.schema"; +import {NtfyChannelConfigSchema} from "./providers/notifications/forms/ntfy.schema"; +import {WebhookChannelConfigSchema} from "./providers/notifications/forms/webhook.schema"; +import {S3ChannelConfigSchema} from "./providers/storages/forms/s3.schema"; +import {GoogleDriveChannelConfigSchema} from "./providers/storages/forms/google-drive.schema"; +import {LocalChannelConfigSchema} from "./providers/storages/forms/local.schema"; -export const ChannelFormSchema = z.object({ +const BaseChannelFormSchema = z.object({ name: z .string() .min(5, "Name must be at least 5 characters long") .max(40, "Name must be at most 40 characters long"), - config: z.record(z.union([z.string(), z.number(), z.boolean(), z.null(), z.undefined()])).optional(), enabled: z.boolean().default(true), }); +export const NotificationChannelFormSchema = z.discriminatedUnion("provider", [ + BaseChannelFormSchema.extend({ + provider: z.literal("slack"), + config: SlackChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("smtp"), + config: SmtpChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("discord"), + config: DiscordChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("telegram"), + config: TelegramChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("gotify"), + config: GotifyChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("ntfy"), + config: NtfyChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("webhook"), + config: WebhookChannelConfigSchema, + }), +]); -export const NotificationChannelFormSchema = ChannelFormSchema.extend({ - provider: z.enum( - ["slack", "smtp", "discord", "telegram", "gotify", "ntfy", "webhook"], - {required_error: "Provider is required"} - ), -}); - -export const StorageChannelFormSchema = ChannelFormSchema.extend({ - provider: z.enum(["local", "s3", "google-drive"], {required_error: "Provider is required"}), -}); +export const StorageChannelFormSchema = z.discriminatedUnion("provider", [ + BaseChannelFormSchema.extend({ + provider: z.literal("s3"), + config: S3ChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("google-drive"), + config: GoogleDriveChannelConfigSchema, + }), + BaseChannelFormSchema.extend({ + provider: z.literal("local"), + config: LocalChannelConfigSchema + }) +]); export type NotificationChannelFormType = z.infer; diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/discord.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/discord.schema.ts new file mode 100644 index 00000000..b7303943 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/discord.schema.ts @@ -0,0 +1,5 @@ +import {z} from "zod"; + +export const DiscordChannelConfigSchema = z.object({ + discordWebhook: z.string().url("Must be a valid URL"), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/gotify.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/gotify.schema.ts new file mode 100644 index 00000000..ef6209d5 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/gotify.schema.ts @@ -0,0 +1,6 @@ +import {z} from "zod"; + +export const GotifyChannelConfigSchema = z.object({ + gotifyServerUrl: z.string().url("Must be a valid URL"), + gotifyAppToken: z.string().min(1, "App token is required"), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/ntfy.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/ntfy.schema.ts new file mode 100644 index 00000000..d8971e77 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/ntfy.schema.ts @@ -0,0 +1,9 @@ +import {z} from "zod"; + +export const NtfyChannelConfigSchema = z.object({ + ntfyTopic: z.string().min(1, "Topic is required"), + ntfyServerUrl: z.string().url("Must be a valid URL").optional().or(z.literal('')), + ntfyToken: z.string().optional(), + ntfyUsername: z.string().optional(), + ntfyPassword: z.string().optional(), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/slack.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/slack.schema.ts new file mode 100644 index 00000000..ba81d534 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/slack.schema.ts @@ -0,0 +1,5 @@ +import {z} from "zod"; + +export const SlackChannelConfigSchema = z.object({ + slackWebhook: z.string().url("Must be a valid URL"), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/smtp.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/smtp.schema.ts new file mode 100644 index 00000000..9844ec43 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/smtp.schema.ts @@ -0,0 +1,10 @@ +import {z} from "zod"; + +export const SmtpChannelConfigSchema = z.object({ + host: z.string().min(1, "Host is required"), + port: z.coerce.number().min(1, "Port is required"), + user: z.string().min(1, "User is required"), + password: z.string().min(1, "Password is required"), + from: z.string().min(1, "From is required"), + to: z.string().min(1, "To is required"), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/telegram.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/telegram.schema.ts new file mode 100644 index 00000000..2dace306 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/telegram.schema.ts @@ -0,0 +1,20 @@ +import { z } from "zod"; + +export const TelegramChannelConfigSchema = z + .object({ + telegramBotToken: z.string().min(1, "Bot token is required"), + telegramChatId: z.string().min(1, "Chat ID is required"), + telegramTopicId: z.string().optional(), + }) + .refine( + (data) => { + if (data.telegramTopicId && !data.telegramChatId) { + return false; + } + return true; + }, + { + message: "Chat ID is required when a Topic ID is provided", + path: ["telegramChatId"], + }, + ); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/webhook.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/webhook.schema.ts new file mode 100644 index 00000000..0d35ee59 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/notifications/forms/webhook.schema.ts @@ -0,0 +1,7 @@ +import {z} from "zod"; + +export const WebhookChannelConfigSchema = z.object({ + webhookUrl: z.string().url("Must be a valid URL"), + webhookSecretHeader: z.string().optional(), + webhookSecret: z.string().optional(), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/google-drive.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/google-drive.schema.ts new file mode 100644 index 00000000..e22b0b9a --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/google-drive.schema.ts @@ -0,0 +1,8 @@ +import {z} from "zod"; + +export const GoogleDriveChannelConfigSchema = z.object({ + clientId: z.string().min(1, "Client ID is required"), + clientSecret: z.string().min(1, "Client Secret is required"), + folderId: z.string().min(1, "Folder ID is required"), + refreshToken: z.string().optional(), +}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/local.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/local.schema.ts new file mode 100644 index 00000000..f8008038 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/local.schema.ts @@ -0,0 +1,3 @@ +import {z} from "zod"; + +export const LocalChannelConfigSchema = z.object({}); diff --git a/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/s3.schema.ts b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/s3.schema.ts new file mode 100644 index 00000000..0d1cd227 --- /dev/null +++ b/src/components/wrappers/dashboard/admin/channels/channel/channel-form/providers/storages/forms/s3.schema.ts @@ -0,0 +1,11 @@ +import {z} from "zod"; + +export const S3ChannelConfigSchema = z.object({ + endPointUrl: z.string().min(1, "Endpoint URL is required"), + region: z.string().min(1, "Region is required"), + accessKey: z.string().min(1, "Access Key is required"), + secretKey: z.string().min(1, "Secret Key is required"), + bucketName: z.string().min(1, "Bucket name is required"), + port: z.coerce.number().optional(), + ssl: z.boolean().optional().default(true), +});