refactor(ui): MultipleSplitValueInput

This commit is contained in:
Fu Diwei 2025-05-25 23:05:08 +08:00
parent 71c093c042
commit b798b824db
8 changed files with 178 additions and 501 deletions

View File

@ -0,0 +1,108 @@
import { type ChangeEvent, useEffect } from "react";
import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
import { nanoid } from "@ant-design/pro-components";
import { useControllableValue } from "ahooks";
import { Button, Form, Input, type InputProps, Space } from "antd";
import { useAntdForm } from "@/hooks";
import ModalForm from "./ModalForm";
import MultipleInput from "./MultipleInput";
type SplitOptions = {
removeEmpty?: boolean;
trim?: boolean;
};
export type MultipleSplitValueInputProps = Omit<InputProps, "count" | "defaultValue" | "showCount" | "value" | "onChange"> & {
defaultValue?: string;
delimiter?: string;
maxCount?: number;
minCount?: number;
modalTitle?: string;
modalWidth?: number;
placeholderInModal?: string;
showSortButton?: boolean;
splitOptions?: SplitOptions;
value?: string[];
onChange?: (value: string) => void;
};
const DEFAULT_DELIMITER = ";";
const MultipleSplitValueInput = ({
className,
style,
delimiter = DEFAULT_DELIMITER,
disabled,
maxCount,
minCount,
modalTitle,
modalWidth = 480,
placeholder,
placeholderInModal,
showSortButton = true,
splitOptions = {},
onClear,
...props
}: MultipleSplitValueInputProps) => {
const [value, setValue] = useControllableValue<string>(props, {
valuePropName: "value",
defaultValuePropName: "defaultValue",
trigger: "onChange",
});
const { form: formInst, formProps } = useAntdForm({
name: "componentMultipleSplitValueInput_" + nanoid(),
initialValues: { value: value?.split(delimiter) },
onSubmit: (values) => {
const temp = values.value ?? [];
if (splitOptions.trim) {
temp.map((e) => e.trim());
}
if (splitOptions.removeEmpty) {
temp.filter((e) => !!e);
}
setValue(temp.join(delimiter));
},
});
useEffect(() => {
formInst.setFieldValue("value", value?.split(delimiter));
}, [delimiter, value]);
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
const handleClear = () => {
setValue("");
onClear?.();
};
return (
<Space.Compact className={className} style={{ width: "100%", ...style }}>
<Input {...props} disabled={disabled} placeholder={placeholder} value={value} onChange={handleChange} onClear={handleClear} />
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={modalTitle}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
validateTrigger="onSubmit"
width={modalWidth}
>
<Form.Item name="value" noStyle>
<MultipleInput minCount={minCount} maxCount={maxCount} placeholder={placeholderInModal ?? placeholder} showSortButton={showSortButton} />
</Form.Item>
</ModalForm>
</Space.Compact>
);
};
export default MultipleSplitValueInput;

View File

