import { memo, useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useControllableValue } from "ahooks"; import { AutoComplete, Button, Divider, Form, Input, InputNumber, Select, Switch, Tooltip, Typography, type AutoCompleteProps } from "antd"; import { createSchemaFieldRule } from "antd-zod"; import { PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons"; import z from "zod"; import AccessEditModal from "@/components/access/AccessEditModal"; import AccessSelect from "@/components/access/AccessSelect"; import { usePanel } from "../PanelProvider"; import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { ACCESS_PROVIDER_USAGES, accessProvidersMap } from "@/domain/access"; import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow"; import { useContactStore } from "@/stores/contact"; import { useWorkflowStore } from "@/stores/workflow"; import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators"; export type ApplyNodeFormProps = { data: WorkflowNode; }; const initFormModel = (): WorkflowNodeConfig => { return { domain: "", keyAlgorithm: "RSA2048", nameservers: "", propagationTimeout: 60, disableFollowCNAME: true, }; }; const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => { const { t } = useTranslation(); const { addEmail } = useContactStore(); const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"])); const { hidePanel } = usePanel(); const formSchema = z.object({ domain: z.string({ message: t("workflow.nodes.apply.form.domain.placeholder") }).refine( (str) => { return String(str) .split(";") .every((e) => validDomainName(e, true)); }, { message: t("common.errmsg.domain_invalid") } ), email: z.string({ message: t("workflow.nodes.apply.form.email.placeholder") }).email("common.errmsg.email_invalid"), access: z.string({ message: t("workflow.nodes.apply.form.access.placeholder") }).min(1, t("workflow.nodes.apply.form.access.placeholder")), keyAlgorithm: z.string().nullish(), nameservers: z .string() .refine( (str) => { if (!str) return true; return String(str) .split(";") .every((e) => validDomainName(e) || validIPv4Address(e) || validIPv6Address(e)); }, { message: t("common.errmsg.host_invalid") } ) .nullish(), timeout: z.number().gte(1, t("workflow.nodes.apply.form.propagation_timeout.placeholder")).nullish(), disableFollowCNAME: z.boolean().nullish(), }); const formRule = createSchemaFieldRule(formSchema); const { form: formInst, formPending, formProps, } = useAntdForm>({ initialValues: data?.config ?? initFormModel(), onSubmit: async (values) => { await updateNode({ ...data, config: { ...values }, validated: true }); await addEmail(values.email); hidePanel(); }, }); return (
} > } > { const provider = accessProvidersMap.get(record.configType); return ACCESS_PROVIDER_USAGES.ALL === provider?.usage || ACCESS_PROVIDER_USAGES.APPLY === provider?.usage; }} /> {t("workflow.nodes.apply.form.advanced_settings.label")} } > } >
); }; const ContactEmailSelect = ({ className, style, disabled, placeholder, ...props }: { className?: string; style?: React.CSSProperties; defaultValue?: string; disabled?: boolean; placeholder?: string; value?: string; onChange?: (value: string) => void; }) => { const { emails, fetchEmails } = useContactStore(); const emailsToOptions = useCallback(() => emails.map((email) => ({ label: email, value: email })), [emails]); useEffect(() => { fetchEmails(); }, [fetchEmails]); const [value, setValue] = useControllableValue(props, { valuePropName: "value", defaultValuePropName: "defaultValue", trigger: "onChange", }); const [options, setOptions] = useState([]); useEffect(() => { setOptions(emailsToOptions()); }, [emails, emailsToOptions]); const handleChange = (value: string) => { setValue(value); }; const handleSearch = (text: string) => { const temp = emailsToOptions(); if (text) { if (temp.every((option) => option.label !== text)) { temp.unshift({ label: text, value: text }); } } setOptions(temp); }; return ( ); }; export default memo(ApplyNodeForm);