"use client"; import React from "react"; import { ActionButton } from "@/components/ui/action-button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { FullPageSpinner } from "@/components/ui/full-page-spinner"; import { Input } from "@/components/ui/input"; import { toast } from "@/components/ui/use-toast"; import { useTranslation } from "@/lib/i18n/client"; import { api } from "@/lib/trpc"; import { zodResolver } from "@hookform/resolvers/zod"; import { Edit, KeyRound, Plus, PlusCircle, Save, Trash2, X, } from "lucide-react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { zNewWebhookSchema, zUpdateWebhookSchema, ZWebhook, } from "@karakeep/shared/types/webhooks"; import ActionConfirmingDialog from "../ui/action-confirming-dialog"; import { Button } from "../ui/button"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "../ui/dialog"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "../ui/table"; import { WebhookEventSelector } from "./WebhookEventSelector"; export function WebhooksEditorDialog() { const { t } = useTranslation(); const [open, setOpen] = React.useState(false); const apiUtils = api.useUtils(); const form = useForm>({ resolver: zodResolver(zNewWebhookSchema), defaultValues: { url: "", events: [], token: "", }, }); React.useEffect(() => { if (open) { form.reset(); } }, [open]); const { mutateAsync: createWebhook, isPending: isCreating } = api.webhooks.create.useMutation({ onSuccess: () => { toast({ description: "Webhook has been created!", }); apiUtils.webhooks.list.invalidate(); setOpen(false); }, }); return ( {t("settings.webhooks.create_webhook")}
{ await createWebhook(value); form.resetField("url"); form.resetField("events"); })} > { return ( URL ); }} /> ( {t("settings.webhooks.auth_token")} )} /> ( Events )} /> { await createWebhook(value); })} loading={isCreating} variant="default" className="items-center" > Add
); } export function EditWebhookDialog({ webhook }: { webhook: ZWebhook }) { const { t } = useTranslation(); const apiUtils = api.useUtils(); const [open, setOpen] = React.useState(false); React.useEffect(() => { if (open) { form.reset({ webhookId: webhook.id, url: webhook.url, events: webhook.events, }); } }, [open]); const { mutateAsync: updateWebhook, isPending: isUpdating } = api.webhooks.update.useMutation({ onSuccess: () => { toast({ description: "Webhook has been updated!", }); setOpen(false); apiUtils.webhooks.list.invalidate(); }, }); const updateSchema = zUpdateWebhookSchema.required({ events: true, url: true, }); const form = useForm>({ resolver: zodResolver(updateSchema), defaultValues: { webhookId: webhook.id, url: webhook.url, events: webhook.events, }, }); return ( {t("settings.webhooks.edit_webhook")}
{ await updateWebhook(value); })} > { return ( ); }} /> { return ( {t("common.url")} ); }} /> ( {t("settings.webhooks.events.title")} )} /> { await updateWebhook(value); })} type="submit" className="items-center" > {t("actions.save")}
); } export function EditTokenDialog({ webhook }: { webhook: ZWebhook }) { const { t } = useTranslation(); const apiUtils = api.useUtils(); const [open, setOpen] = React.useState(false); React.useEffect(() => { if (open) { form.reset({ webhookId: webhook.id, token: "", }); } }, [open]); const updateSchema = zUpdateWebhookSchema .pick({ webhookId: true, token: true, }) .required({ token: true, }); const form = useForm>({ resolver: zodResolver(updateSchema), defaultValues: { webhookId: webhook.id, token: "", }, }); const { mutateAsync: updateWebhook, isPending: isUpdating } = api.webhooks.update.useMutation({ onSuccess: () => { toast({ description: "Webhook token has been updated!", }); setOpen(false); apiUtils.webhooks.list.invalidate(); }, }); return ( {t("settings.webhooks.edit_auth_token")}
{ await updateWebhook(value); })} > ( )} /> ( {t("settings.webhooks.auth_token")} )} /> { await updateWebhook({ webhookId: value.webhookId, token: null, }); })} className="items-center" > {t("actions.delete")} { await updateWebhook(value); })} type="submit" className="items-center" > {t("actions.save")}
); } export function WebhookRow({ webhook }: { webhook: ZWebhook }) { const { t } = useTranslation(); const apiUtils = api.useUtils(); const { mutate: deleteWebhook, isPending: isDeleting } = api.webhooks.delete.useMutation({ onSuccess: () => { toast({ description: "Webhook has been deleted!", }); apiUtils.webhooks.list.invalidate(); }, }); return ( {webhook.url} {webhook.events.join(", ")} {webhook.hasToken ? "*******" : } ( deleteWebhook({ webhookId: webhook.id })} className="items-center" type="button" > {t("actions.delete")} )} > ); } export default function WebhookSettings() { const { t } = useTranslation(); const { data: webhooks, isLoading } = api.webhooks.list.useQuery(); return (
{t("settings.webhooks.webhooks")}

{t("settings.webhooks.description")}

{isLoading && } {webhooks && webhooks.webhooks.length == 0 && (

You don't have any webhooks configured yet.

)} {webhooks && webhooks.webhooks.length > 0 && ( {t("common.url")} {t("settings.webhooks.events.title")} {t("settings.webhooks.auth_token")} {t("common.actions")} {webhooks.webhooks.map((webhook) => ( ))}
)}
); }