@ -1,12 +1,7 @@
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import {
FormOutlined as FormOutlinedIcon,
PlusOutlined as PlusOutlinedIcon,
QuestionCircleOutlined as QuestionCircleOutlinedIcon,
RightOutlined as RightOutlinedIcon,
} from "@ant-design/icons";
import { PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon, RightOutlined as RightOutlinedIcon } from "@ant-design/icons";
import { useControllableValue } from "ahooks";
import {
AutoComplete,
@ -19,7 +14,6 @@ import {
Input,
InputNumber,
Select,
Space,
Switch,
Tooltip,
Typography,
@ -29,8 +23,7 @@ import { z } from "zod";
import AccessEditModal from "@/components/access/AccessEditModal";
import AccessSelect from "@/components/access/AccessSelect";
import ModalForm from "@/components/ModalForm";
import MultipleInput from "@/components/MultipleInput";
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
import ACMEDns01ProviderSelect from "@/components/provider/ACMEDns01ProviderSelect";
import CAProviderSelect from "@/components/provider/CAProviderSelect";
import Show from "@/components/Show";
@ -152,11 +145,9 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
initialValues: initialValues ?? initFormModel(),
});
const fieldDomains = Form.useWatch<string>("domains", formInst);
const fieldProvider = Form.useWatch<string>("provider", { form: formInst, preserve: true });
const fieldProviderAccessId = Form.useWatch<string>("providerAccessId", formInst);
const fieldCAProvider = Form.useWatch<string>("caProvider", formInst);
const fieldNameservers = Form.useWatch<string>("nameservers", formInst);
const [showProvider, setShowProvider] = useState(false);
useEffect(() => {
@ -294,25 +285,17 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
<Form.Provider onFormChange={handleFormProviderChange}>
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
<Form.Item
name="domains"
label={t("workflow_node.apply.form.domains.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.domains.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="domains" noStyle rules={[formRule]}>
<Input placeholder={t("workflow_node.apply.form.domains.placeholder")} />
</Form.Item>
<DomainsModalInput
value={fieldDomains}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(v) => {
formInst.setFieldValue("domains", v);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.apply.form.domains.multiple_input_modal.title")}
placeholder={t("workflow_node.apply.form.domains.placeholder")}
placeholderInModal={t("workflow_node.apply.form.domains.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
<Form.Item
@ -497,36 +480,17 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
<Form.Item
name="nameservers"
label={t("workflow_node.apply.form.nameservers.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.apply.form.nameservers.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="nameservers" noStyle rules={[formRule]}>
<Input
allowClear
disabled={disabled}
value={fieldNameservers}
placeholder={t("workflow_node.apply.form.nameservers.placeholder")}
onChange={(e) => {
formInst.setFieldValue("nameservers", e.target.value);
}}
onClear={() => {
formInst.setFieldValue("nameservers", undefined);
}}
/>
</Form.Item>
<NameserversModalInput
value={fieldNameservers}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(value) => {
formInst.setFieldValue("nameservers", value);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.apply.form.nameservers.multiple_input_modal.title")}
placeholder={t("workflow_node.apply.form.nameservers.placeholder")}
placeholderInModal={t("workflow_node.apply.form.nameservers.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
<Form.Item
@ -678,84 +642,4 @@ const EmailInput = memo(
}
);
const DomainsModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
domains: z.array(z.string()).refine((v) => {
return v.every((e) => !e?.trim() || validDomainName(e.trim(), { allowWildcard: true }));
}, t("common.errmsg.domain_invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeApplyConfigFormDomainsModalInput",
initialValues: { domains: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.domains
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.apply.form.domains.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="domains" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.apply.form.domains.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
const NameserversModalInput = memo(({ trigger, value, onChange }: { trigger?: React.ReactNode; value?: string; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
nameservers: z.array(z.string()).refine((v) => {
return v.every((e) => !e?.trim() || validIPv4Address(e) || validIPv6Address(e) || validDomainName(e));
}, t("common.errmsg.domain_invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeApplyConfigFormNameserversModalInput",
initialValues: { nameservers: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.nameservers
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.apply.form.nameservers.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="nameservers" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.apply.form.nameservers.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
export default memo(ApplyNodeConfigForm);

View File

@ -1,13 +1,9 @@
import { memo } from "react";
import { useTranslation } from "react-i18next";
import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
import { Alert, Button, Form, type FormInstance, Input, Space } from "antd";
import { Alert, Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import ModalForm from "@/components/ModalForm";
import MultipleInput from "@/components/MultipleInput";
import { useAntdForm } from "@/hooks";
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
type DeployNodeConfigFormAliyunCASDeployConfigFieldValues = Nullish<{
region: string;
@ -61,9 +57,6 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({
});
const formRule = createSchemaFieldRule(formSchema);
const fieldResourceIds = Form.useWatch<string>("resourceIds", formInst);
const fieldContactIds = Form.useWatch<string>("contactIds", formInst);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
};
@ -87,69 +80,31 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({
</Form.Item>
<Form.Item
name="resourceIds"
label={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="resourceIds" noStyle rules={[formRule]}>
<Input
allowClear
disabled={disabled}
value={fieldResourceIds}
placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.placeholder")}
onChange={(e) => {
formInst.setFieldValue("resourceIds", e.target.value);
}}
onClear={() => {
formInst.setFieldValue("resourceIds", "");
}}
/>
</Form.Item>
<ResourceIdsModalInput
value={fieldResourceIds}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(value) => {
formInst.setFieldValue("resourceIds", value);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.multiple_input_modal.title")}
placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.placeholder")}
placeholderInModal={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
<Form.Item
name="contactIds"
label={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="contactIds" noStyle rules={[formRule]}>
<Input
allowClear
disabled={disabled}
value={fieldContactIds}
placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.placeholder")}
onChange={(e) => {
formInst.setFieldValue("contactIds", e.target.value);
}}
onClear={() => {
formInst.setFieldValue("contactIds", "");
}}
/>
</Form.Item>
<ContactIdsModalInput
value={fieldContactIds}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(value) => {
formInst.setFieldValue("contactIds", value);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.title")}
placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.placeholder")}
placeholderInModal={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
<Form.Item>
@ -159,84 +114,4 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({
);
};
const ResourceIdsModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
resourceIds: z.array(z.string()).refine((v) => {
return v.every((e) => !e?.trim() || /^[1-9]\d*$/.test(e));
}, t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.errmsg.invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeDeployConfigFormAliyunCASResourceIdsModalInput",
initialValues: { resourceIds: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.resourceIds
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="resourceIds" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_resource_ids.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
const ContactIdsModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
contactIds: z.array(z.string()).refine((v) => {
return v.every((e) => !e?.trim() || /^[1-9]\d*$/.test(e));
}, t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.errmsg.invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeDeployConfigFormAliyunCASDeploymentJobContactIdsModalInput",
initialValues: { contactIds: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.contactIds
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="contactIds" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.deploy.form.aliyun_cas_deploy_contact_ids.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
export default DeployNodeConfigFormAliyunCASDeployConfig;

View File

@ -1,14 +1,10 @@
import { memo } from "react";
import { useTranslation } from "react-i18next";
import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
import { Button, Form, type FormInstance, Input, Select, Space } from "antd";
import { Form, type FormInstance, Input, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import ModalForm from "@/components/ModalForm";
import MultipleInput from "@/components/MultipleInput";
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
import Show from "@/components/Show";
import { useAntdForm } from "@/hooks";
type DeployNodeConfigFormBaotaPanelSiteConfigFieldValues = Nullish<{
siteType: string;
@ -71,7 +67,6 @@ const DeployNodeConfigFormBaotaPanelSiteConfig = ({
const formRule = createSchemaFieldRule(formSchema);
const fieldSiteType = Form.useWatch<string>("siteType", formInst);
const fieldSiteNames = Form.useWatch<string>("siteNames", formInst);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
@ -110,80 +105,21 @@ const DeployNodeConfigFormBaotaPanelSiteConfig = ({
<Show when={fieldSiteType === SITE_TYPE_OTHER}>
<Form.Item
name="siteNames"
label={t("workflow_node.deploy.form.baotapanel_site_names.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.baotapanel_site_names.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="siteNames" noStyle rules={[formRule]}>
<Input
allowClear
disabled={disabled}
value={fieldSiteNames}
placeholder={t("workflow_node.deploy.form.baotapanel_site_names.placeholder")}
onChange={(e) => {
formInst.setFieldValue("siteNames", e.target.value);
}}
onClear={() => {
formInst.setFieldValue("siteNames", "");
}}
/>
</Form.Item>
<SiteNamesModalInput
value={fieldSiteNames}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(value) => {
formInst.setFieldValue("siteNames", value);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title")}
placeholder={t("workflow_node.deploy.form.baotapanel_site_names.placeholder")}
placeholderInModal={t("workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
</Show>
</Form>
);
};
const SiteNamesModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
siteNames: z.array(z.string()).refine((v) => {
return v.every((e) => !!e?.trim());
}, t("workflow_node.deploy.form.baotapanel_site_names.errmsg.invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeDeployConfigFormBaotaPanelSiteNamesModalInput",
initialValues: { siteNames: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.siteNames
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="siteNames" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.deploy.form.baotapanel_site_names.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
export default DeployNodeConfigFormBaotaPanelSiteConfig;

View File

@ -1,13 +1,9 @@
import { memo } from "react";
import { useTranslation } from "react-i18next";
import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
import { Alert, AutoComplete, Button, Form, type FormInstance, Input, Space } from "antd";
import { Alert, AutoComplete, Form, type FormInstance, Input } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import ModalForm from "@/components/ModalForm";
import MultipleInput from "@/components/MultipleInput";
import { useAntdForm } from "@/hooks";
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
type DeployNodeConfigFormTencentCloudSSLDeployConfigFieldValues = Nullish<{
region: string;
@ -56,8 +52,6 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({
});
const formRule = createSchemaFieldRule(formSchema);
const fieldResourceIds = Form.useWatch<string>("resourceIds", formInst);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
};
@ -94,36 +88,17 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({
</Form.Item>
<Form.Item
name="resourceIds"
label={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="resourceIds" noStyle rules={[formRule]}>
<Input
allowClear
disabled={disabled}
value={fieldResourceIds}
placeholder={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.placeholder")}
onChange={(e) => {
formInst.setFieldValue("resourceIds", e.target.value);
}}
onClear={() => {
formInst.setFieldValue("resourceIds", "");
}}
/>
</Form.Item>
<ResourceIdsModalInput
value={fieldResourceIds}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(value) => {
formInst.setFieldValue("resourceIds", value);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.title")}
placeholder={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.placeholder")}
placeholderInModal={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
<Form.Item>
@ -133,44 +108,4 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({
);
};
const ResourceIdsModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
resourceIds: z.array(z.string()).refine((v) => {
return v.every((e) => !e?.trim() || /^[A-Za-z0-9*._-|]+$/.test(e));
}, t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.errmsg.invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeDeployConfigFormTencentCloudSSLDeployResourceIdsModalInput",
initialValues: { resourceIds: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.resourceIds
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="resourceIds" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.deploy.form.tencentcloud_ssl_deploy_resource_ids.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
export default DeployNodeConfigFormTencentCloudSSLDeployConfig;

View File

@ -1,13 +1,9 @@
import { memo } from "react";
import { useTranslation } from "react-i18next";
import { FormOutlined as FormOutlinedIcon } from "@ant-design/icons";
import { Button, Form, type FormInstance, Input, Space } from "antd";
import { Form, type FormInstance } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { z } from "zod";
import ModalForm from "@/components/ModalForm";
import MultipleInput from "@/components/MultipleInput";
import { useAntdForm } from "@/hooks";
import MultipleSplitValueInput from "@/components/MultipleSplitValueInput";
import { validDomainName } from "@/utils/validators";
type DeployNodeConfigFormWangsuCDNConfigFieldValues = Nullish<{
@ -52,8 +48,6 @@ const DeployNodeConfigFormWangsuCDNConfig = ({
});
const formRule = createSchemaFieldRule(formSchema);
const fieldDomains = Form.useWatch<string>("domains", formInst);
const handleFormChange = (_: unknown, values: z.infer<typeof formSchema>) => {
onValuesChange?.(values);
};
@ -68,79 +62,20 @@ const DeployNodeConfigFormWangsuCDNConfig = ({
onValuesChange={handleFormChange}
>
<Form.Item
name="domains"
label={t("workflow_node.deploy.form.wangsu_cdn_domains.label")}
rules={[formRule]}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.wangsu_cdn_domains.tooltip") }}></span>}
>
<Space.Compact style={{ width: "100%" }}>
<Form.Item name="domains" noStyle rules={[formRule]}>
<Input
allowClear
disabled={disabled}
value={fieldDomains}
placeholder={t("workflow_node.deploy.form.wangsu_cdn_domains.placeholder")}
onChange={(e) => {
formInst.setFieldValue("domains", e.target.value);
}}
onClear={() => {
formInst.setFieldValue("domains", "");
}}
/>
</Form.Item>
<SiteNamesModalInput
value={fieldDomains}
trigger={
<Button disabled={disabled}>
<FormOutlinedIcon />
</Button>
}
onChange={(value) => {
formInst.setFieldValue("domains", value);
}}
/>
</Space.Compact>
<MultipleSplitValueInput
modalTitle={t("workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.title")}
placeholder={t("workflow_node.deploy.form.wangsu_cdn_domains.placeholder")}
placeholderInModal={t("workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.placeholder")}
splitOptions={{ trim: true, removeEmpty: true }}
/>
</Form.Item>
</Form>
);
};
const SiteNamesModalInput = memo(({ value, trigger, onChange }: { value?: string; trigger?: React.ReactNode; onChange?: (value: string) => void }) => {
const { t } = useTranslation();
const formSchema = z.object({
domains: z.array(z.string()).refine((v) => {
return v.every((e) => validDomainName(e));
}, t("workflow_node.deploy.form.wangsu_cdn_domains.errmsg.invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const { form: formInst, formProps } = useAntdForm({
name: "workflowNodeDeployConfigFormWangsuCDNNamesModalInput",
initialValues: { domains: value?.split(MULTIPLE_INPUT_DELIMITER) },
onSubmit: (values) => {
onChange?.(
values.domains
.map((e) => e.trim())
.filter((e) => !!e)
.join(MULTIPLE_INPUT_DELIMITER)
);
},
});
return (
<ModalForm
{...formProps}
layout="vertical"
form={formInst}
modalProps={{ destroyOnHidden: true }}
title={t("workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
>
<Form.Item name="domains" rules={[formRule]}>
<MultipleInput placeholder={t("workflow_node.deploy.form.wangsu_cdn_domains.multiple_input_modal.placeholder")} />
</Form.Item>
</ModalForm>
);
});
export default DeployNodeConfigFormWangsuCDNConfig;

View File

@ -1,9 +1,11 @@
{
"workflow_node.action.configure_node": "Configure node",
"workflow_node.action.add_node": "Add node",
"workflow_node.action.duplicate_node": "Duplicate node",
"workflow_node.action.rename_node": "Rename node",
"workflow_node.action.remove_node": "Delete node",
"workflow_node.action.add_branch": "Add branch",
"workflow_node.action.duplicate_branch": "Duplicate branch",
"workflow_node.action.rename_branch": "Rename branch",
"workflow_node.action.remove_branch": "Delete branch",

View File

@ -1,9 +1,11 @@
{
"workflow_node.action.configure_node": "配置节点",
"workflow_node.branch.add_node": "添加节点",
"workflow_node.action.duplicate_node": "复制节点",
"workflow_node.action.rename_node": "重命名",
"workflow_node.action.remove_node": "删除节点",
"workflow_node.action.add_branch": "添加并行分支",
"workflow_node.action.duplicate_branch": "复制分支",
"workflow_node.action.rename_branch": "重命名",
"workflow_node.action.remove_branch": "删除分支",