import { useTranslation } from "react-i18next"; import { DownOutlined as DownOutlinedIcon } from "@ant-design/icons"; import { Alert, Button, Dropdown, Form, type FormInstance, Input, Select, Switch } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { z } from "zod"; import CodeInput from "@/components/CodeInput"; import Show from "@/components/Show"; import { type AccessConfigForWebhook } from "@/domain/access"; type AccessFormWebhookConfigFieldValues = Nullish; export type AccessFormWebhookConfigProps = { form: FormInstance; formName: string; disabled?: boolean; initialValues?: AccessFormWebhookConfigFieldValues; usage?: "deployment" | "notification" | "none"; onValuesChange?: (values: AccessFormWebhookConfigFieldValues) => void; }; const initFormModel = (): AccessFormWebhookConfigFieldValues => { return { url: "", method: "POST", headers: "Content-Type: application/json", allowInsecureConnections: false, defaultDataForDeployment: JSON.stringify( { name: "${DOMAINS}", cert: "${CERTIFICATE}", privkey: "${PRIVATE_KEY}", }, null, 2 ), defaultDataForNotification: JSON.stringify( { subject: "${SUBJECT}", message: "${MESSAGE}", }, null, 2 ), }; }; const AccessFormWebhookConfig = ({ form: formInst, formName, disabled, initialValues, usage, onValuesChange }: AccessFormWebhookConfigProps) => { const { t } = useTranslation(); const formSchema = z.object({ url: z.string().url(t("common.errmsg.url_invalid")), method: z.union([z.literal("GET"), z.literal("POST"), z.literal("PUT"), z.literal("PATCH"), z.literal("DELETE")], { message: t("access.form.webhook_method.placeholder"), }), headers: z .string() .nullish() .refine((v) => { if (!v) return true; const lines = v.split(/\r?\n/); for (const line of lines) { if (line.split(":").length < 2) { return false; } } return true; }, t("access.form.webhook_headers.errmsg.invalid")), allowInsecureConnections: z.boolean().nullish(), defaultDataForDeployment: z .string() .nullish() .refine((v) => { if (usage && usage !== "deployment") return true; if (!v) return true; try { const obj = JSON.parse(v); return typeof obj === "object" && !Array.isArray(obj); } catch { return false; } }, t("access.form.webhook_default_data.errmsg.json_invalid")), defaultDataForNotification: z .string() .nullish() .refine((v) => { if (usage && usage !== "notification") return true; if (!v) return true; try { const obj = JSON.parse(v); return typeof obj === "object" && !Array.isArray(obj); } catch { return false; } }, t("access.form.webhook_default_data.errmsg.json_invalid")), }); const formRule = createSchemaFieldRule(formSchema); const handleWebhookHeadersBlur = (e: React.FocusEvent) => { let value = e.target.value; value = value.trim(); value = value.replace(/(? { const value = formInst.getFieldValue("defaultDataForDeployment"); try { const json = JSON.stringify(JSON.parse(value), null, 2); formInst.setFieldValue("defaultDataForDeployment", json); } catch { return; } }; const handleWebhookDataForNotificationBlur = () => { const value = formInst.getFieldValue("defaultDataForNotification"); try { const json = JSON.stringify(JSON.parse(value), null, 2); formInst.setFieldValue("defaultDataForNotification", json); } catch { return; } }; const handlePresetDataForDeploymentClick = () => { formInst.setFieldValue("defaultDataForDeployment", initFormModel().defaultDataForDeployment); }; const handlePresetDataForNotificationClick = (key: string) => { switch (key) { case "bark": formInst.setFieldValue("url", "https://api.day.app/push"); formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json\r\nAuthorization: Bearer "); formInst.setFieldValue( "defaultDataForNotification", JSON.stringify( { title: "${SUBJECT}", body: "${MESSAGE}", device_key: "", }, null, 2 ) ); break; case "gotify": formInst.setFieldValue("url", "https:///"); formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json\r\nAuthorization: Bearer "); formInst.setFieldValue( "defaultDataForNotification", JSON.stringify( { title: "${SUBJECT}", message: "${MESSAGE}", priority: 1, }, null, 2 ) ); break; case "ntfy": formInst.setFieldValue("url", "https:///"); formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json"); formInst.setFieldValue( "defaultDataForNotification", JSON.stringify( { topic: "", title: "${SUBJECT}", message: "${MESSAGE}", priority: 1, }, null, 2 ) ); break; case "pushover": formInst.setFieldValue("url", "https://api.pushover.net/1/messages.json"); formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json"); formInst.setFieldValue( "defaultDataForNotification", JSON.stringify( { token: "", user: "", title: "${SUBJECT}", message: "${MESSAGE}", }, null, 2 ) ); break; case "pushplus": formInst.setFieldValue("url", "https://www.pushplus.plus/send"); formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json"); formInst.setFieldValue( "defaultDataForNotification", JSON.stringify( { token: "", title: "${SUBJECT}", content: "${MESSAGE}", }, null, 2 ) ); break; case "serverchan": formInst.setFieldValue("url", "https://sctapi.ftqq.com/.send"); formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json"); formInst.setFieldValue( "defaultDataForNotification", JSON.stringify( { text: "${SUBJECT}", desp: "${MESSAGE}", }, null, 2 ) ); break; default: formInst.setFieldValue("method", "POST"); formInst.setFieldValue("headers", "Content-Type: application/json"); formInst.setFieldValue("defaultDataForNotification", initFormModel().defaultDataForNotification); break; } }; const handleFormChange = (_: unknown, values: z.infer) => { onValuesChange?.(values); }; return (