import { arktypeResolver } from "@hookform/resolvers/arktype"; import { type } from "arktype"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { cn, slugify } from "~/client/lib/utils"; import { deepClean } from "~/utils/object"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "~/client/components/ui/form"; import { Input } from "~/client/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select"; import { Checkbox } from "~/client/components/ui/checkbox"; import { notificationConfigSchema } from "~/schemas/notifications"; export const formSchema = type({ name: "2<=string<=32", }).and(notificationConfigSchema); const cleanSchema = type.pipe((d) => formSchema(deepClean(d))); export type NotificationFormValues = typeof formSchema.inferIn; type Props = { onSubmit: (values: NotificationFormValues) => void; mode?: "create" | "update"; initialValues?: Partial; formId?: string; className?: string; }; const defaultValuesForType = { email: { type: "email" as const, smtpHost: "", smtpPort: 587, username: "", password: "", from: "", to: [], useTLS: true, }, slack: { type: "slack" as const, webhookUrl: "", }, discord: { type: "discord" as const, webhookUrl: "", }, gotify: { type: "gotify" as const, serverUrl: "", token: "", priority: 5, }, ntfy: { type: "ntfy" as const, topic: "", priority: "default" as const, }, pushover: { type: "pushover" as const, userKey: "", apiToken: "", priority: 0 as const, }, telegram: { type: "telegram" as const, botToken: "", chatId: "", }, custom: { type: "custom" as const, shoutrrrUrl: "", }, }; export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValues, formId, className }: Props) => { const form = useForm({ resolver: arktypeResolver(cleanSchema as unknown as typeof formSchema), defaultValues: initialValues, resetOptions: { keepDefaultValues: true, keepDirtyValues: false, }, }); const { watch } = form; const watchedType = watch("type"); useEffect(() => { if (!initialValues) { form.reset({ name: form.getValues().name, ...defaultValuesForType[watchedType as keyof typeof defaultValuesForType], }); } }, [watchedType, form, initialValues]); return (
( Name field.onChange(slugify(e.target.value))} max={32} min={2} /> Unique identifier for this notification destination. )} /> ( Type Choose the notification delivery method. )} /> {watchedType === "email" && ( <> ( SMTP Host )} /> ( SMTP Port field.onChange(Number(e.target.value))} /> )} /> ( Username )} /> ( Password )} /> ( From Address )} /> ( To Addresses field.onChange(e.target.value.split(",").map((email) => email.trim()))} /> Comma-separated list of recipient email addresses. )} /> (
Use TLS Enable TLS encryption for SMTP connection.
)} /> )} {watchedType === "slack" && ( <> ( Webhook URL Get this from your Slack app's Incoming Webhooks settings. )} /> ( Channel (Optional) Override the default channel (use # for channels, @ for users). )} /> ( Bot Username (Optional) )} /> ( Icon Emoji (Optional) )} /> )} {watchedType === "discord" && ( <> ( Webhook URL Get this from your Discord server's Integrations settings. )} /> ( Bot Username (Optional) )} /> ( Avatar URL (Optional) )} /> ( Thread ID (Optional) ID of the thread to post messages in. Leave empty to post in the main channel. )} /> )} {watchedType === "gotify" && ( <> ( Server URL Your self-hosted Gotify server URL. )} /> ( App Token Application token from Gotify. )} /> ( Priority field.onChange(Number(e.target.value))} /> Priority level (0-10, where 10 is highest). )} /> ( Path (Optional) Custom path on the Gotify server, if applicable. )} /> )} {watchedType === "ntfy" && ( <> ( Server URL (Optional) Leave empty to use ntfy.sh public service. )} /> ( Topic The ntfy topic name to publish to. )} /> ( Username (Optional) Username for server authentication, if required. )} /> ( Password (Optional) Password for server authentication, if required. )} /> ( Priority )} /> )} {watchedType === "pushover" && ( <> ( User Key Your Pushover user key from the dashboard. )} /> ( API Token Application API token from your Pushover application. )} /> ( Devices (Optional) Comma-separated list of device names. Leave empty for all devices. )} /> ( Priority Message priority level. )} /> )} {watchedType === "telegram" && ( <> ( Bot Token Telegram bot token. Get this from BotFather when you create your bot. )} /> ( Chat ID Telegram chat ID to send notifications to. )} /> )} {watchedType === "custom" && ( ( Shoutrrr URL Direct Shoutrrr URL for power users. See  Shoutrrr documentation  for supported services and URL formats. )} /> )} ); };