Initial Release
This commit is contained in:
+349
@@ -0,0 +1,349 @@
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogFooter
|
||||
} from "@/components/ui/dialog";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
||||
import { AlertConfiguration, alertConfigService } from "@/services/alertConfigService";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "@/components/ui/form";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Loader2 } from "lucide-react";
|
||||
|
||||
interface NotificationChannelDialogProps {
|
||||
open: boolean;
|
||||
onClose: (refreshList: boolean) => void;
|
||||
editingConfig: AlertConfiguration | null;
|
||||
}
|
||||
|
||||
const baseSchema = z.object({
|
||||
notify_name: z.string().min(1, "Name is required"),
|
||||
notification_type: z.enum(["telegram", "discord", "slack", "signal", "email"]),
|
||||
enabled: z.boolean().default(true),
|
||||
service_id: z.string().default("global"), // Assuming global for now, could be linked to specific services
|
||||
template_id: z.string().optional(),
|
||||
});
|
||||
|
||||
const telegramSchema = baseSchema.extend({
|
||||
notification_type: z.literal("telegram"),
|
||||
telegram_chat_id: z.string().min(1, "Chat ID is required"),
|
||||
bot_token: z.string().min(1, "Bot token is required"),
|
||||
});
|
||||
|
||||
const discordSchema = baseSchema.extend({
|
||||
notification_type: z.literal("discord"),
|
||||
discord_webhook_url: z.string().url("Must be a valid URL"),
|
||||
});
|
||||
|
||||
const slackSchema = baseSchema.extend({
|
||||
notification_type: z.literal("slack"),
|
||||
slack_webhook_url: z.string().url("Must be a valid URL"),
|
||||
});
|
||||
|
||||
const signalSchema = baseSchema.extend({
|
||||
notification_type: z.literal("signal"),
|
||||
signal_number: z.string().min(1, "Signal number is required"),
|
||||
});
|
||||
|
||||
const emailSchema = baseSchema.extend({
|
||||
notification_type: z.literal("email"),
|
||||
// Email specific fields could be added here
|
||||
});
|
||||
|
||||
const formSchema = z.discriminatedUnion("notification_type", [
|
||||
telegramSchema,
|
||||
discordSchema,
|
||||
slackSchema,
|
||||
signalSchema,
|
||||
emailSchema
|
||||
]);
|
||||
|
||||
type FormValues = z.infer<typeof formSchema>;
|
||||
|
||||
export const NotificationChannelDialog = ({
|
||||
open,
|
||||
onClose,
|
||||
editingConfig
|
||||
}: NotificationChannelDialogProps) => {
|
||||
const isEditing = !!editingConfig;
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
notify_name: "",
|
||||
notification_type: "telegram" as const,
|
||||
enabled: true,
|
||||
service_id: "global",
|
||||
template_id: "",
|
||||
},
|
||||
});
|
||||
|
||||
const { watch, reset } = form;
|
||||
const notificationType = watch("notification_type");
|
||||
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (editingConfig) {
|
||||
// Handle string vs boolean for enabled field
|
||||
const enabled = typeof editingConfig.enabled === 'string'
|
||||
? editingConfig.enabled === "true"
|
||||
: !!editingConfig.enabled;
|
||||
|
||||
reset({
|
||||
...editingConfig,
|
||||
enabled
|
||||
});
|
||||
} else if (open) {
|
||||
reset({
|
||||
notify_name: "",
|
||||
notification_type: "telegram" as const,
|
||||
enabled: true,
|
||||
service_id: "global",
|
||||
template_id: "",
|
||||
});
|
||||
}
|
||||
}, [editingConfig, open, reset]);
|
||||
|
||||
const handleClose = () => {
|
||||
onClose(false);
|
||||
};
|
||||
|
||||
const onSubmit = async (values: FormValues) => {
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
// Ensure service_id is always present
|
||||
const configData = {
|
||||
...values,
|
||||
service_id: values.service_id || "global",
|
||||
};
|
||||
|
||||
if (isEditing && editingConfig?.id) {
|
||||
await alertConfigService.updateAlertConfiguration(editingConfig.id, configData);
|
||||
} else {
|
||||
await alertConfigService.createAlertConfiguration(configData as any);
|
||||
}
|
||||
onClose(true); // Close with refresh
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={() => handleClose()}>
|
||||
<DialogContent className="sm:max-w-[500px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{isEditing ? "Edit Notification Channel" : "Add Notification Channel"}
|
||||
</DialogTitle>
|
||||
</DialogHeader>
|
||||
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="notify_name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="My Notification Channel" {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
A name to identify this notification channel
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="notification_type"
|
||||
render={({ field }) => (
|
||||
<FormItem className="space-y-3">
|
||||
<FormLabel>Channel Type</FormLabel>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
onValueChange={field.onChange}
|
||||
defaultValue={field.value}
|
||||
value={field.value}
|
||||
className="flex flex-col space-y-1"
|
||||
>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="telegram" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Telegram
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="discord" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Discord
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="slack" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Slack
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="signal" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Signal
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
<FormItem className="flex items-center space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<RadioGroupItem value="email" />
|
||||
</FormControl>
|
||||
<FormLabel className="font-normal">
|
||||
Email
|
||||
</FormLabel>
|
||||
</FormItem>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Show different fields based on notification type */}
|
||||
{notificationType === "telegram" && (
|
||||
<>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="telegram_chat_id"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Chat ID</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Telegram Chat ID" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bot_token"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bot Token</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Telegram Bot Token" {...field} type="password" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{notificationType === "discord" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="discord_webhook_url"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Discord Webhook URL" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{notificationType === "slack" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="slack_webhook_url"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Webhook URL</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Slack Webhook URL" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{notificationType === "signal" && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="signal_number"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Signal Number</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="+1234567890" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="enabled"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
|
||||
<div className="space-y-0.5">
|
||||
<FormLabel>Enabled</FormLabel>
|
||||
<FormDescription>
|
||||
Turn notifications on or off
|
||||
</FormDescription>
|
||||
</div>
|
||||
<FormControl>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<DialogFooter>
|
||||
<Button variant="outline" type="button" onClick={handleClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
{isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
|
||||
{isEditing ? "Update" : "Create"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user