,
+ icon:
,
danger: true,
onClick: () => {
removeBranch(branchId ?? "", branchIndex ?? 0);
@@ -30,7 +31,7 @@ const ConditionNode = ({ data, branchId, branchIndex }: NodeProps) => {
trigger={["click"]}
>
-
+
diff --git a/ui/src/components/workflow/DeployForm.tsx b/ui/src/components/workflow/DeployForm.tsx
index ca7846ee..32b5bf05 100644
--- a/ui/src/components/workflow/DeployForm.tsx
+++ b/ui/src/components/workflow/DeployForm.tsx
@@ -1,31 +1,33 @@
-import { WorkflowNode } from "@/domain/workflow";
import { memo } from "react";
-import DeployToAliyunOSS from "./DeployToAliyunOss";
+
+import { type WorkflowNode } from "@/domain/workflow";
import DeployToAliyunALB from "./DeployToAliyunALB";
import DeployToAliyunCDN from "./DeployToAliyunCDN";
import DeployToAliyunCLB from "./DeployToAliyunCLB";
import DeployToAliyunNLB from "./DeployToAliyunNLB";
+import DeployToAliyunOSS from "./DeployToAliyunOss";
import DeployToBaiduCloudCDN from "./DeployToBaiduCloudCDN";
+import DeployToBytePlusCDN from "./DeployToByteplusCDN";
import DeployToDogeCloudCDN from "./DeployToDogeCloudCDN";
import DeployToHuaweiCloudCDN from "./DeployToHuaweiCloudCDN";
import DeployToHuaweiCloudELB from "./DeployToHuaweiCloudELB";
import DeployToKubernetesSecret from "./DeployToKubernetesSecret";
+import DeployToLocal from "./DeployToLocal";
import DeployToQiniuCDN from "./DeployToQiniuCDN";
-import DeployToWebhook from "./DeployToWebhook";
+import DeployToSSH from "./DeployToSSH";
import DeployToTencentCDN from "./DeployToTencentCDN";
import DeployToTencentCLB from "./DeployToTencentCLB";
import DeployToTencentCOS from "./DeployToTencentCOS";
-import DeployToTencentTEO from "./DeployToTencentTEO";
-import DeployToSSH from "./DeployToSSH";
-import DeployToLocal from "./DeployToLocal";
-import DeployToByteplusCDN from "./DeployToByteplusCDN";
-import DeployToVolcengineCDN from "./DeployToVolcengineCDN";
-import DeployToVolcengineLive from "./DeployToVolcengineLive";
+import DeployToTencentEO from "./DeployToTencentTEO";
+import DeployToVolcEngineCDN from "./DeployToVolcengineCDN";
+import DeployToVolcEngineLive from "./DeployToVolcengineLive";
+import DeployToWebhook from "./DeployToWebhook";
export type DeployFormProps = {
data: WorkflowNode;
defaultProivder?: string;
};
+
const DeployForm = ({ data, defaultProivder }: DeployFormProps) => {
return
{getForm(data, defaultProivder)}
;
};
@@ -68,17 +70,17 @@ const getForm = (data: WorkflowNode, defaultProivder?: string) => {
case "tencentcloud-cos":
return
;
case "tencentcloud-eo":
- return
;
+ return
;
case "ssh":
return
;
case "local":
return
;
case "byteplus-cdn":
- return
;
+ return
;
case "volcengine-cdn":
- return
;
+ return
;
case "volcengine-live":
- return
;
+ return
;
default:
return <>>;
}
diff --git a/ui/src/components/workflow/DeployPanelBody.tsx b/ui/src/components/workflow/DeployPanelBody.tsx
index e428c2c6..084302ec 100644
--- a/ui/src/components/workflow/DeployPanelBody.tsx
+++ b/ui/src/components/workflow/DeployPanelBody.tsx
@@ -1,13 +1,15 @@
-import { WorkflowNode } from "@/domain/workflow";
import { memo, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
-import Show from "../Show";
-import DeployForm from "./DeployForm";
-import { DeployTarget, deployTargets } from "@/domain/domain";
+
+import Show from "@/components/Show";
+import DeployNodeForm from "./node/DeployNodeForm";
+import { deployProvidersMap } from "@/domain/provider";
+import { type WorkflowNode } from "@/domain/workflow";
type DeployPanelBodyProps = {
data: WorkflowNode;
};
+
const DeployPanelBody = ({ data }: DeployPanelBodyProps) => {
const { t } = useTranslation();
@@ -21,33 +23,22 @@ const DeployPanelBody = ({ data }: DeployPanelBodyProps) => {
return (
<>
{/* 默认展示服务商列表 */}
-
}>
+
}>
选择服务商
- {deployTargets
- .reduce((acc: DeployTarget[][], provider, index) => {
- if (index % 2 === 0) {
- acc.push([provider]);
- } else {
- acc[acc.length - 1].push(provider);
- }
- return acc;
- }, [])
- .map((providerRow, rowIndex) => (
-
- {providerRow.map((provider, index) => (
-
{
- setProviderType(provider.type);
- }}
- >
-
-
{t(provider.name)}
-
- ))}
+ {Array.from(deployProvidersMap.values()).map((provider, index) => {
+ return (
+
{
+ setProviderType(provider.type);
+ }}
+ >
+
+
{t(provider.name)}
- ))}
+ );
+ })}
>
);
diff --git a/ui/src/components/workflow/Node.tsx b/ui/src/components/workflow/Node.tsx
index e749ab1d..7952a351 100644
--- a/ui/src/components/workflow/Node.tsx
+++ b/ui/src/components/workflow/Node.tsx
@@ -1,15 +1,16 @@
-import { WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
-import AddNode from "./AddNode";
-import { useWorkflowStore } from "@/stores/workflow";
-import { useZustandShallowSelector } from "@/hooks";
+import { useTranslation } from "react-i18next";
import { Dropdown } from "antd";
-import { Ellipsis, Trash2 } from "lucide-react";
+import { DeleteOutlined as DeleteOutlinedIcon, EllipsisOutlined as EllipsisOutlinedIcon } from "@ant-design/icons";
+
+import Show from "@/components/Show";
+import AddNode from "./AddNode";
import { usePanel } from "./PanelProvider";
import PanelBody from "./PanelBody";
-import { useTranslation } from "react-i18next";
-import Show from "../Show";
-import { deployTargetsMap } from "@/domain/domain";
+import { useZustandShallowSelector } from "@/hooks";
+import { deployProvidersMap } from "@/domain/provider";
import { notifyChannelsMap } from "@/domain/settings";
+import { type WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
+import { useWorkflowStore } from "@/stores/workflow";
type NodeProps = {
data: WorkflowNode;
@@ -56,7 +57,7 @@ const Node = ({ data }: NodeProps) => {
case WorkflowNodeType.Apply:
return
{data.config?.domain as string}
;
case WorkflowNodeType.Deploy: {
- const provider = deployTargetsMap.get(data.config?.providerType as string);
+ const provider = deployProvidersMap.get(data.config?.providerType as string);
return (
@@ -90,7 +91,7 @@ const Node = ({ data }: NodeProps) => {
{
key: "delete",
label: t(`${i18nPrefix}.delete.label`),
- icon:
,
+ icon:
,
danger: true,
onClick: () => {
removeNode(data.id);
@@ -101,7 +102,7 @@ const Node = ({ data }: NodeProps) => {
trigger={["click"]}
>
-
+
>
diff --git a/ui/src/components/workflow/node/ApplyNodeForm.tsx b/ui/src/components/workflow/node/ApplyNodeForm.tsx
index 88052c5c..bf357b93 100644
--- a/ui/src/components/workflow/node/ApplyNodeForm.tsx
+++ b/ui/src/components/workflow/node/ApplyNodeForm.tsx
@@ -4,6 +4,7 @@ import { useControllableValue } from "ahooks";
import { AutoComplete, Button, Divider, Form, Input, Select, Space, Switch, Tooltip, Typography, type AutoCompleteProps } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { FormOutlined as FormOutlinedIcon, PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
+import { produce } from "immer";
import z from "zod";
import AccessEditModal from "@/components/access/AccessEditModal";
@@ -12,7 +13,8 @@ import ModalForm from "@/components/core/ModalForm";
import MultipleInput from "@/components/core/MultipleInput";
import { usePanel } from "../PanelProvider";
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
-import { ACCESS_USAGES, accessProvidersMap } from "@/domain/access";
+import { ACCESS_USAGES } from "@/domain/access";
+import { accessProvidersMap } from "@/domain/provider";
import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow";
import { useContactStore } from "@/stores/contact";
import { useWorkflowStore } from "@/stores/workflow";
@@ -42,33 +44,27 @@ const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
const { hidePanel } = usePanel();
const formSchema = z.object({
- domain: z.string({ message: t("workflow.nodes.apply.form.domains.placeholder") }).refine(
- (v) => {
- return String(v)
- .split(MULTIPLE_INPUT_DELIMITER)
- .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")),
+ domain: z.string({ message: t("workflow_node.apply.form.domains.placeholder") }).refine((v) => {
+ return String(v)
+ .split(MULTIPLE_INPUT_DELIMITER)
+ .every((e) => validDomainName(e, true));
+ }, t("common.errmsg.domain_invalid")),
+ email: z.string({ message: t("workflow_node.apply.form.email.placeholder") }).email("common.errmsg.email_invalid"),
+ access: z.string({ message: t("workflow_node.apply.form.access.placeholder") }).min(1, t("workflow_node.apply.form.access.placeholder")),
keyAlgorithm: z.string().nullish(),
nameservers: z
.string()
- .refine(
- (v) => {
- if (!v) return true;
- return String(v)
- .split(MULTIPLE_INPUT_DELIMITER)
- .every((e) => validIPv4Address(e) || validIPv6Address(e) || validDomainName(e));
- },
- { message: t("common.errmsg.host_invalid") }
- )
- .nullish(),
+ .nullish()
+ .refine((v) => {
+ if (!v) return true;
+ return String(v)
+ .split(MULTIPLE_INPUT_DELIMITER)
+ .every((e) => validIPv4Address(e) || validIPv6Address(e) || validDomainName(e));
+ }, t("common.errmsg.host_invalid")),
propagationTimeout: z
.union([
- z.number().int().gte(1, t("workflow.nodes.apply.form.propagation_timeout.placeholder")),
- z.string().refine((v) => !v || (parseInt(v) === +v && +v > 0), { message: t("workflow.nodes.apply.form.propagation_timeout.placeholder") }),
+ z.number().int().gte(1, t("workflow_node.apply.form.propagation_timeout.placeholder")),
+ z.string().refine((v) => !v || /^[1-9]\d*$/.test(v), t("workflow_node.apply.form.propagation_timeout.placeholder")),
])
.nullish(),
disableFollowCNAME: z.boolean().nullish(),
@@ -81,8 +77,14 @@ const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
} = useAntdForm
>({
initialValues: data?.config ?? initFormModel(),
onSubmit: async (values) => {
- await updateNode({ ...data, config: { ...values }, validated: true });
+ await formInst.validateFields();
await addEmail(values.email);
+ await updateNode(
+ produce(data, (draft) => {
+ draft.config = { ...values };
+ draft.validated = true;
+ })
+ );
hidePanel();
},
});
@@ -106,15 +108,15 @@ const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
}
+ tooltip={ }
>
{
}
+ tooltip={ }
>
-
+
-
+
-
{t("workflow.nodes.apply.form.access.label")}
-
+ {t("workflow_node.apply.form.access.label")}
+
@@ -158,7 +160,7 @@ const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
trigger={
- {t("workflow.nodes.apply.form.access.button")}
+ {t("workflow_node.apply.form.access.button")}
}
onSubmit={(record) => {
@@ -173,7 +175,7 @@ const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
{
const provider = accessProvidersMap.get(record.configType);
return ACCESS_USAGES.ALL === provider?.usage || ACCESS_USAGES.APPLY === provider?.usage;
@@ -183,33 +185,33 @@ const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
-
- {t("workflow.nodes.apply.form.advanced_settings.label")}
+
+ {t("workflow_node.apply.form.advanced_config.label")}
-
+
({
label: e,
value: e,
}))}
- placeholder={t("workflow.nodes.apply.form.key_algorithm.placeholder")}
+ placeholder={t("workflow_node.apply.form.key_algorithm.placeholder")}
/>
}
+ tooltip={ }
>
{
}
+ tooltip={ }
>
}
+ tooltip={ }
>
@@ -339,12 +341,9 @@ const FormFieldDomainsModalForm = ({
const { t } = useTranslation();
const formSchema = z.object({
- domains: z.array(z.string()).refine(
- (v) => {
- return v.every((e) => !e?.trim() || validDomainName(e.trim(), true));
- },
- { message: t("common.errmsg.domain_invalid") }
- ),
+ domains: z.array(z.string()).refine((v) => {
+ return v.every((e) => !e?.trim() || validDomainName(e.trim(), true));
+ }, t("common.errmsg.domain_invalid")),
});
const formRule = createSchemaFieldRule(formSchema);
const [formInst] = Form.useForm>();
@@ -372,14 +371,14 @@ const FormFieldDomainsModalForm = ({
form={formInst}
initialValues={model}
modalProps={{ destroyOnClose: true }}
- title={t("workflow.nodes.apply.form.domains.multiple_input_modal.title")}
+ title={t("workflow_node.apply.form.domains.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
onFinish={handleFinish}
>
-
+
);
@@ -389,12 +388,9 @@ const FormFieldNameserversModalForm = ({ data, trigger, onFinish }: { data: stri
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));
- },
- { message: t("common.errmsg.domain_invalid") }
- ),
+ 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 [formInst] = Form.useForm>();
@@ -422,14 +418,14 @@ const FormFieldNameserversModalForm = ({ data, trigger, onFinish }: { data: stri
form={formInst}
initialValues={model}
modalProps={{ destroyOnClose: true }}
- title={t("workflow.nodes.apply.form.nameservers.multiple_input_modal.title")}
+ title={t("workflow_node.apply.form.nameservers.multiple_input_modal.title")}
trigger={trigger}
validateTrigger="onSubmit"
width={480}
onFinish={handleFinish}
>
-
+
);
diff --git a/ui/src/components/workflow/node/DeployNodeForm.tsx b/ui/src/components/workflow/node/DeployNodeForm.tsx
new file mode 100644
index 00000000..c75946f9
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeForm.tsx
@@ -0,0 +1,282 @@
+import { memo, useEffect, useMemo, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { Avatar, Button, Divider, Form, Select, Space, Tooltip, Typography } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
+import { produce } from "immer";
+import z from "zod";
+
+import AccessEditModal from "@/components/access/AccessEditModal";
+import AccessSelect from "@/components/access/AccessSelect";
+import { usePanel } from "../PanelProvider";
+import DeployNodeFormAliyunALBFields from "./DeployNodeFormAliyunALBFields";
+import DeployNodeFormAliyunCLBFields from "./DeployNodeFormAliyunCLBFields";
+import DeployNodeFormAliyunCDNFields from "./DeployNodeFormAliyunCDNFields";
+import DeployNodeFormAliyunDCDNFields from "./DeployNodeFormAliyunDCDNFields";
+import DeployNodeFormAliyunNLBFields from "./DeployNodeFormAliyunNLBFields";
+import DeployNodeFormAliyunOSSFields from "./DeployNodeFormAliyunOSSFields";
+import DeployNodeFormBaiduCloudCDNFields from "./DeployNodeFormBaiduCloudCDNFields";
+import DeployNodeFormBytePlusCDNFields from "./DeployNodeFormBytePlusCDNFields";
+import DeployNodeFormDogeCloudCDNFields from "./DeployNodeFormDogeCloudCDNFields";
+import DeployNodeFormHuaweiCloudCDNFields from "./DeployNodeFormHuaweiCloudCDNFields";
+import DeployNodeFormHuaweiCloudELBFields from "./DeployNodeFormHuaweiCloudELBFields";
+import DeployNodeFormKubernetesSecretFields from "./DeployNodeFormKubernetesSecretFields";
+import DeployNodeFormLocalFields from "./DeployNodeFormLocalFields";
+import DeployNodeFormQiniuCDNFields from "./DeployNodeFormQiniuCDNFields";
+import DeployNodeFormSSHFields from "./DeployNodeFormSSHFields";
+import DeployNodeFormTencentCloudCDNFields from "./DeployNodeFormTencentCloudCDNFields";
+import DeployNodeFormTencentCloudCLBFields from "./DeployNodeFormTencentCloudCLBFields";
+import DeployNodeFormTencentCloudCOSFields from "./DeployNodeFormTencentCloudCOSFields";
+import DeployNodeFormTencentCloudECDNFields from "./DeployNodeFormTencentCloudECDNFields";
+import DeployNodeFormTencentCloudEOFields from "./DeployNodeFormTencentCloudEOFields";
+import DeployNodeFormVolcEngineCDNFields from "./DeployNodeFormVolcEngineCDNFields";
+import DeployNodeFormVolcEngineLiveFields from "./DeployNodeFormVolcEngineLiveFields";
+import DeployNodeFormWebhookFields from "./DeployNodeFormWebhookFields";
+import { useAntdForm, useZustandShallowSelector } from "@/hooks";
+import { ACCESS_USAGES } from "@/domain/access";
+import { accessProvidersMap, deployProvidersMap } from "@/domain/provider";
+import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow";
+import { useWorkflowStore } from "@/stores/workflow";
+
+export type DeployFormProps = {
+ data: WorkflowNode;
+ defaultProivderType?: string;
+};
+
+const initFormModel = (): WorkflowNodeConfig => {
+ return {};
+};
+
+const DeployNodeForm = ({ data, defaultProivderType }: DeployFormProps) => {
+ const { t } = useTranslation();
+
+ const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
+ const { hidePanel } = usePanel();
+
+ const formSchema = z.object({
+ providerType: z
+ .string({ message: t("workflow_node.deploy.form.provider_type.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.provider_type.placeholder")),
+ access: z
+ .string({ message: t("workflow_node.deploy.form.provider_access.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.provider_access.placeholder")),
+ certificate: z.string({ message: t("workflow_node.deploy.form.certificate.placeholder") }).nonempty(t("workflow_node.deploy.form.certificate.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const {
+ form: formInst,
+ formPending,
+ formProps,
+ } = useAntdForm>({
+ initialValues: data?.config ?? initFormModel(),
+ onSubmit: async (values) => {
+ await formInst.validateFields();
+ await updateNode(
+ produce(data, (draft) => {
+ draft.config = { ...values };
+ draft.validated = true;
+ })
+ );
+ hidePanel();
+ },
+ });
+
+ const [previousOutput, setPreviousOutput] = useState([]);
+ useEffect(() => {
+ const rs = getWorkflowOuptutBeforeId(data.id, "certificate");
+ setPreviousOutput(rs);
+ }, [data, getWorkflowOuptutBeforeId]);
+
+ const fieldProviderType = Form.useWatch("providerType", formInst);
+ // const fieldAccess = Form.useWatch("access", formInst);
+
+ const formFieldsComponent = useMemo(() => {
+ /*
+ 注意:如果追加新的子组件,请保持以 ASCII 排序。
+ NOTICE: If you add new child component, please keep ASCII order.
+ */
+ switch (fieldProviderType) {
+ case "aliyun-alb":
+ return ;
+ case "aliyun-clb":
+ return ;
+ case "aliyun-cdn":
+ return ;
+ case "aliyun-dcdn":
+ return ;
+ case "aliyun-nlb":
+ return ;
+ case "aliyun-oss":
+ return ;
+ case "baiducloud-cdn":
+ return ;
+ case "byteplus-cdn":
+ return ;
+ case "dogecloud-cdn":
+ return ;
+ case "huaweicloud-cdn":
+ return ;
+ case "huaweicloud-elb":
+ return ;
+ case "k8s-secret":
+ return ;
+ case "local":
+ return ;
+ case "qiniu-cdn":
+ return ;
+ case "ssh":
+ return ;
+ case "tencentcloud-cdn":
+ return ;
+ case "tencentcloud-clb":
+ return ;
+ case "tencentcloud-cos":
+ return ;
+ case "tencentcloud-ecdn":
+ return ;
+ case "tencentcloud-eo":
+ return ;
+ case "volcengine-cdn":
+ return ;
+ case "volcengine-live":
+ return ;
+ case "webhook":
+ return ;
+ }
+ }, [fieldProviderType]);
+
+ const handleProviderTypeSelect = (value: string) => {
+ if (fieldProviderType === value) return;
+
+ // 切换部署目标时重置表单,避免其他部署目标的配置字段影响当前部署目标
+ if (data.config?.providerType === value) {
+ formInst.resetFields();
+ } else {
+ const oldValues = formInst.getFieldsValue();
+ const newValues: Record = {};
+ for (const key in oldValues) {
+ if (key === "providerType" || key === "access" || key === "certificate") {
+ newValues[key] = oldValues[key];
+ } else {
+ newValues[key] = undefined;
+ }
+ }
+ formInst.setFieldsValue(newValues);
+ }
+ };
+
+ return (
+
+ {
+ const type = String(option?.value ?? "");
+ const target = deployProvidersMap.get(type);
+ const filter = (v?: string) => v?.toLowerCase()?.includes(searchValue.toLowerCase()) ?? false;
+ return filter(type) || filter(t(target?.name ?? ""));
+ }}
+ onSelect={handleProviderTypeSelect}
+ >
+ {Array.from(deployProvidersMap.values()).map((item) => {
+ return (
+
+
+
+
+ {t(item.name)}
+
+
+
+ );
+ })}
+
+
+
+
+
+
+
+ {t("workflow_node.deploy.form.provider_access.label")}
+
+
+
+
+
+
+
+
+
+ {t("workflow_node.deploy.form.provider_access.button")}
+
+ }
+ onSubmit={(record) => {
+ const provider = accessProvidersMap.get(record.configType);
+ if (ACCESS_USAGES.ALL === provider?.usage || ACCESS_USAGES.DEPLOY === provider?.usage) {
+ formInst.setFieldValue("access", record.id);
+ }
+ }}
+ />
+
+
+
+
+ {
+ if (defaultProivderType) {
+ return deployProvidersMap.get(defaultProivderType)?.provider === record.configType;
+ }
+
+ const provider = accessProvidersMap.get(record.configType);
+ return ACCESS_USAGES.ALL === provider?.usage || ACCESS_USAGES.APPLY === provider?.usage;
+ }}
+ />
+
+
+
+ }
+ >
+ {
+ return {
+ label: item.name,
+ options: item.output?.map((output) => {
+ return {
+ label: `${item.name} - ${output.label}`,
+ value: `${item.id}#${output.name}`,
+ };
+ }),
+ };
+ })}
+ placeholder={t("workflow_node.deploy.form.certificate.placeholder")}
+ />
+
+
+
+
+ {t("workflow_node.deploy.form.params_config.label")}
+
+
+
+ {formFieldsComponent}
+
+
+
+ {t("common.button.save")}
+
+
+
+ );
+};
+
+export default memo(DeployNodeForm);
diff --git a/ui/src/components/workflow/node/DeployNodeFormAliyunALBFields.tsx b/ui/src/components/workflow/node/DeployNodeFormAliyunALBFields.tsx
new file mode 100644
index 00000000..1e69763a
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormAliyunALBFields.tsx
@@ -0,0 +1,87 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
+const RESOURCE_TYPE_LISTENER = "listener" as const;
+
+const DeployNodeFormAliyunALBFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.union([z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER)], {
+ message: t("workflow_node.deploy.form.aliyun_alb_resource_type.placeholder"),
+ }),
+ region: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_alb_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.aliyun_alb_region.placeholder"))
+ .trim(),
+ loadbalancerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_LOADBALANCER || !!v?.trim(), t("workflow_node.deploy.form.aliyun_alb_loadbalancer_id.placeholder")),
+ listenerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_LISTENER || !!v?.trim(), t("workflow_node.deploy.form.aliyun_alb_listener_id.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label")}
+
+
+ {t("workflow_node.deploy.form.aliyun_alb_resource_type.option.listener.label")}
+
+
+
+
+ }
+ >
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormAliyunALBFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormAliyunCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormAliyunCDNFields.tsx
new file mode 100644
index 00000000..7c54de0f
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormAliyunCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormAliyunCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormAliyunCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormAliyunCLBFields.tsx b/ui/src/components/workflow/node/DeployNodeFormAliyunCLBFields.tsx
new file mode 100644
index 00000000..e0ca9b9b
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormAliyunCLBFields.tsx
@@ -0,0 +1,96 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+import { validPortNumber } from "@/utils/validators";
+
+const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
+const RESOURCE_TYPE_LISTENER = "listener" as const;
+
+const DeployNodeFormAliyunCLBFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.union([z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER)], {
+ message: t("workflow_node.deploy.form.aliyun_clb_resource_type.placeholder"),
+ }),
+ region: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_clb_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.aliyun_clb_region.placeholder"))
+ .trim(),
+ loadbalancerId: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_clb_loadbalancer_id.placeholder") })
+ .min(1, t("workflow_node.deploy.form.aliyun_clb_loadbalancer_id.placeholder"))
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim(),
+ listenerPort: z
+ .union([
+ z
+ .number()
+ .refine(
+ (v) => fieldResourceType === RESOURCE_TYPE_LISTENER && validPortNumber(v),
+ t("workflow_node.deploy.form.aliyun_clb_listener_port.placeholder")
+ ),
+ z
+ .string()
+ .refine(
+ (v) => fieldResourceType === RESOURCE_TYPE_LISTENER && validPortNumber(v),
+ t("workflow_node.deploy.form.aliyun_clb_listener_port.placeholder")
+ ),
+ ])
+ .nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.aliyun_clb_resource_type.option.loadbalancer.label")}
+
+
+ {t("workflow_node.deploy.form.aliyun_clb_resource_type.option.listener.label")}
+
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+
+ }
+ initialValue={443}
+ >
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormAliyunCLBFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormAliyunDCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormAliyunDCDNFields.tsx
new file mode 100644
index 00000000..e3138017
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormAliyunDCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormAliyunDCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_dcdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormAliyunDCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormAliyunNLBFields.tsx b/ui/src/components/workflow/node/DeployNodeFormAliyunNLBFields.tsx
new file mode 100644
index 00000000..427ad97a
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormAliyunNLBFields.tsx
@@ -0,0 +1,87 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
+const RESOURCE_TYPE_LISTENER = "listener" as const;
+
+const DeployNodeFormAliyunNLBFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.union([z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER)], {
+ message: t("workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder"),
+ }),
+ region: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_nlb_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.aliyun_nlb_region.placeholder"))
+ .trim(),
+ loadbalancerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_LOADBALANCER || !!v?.trim(), t("workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.placeholder")),
+ listenerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_LISTENER || !!v?.trim(), t("workflow_node.deploy.form.aliyun_nlb_listener_id.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.aliyun_nlb_resource_type.option.loadbalancer.label")}
+
+
+ {t("workflow_node.deploy.form.aliyun_nlb_resource_type.option.listener.label")}
+
+
+
+
+ }
+ >
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormAliyunNLBFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormAliyunOSSFields.tsx b/ui/src/components/workflow/node/DeployNodeFormAliyunOSSFields.tsx
new file mode 100644
index 00000000..74f89427
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormAliyunOSSFields.tsx
@@ -0,0 +1,58 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormAliyunOSSFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ endpoint: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_oss_endpoint.placeholder") })
+ .url(t("common.errmsg.url_invalid"))
+ .trim(),
+ bucket: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_oss_bucket.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.aliyun_oss_bucket.placeholder"))
+ .trim(),
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.aliyun_oss_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormAliyunOSSFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormBaiduCloudCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormBaiduCloudCDNFields.tsx
new file mode 100644
index 00000000..4b6702ef
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormBaiduCloudCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormBaiduCloudCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.baiducloud_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormBaiduCloudCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormBytePlusCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormBytePlusCDNFields.tsx
new file mode 100644
index 00000000..3b494dc2
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormBytePlusCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormBytePlusCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.byteplus_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormBytePlusCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormDogeCloudCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormDogeCloudCDNFields.tsx
new file mode 100644
index 00000000..ff3cd3c4
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormDogeCloudCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormDogeCloudCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.dogecloud_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormDogeCloudCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormHuaweiCloudCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormHuaweiCloudCDNFields.tsx
new file mode 100644
index 00000000..5b40e1eb
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormHuaweiCloudCDNFields.tsx
@@ -0,0 +1,45 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormHuaweiCloudCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ region: z
+ .string({ message: t("workflow_node.deploy.form.huaweicloud_cdn_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.huaweicloud_cdn_region.placeholder"))
+ .trim(),
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormHuaweiCloudCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormHuaweiCloudELBFields.tsx b/ui/src/components/workflow/node/DeployNodeFormHuaweiCloudELBFields.tsx
new file mode 100644
index 00000000..be6fbe3d
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormHuaweiCloudELBFields.tsx
@@ -0,0 +1,111 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+const RESOURCE_TYPE_CERTIFICATE = "certificate" as const;
+const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
+const RESOURCE_TYPE_LISTENER = "listener" as const;
+
+const DeployNodeFormHuaweiCloudELBFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.union([z.literal(RESOURCE_TYPE_CERTIFICATE), z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER)], {
+ message: t("workflow_node.deploy.form.huaweicloud_elb_resource_type.placeholder"),
+ }),
+ region: z
+ .string({ message: t("workflow_node.deploy.form.huaweicloud_elb_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.huaweicloud_elb_region.placeholder"))
+ .trim(),
+ certificateId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_CERTIFICATE || !!v?.trim(), t("workflow_node.deploy.form.huaweicloud_elb_certificate_id.placeholder")),
+ loadbalancerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine(
+ (v) => fieldResourceType !== RESOURCE_TYPE_LOADBALANCER || !!v?.trim(),
+ t("workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.placeholder")
+ ),
+ listenerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldResourceType !== RESOURCE_TYPE_LISTENER || !!v?.trim(), t("workflow_node.deploy.form.huaweicloud_elb_listener_id.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.huaweicloud_elb_resource_type.option.certificate.label")}
+
+
+ {t("workflow_node.deploy.form.huaweicloud_elb_resource_type.option.loadbalancer.label")}
+
+
+ {t("workflow_node.deploy.form.huaweicloud_elb_resource_type.option.listener.label")}
+
+
+
+
+ }
+ >
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormHuaweiCloudELBFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormKubernetesSecretFields.tsx b/ui/src/components/workflow/node/DeployNodeFormKubernetesSecretFields.tsx
new file mode 100644
index 00000000..86594924
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormKubernetesSecretFields.tsx
@@ -0,0 +1,77 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+const DeployNodeFormKubernetesSecretFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ namespace: z
+ .string({ message: t("workflow_node.deploy.form.k8s_namespace.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.k8s_namespace.placeholder"))
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim(),
+ secretName: z
+ .string({ message: t("workflow_node.deploy.form.k8s_secret_name.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.k8s_secret_name.placeholder"))
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim(),
+ secretDataKeyForCrt: z
+ .string({ message: t("workflow_node.deploy.form.k8s_secret_data_key_for_crt.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.k8s_secret_data_key_for_crt.placeholder"))
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim(),
+ secretDataKeyForKey: z
+ .string({ message: t("workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder"))
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ initialValue="default"
+ >
+
+
+
+ }
+ >
+
+
+
+ }
+ initialValue="tls.crt"
+ >
+
+
+
+ }
+ initialValue="tls.key"
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormKubernetesSecretFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormLocalFields.tsx b/ui/src/components/workflow/node/DeployNodeFormLocalFields.tsx
new file mode 100644
index 00000000..a9b3a502
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormLocalFields.tsx
@@ -0,0 +1,305 @@
+import { useTranslation } from "react-i18next";
+import { Button, Dropdown, Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { DownOutlined as DownOutlinedIcon } from "@ant-design/icons";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+const FORMAT_PEM = "pem" as const;
+const FORMAT_PFX = "pfx" as const;
+const FORMAT_JKS = "jks" as const;
+
+const SHELLENV_SH = "sh" as const;
+const SHELLENV_CMD = "cmd" as const;
+const SHELLENV_POWERSHELL = "powershell" as const;
+
+const DeployNodeFormLocalFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ format: z.union([z.literal(FORMAT_PEM), z.literal(FORMAT_PFX), z.literal(FORMAT_JKS)], {
+ message: t("domain.deployment.form.local_format.placeholder"),
+ }),
+ certPath: z
+ .string()
+ .min(1, t("workflow_node.deploy.form.local_cert_path.tooltip"))
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim(),
+ keyPath: z
+ .string()
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_PEM || !!v?.trim(), { message: t("workflow_node.deploy.form.local_key_path.tooltip") }),
+ pfxPassword: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_PFX || !!v?.trim(), { message: t("workflow_node.deploy.form.local_pfx_password.tooltip") }),
+ jksAlias: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_JKS || !!v?.trim(), { message: t("workflow_node.deploy.form.local_jks_alias.tooltip") }),
+ jksKeypass: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_JKS || !!v?.trim(), { message: t("workflow_node.deploy.form.local_jks_keypass.tooltip") }),
+ jksStorepass: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_JKS || !!v?.trim(), { message: t("workflow_node.deploy.form.local_jks_storepass.tooltip") }),
+ shellEnv: z.union([z.literal(SHELLENV_SH), z.literal(SHELLENV_CMD), z.literal(SHELLENV_POWERSHELL)], {
+ message: t("domain.deployment.form.shell.placeholder"),
+ }),
+ preCommand: z
+ .string()
+ .max(20480, t("common.errmsg.string_max", { max: 20480 }))
+ .nullish(),
+ postCommand: z
+ .string()
+ .max(20480, t("common.errmsg.string_max", { max: 20480 }))
+ .nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldFormat = Form.useWatch("format", formInst);
+ const fieldCertPath = Form.useWatch("certPath", formInst);
+
+ const handleFormatSelect = (value: string) => {
+ if (fieldFormat === value) return;
+
+ switch (value) {
+ case FORMAT_PEM:
+ {
+ if (/(.pfx|.jks)$/.test(fieldCertPath)) {
+ formInst.setFieldValue("certPath", fieldCertPath.replace(/(.pfx|.jks)$/, ".crt"));
+ }
+ }
+ break;
+
+ case FORMAT_PFX:
+ {
+ if (/(.crt|.jks)$/.test(fieldCertPath)) {
+ formInst.setFieldValue("certPath", fieldCertPath.replace(/(.crt|.jks)$/, ".pfx"));
+ }
+ }
+ break;
+
+ case FORMAT_JKS:
+ {
+ if (/(.crt|.pfx)$/.test(fieldCertPath)) {
+ formInst.setFieldValue("certPath", fieldCertPath.replace(/(.crt|.pfx)$/, ".jks"));
+ }
+ }
+ break;
+ }
+ };
+
+ const handlePresetScriptClick = (key: string) => {
+ switch (key) {
+ case "reload_nginx":
+ {
+ formInst.setFieldValue("shellEnv", "sh");
+ formInst.setFieldValue("postCommand", "sudo service nginx reload");
+ }
+ break;
+
+ case "binding_iis":
+ {
+ formInst.setFieldValue("shellEnv", "powershell");
+ formInst.setFieldValue(
+ "postCommand",
+ `# 请将以下变量替换为实际值
+$pfxPath = "" # PFX 文件路径
+$pfxPassword = "" # PFX 密码
+$siteName = "" # IIS 网站名称
+$domain = "" # 域名
+$ipaddr = "" # 绑定 IP,“*”表示所有 IP 绑定
+$port = "" # 绑定端口
+
+
+# 导入证书到本地计算机的个人存储区
+$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable
+# 获取 Thumbprint
+$thumbprint = $cert.Thumbprint
+# 导入 WebAdministration 模块
+Import-Module WebAdministration
+# 检查是否已存在 HTTPS 绑定
+$existingBinding = Get-WebBinding -Name "$siteName" -Protocol "https" -Port $port -HostHeader "$domain" -ErrorAction SilentlyContinue
+if (!$existingBinding) {
+ # 添加新的 HTTPS 绑定
+ New-WebBinding -Name "$siteName" -Protocol "https" -Port $port -IPAddress "$ipaddr" -HostHeader "$domain"
+}
+# 获取绑定对象
+$binding = Get-WebBinding -Name "$siteName" -Protocol "https" -Port $port -IPAddress "$ipaddr" -HostHeader "$domain"
+# 绑定 SSL 证书
+$binding.AddSslCertificate($thumbprint, "My")
+# 删除目录下的证书文件
+Remove-Item -Path "$pfxPath" -Force
+ `.trim()
+ );
+ }
+ break;
+
+ case "binding_netsh":
+ {
+ formInst.setFieldValue("shellEnv", "powershell");
+ formInst.setFieldValue(
+ "postCommand",
+ `# 请将以下变量替换为实际值
+$pfxPath = "" # PFX 文件路径
+$pfxPassword = "" # PFX 密码
+$ipaddr = "" # 绑定 IP,“0.0.0.0”表示所有 IP 绑定,可填入域名。
+$port = "" # 绑定端口
+
+$addr = $ipaddr + ":" + $port
+
+# 导入证书到本地计算机的个人存储区
+$cert = Import-PfxCertificate -FilePath "$pfxPath" -CertStoreLocation Cert:\\LocalMachine\\My -Password (ConvertTo-SecureString -String "$pfxPassword" -AsPlainText -Force) -Exportable
+# 获取 Thumbprint
+$thumbprint = $cert.Thumbprint
+# 检测端口是否绑定证书,如绑定则删除绑定
+$isExist = netsh http show sslcert ipport=$addr
+if ($isExist -like "*$addr*"){ netsh http delete sslcert ipport=$addr }
+# 绑定到端口
+netsh http add sslcert ipport=$addr certhash=$thumbprint
+# 删除目录下的证书文件
+Remove-Item -Path "$pfxPath" -Force
+ `.trim()
+ );
+ }
+ break;
+ }
+ };
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.local_format.option.pem.label")}
+
+
+ {t("workflow_node.deploy.form.local_format.option.pfx.label")}
+
+
+ {t("workflow_node.deploy.form.local_format.option.jks.label")}
+
+
+
+
+ }
+ initialValue="/etc/ssl/certs/cert.crt"
+ >
+
+
+
+
+ }
+ initialValue="/etc/ssl/certs/cert.key"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t("workflow_node.deploy.form.local_shell_env.option.sh.label")}
+
+
+ {t("workflow_node.deploy.form.local_shell_env.option.cmd.label")}
+
+
+ {t("workflow_node.deploy.form.local_shell_env.option.powershell.label")}
+
+
+
+
+
+
+
+
+
+
+
+
+ {t("workflow_node.deploy.form.local_post_command.label")}
+
+
+ handlePresetScriptClick("reload_nginx"),
+ },
+ {
+ key: "binding_iis",
+ label: t("workflow_node.deploy.form.local_preset_scripts.option.binding_iis.label"),
+ onClick: () => handlePresetScriptClick("binding_iis"),
+ },
+ {
+ key: "binding_netsh",
+ label: t("workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label"),
+ onClick: () => handlePresetScriptClick("binding_netsh"),
+ },
+ ],
+ }}
+ trigger={["click"]}
+ >
+
+ {t("workflow_node.deploy.form.local_preset_scripts.button")}
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormLocalFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormQiniuCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormQiniuCDNFields.tsx
new file mode 100644
index 00000000..b7ab41df
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormQiniuCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormQiniuCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.qiniu_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormQiniuCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormSSHFields.tsx b/ui/src/components/workflow/node/DeployNodeFormSSHFields.tsx
new file mode 100644
index 00000000..95385367
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormSSHFields.tsx
@@ -0,0 +1,211 @@
+import { useTranslation } from "react-i18next";
+import { Button, Dropdown, Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { DownOutlined as DownOutlinedIcon } from "@ant-design/icons";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+
+const FORMAT_PEM = "pem" as const;
+const FORMAT_PFX = "pfx" as const;
+const FORMAT_JKS = "jks" as const;
+
+const DeployNodeFormSSHFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ format: z.union([z.literal(FORMAT_PEM), z.literal(FORMAT_PFX), z.literal(FORMAT_JKS)], {
+ message: t("domain.deployment.form.ssh_format.placeholder"),
+ }),
+ certPath: z
+ .string()
+ .min(1, t("workflow_node.deploy.form.ssh_cert_path.tooltip"))
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim(),
+ keyPath: z
+ .string()
+ .max(256, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_PEM || !!v?.trim(), { message: t("workflow_node.deploy.form.ssh_key_path.tooltip") }),
+ pfxPassword: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_PFX || !!v?.trim(), { message: t("workflow_node.deploy.form.ssh_pfx_password.tooltip") }),
+ jksAlias: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_JKS || !!v?.trim(), { message: t("workflow_node.deploy.form.ssh_jks_alias.tooltip") }),
+ jksKeypass: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_JKS || !!v?.trim(), { message: t("workflow_node.deploy.form.ssh_jks_keypass.tooltip") }),
+ jksStorepass: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 256 }))
+ .trim()
+ .nullish()
+ .refine((v) => fieldFormat !== FORMAT_JKS || !!v?.trim(), { message: t("workflow_node.deploy.form.ssh_jks_storepass.tooltip") }),
+ preCommand: z
+ .string()
+ .max(20480, t("common.errmsg.string_max", { max: 20480 }))
+ .nullish(),
+ postCommand: z
+ .string()
+ .max(20480, t("common.errmsg.string_max", { max: 20480 }))
+ .nullish(),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldFormat = Form.useWatch("format", formInst);
+ const fieldCertPath = Form.useWatch("certPath", formInst);
+
+ const handleFormatSelect = (value: string) => {
+ if (fieldFormat === value) return;
+
+ switch (value) {
+ case FORMAT_PEM:
+ {
+ if (/(.pfx|.jks)$/.test(fieldCertPath)) {
+ formInst.setFieldValue("certPath", fieldCertPath.replace(/(.pfx|.jks)$/, ".crt"));
+ }
+ }
+ break;
+
+ case FORMAT_PFX:
+ {
+ if (/(.crt|.jks)$/.test(fieldCertPath)) {
+ formInst.setFieldValue("certPath", fieldCertPath.replace(/(.crt|.jks)$/, ".pfx"));
+ }
+ }
+ break;
+
+ case FORMAT_JKS:
+ {
+ if (/(.crt|.pfx)$/.test(fieldCertPath)) {
+ formInst.setFieldValue("certPath", fieldCertPath.replace(/(.crt|.pfx)$/, ".jks"));
+ }
+ }
+ break;
+ }
+ };
+
+ const handlePresetScriptClick = (key: string) => {
+ switch (key) {
+ case "reload_nginx":
+ {
+ formInst.setFieldValue("postCommand", "sudo service nginx reload");
+ }
+ break;
+ }
+ };
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.ssh_format.option.pem.label")}
+
+
+ {t("workflow_node.deploy.form.ssh_format.option.pfx.label")}
+
+
+ {t("workflow_node.deploy.form.ssh_format.option.jks.label")}
+
+
+
+
+ }
+ initialValue="/etc/ssl/certs/cert.crt"
+ >
+
+
+
+
+ }
+ initialValue="/etc/ssl/certs/cert.key"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t("workflow_node.deploy.form.ssh_post_command.label")}
+
+
+ handlePresetScriptClick("reload_nginx"),
+ },
+ ],
+ }}
+ trigger={["click"]}
+ >
+
+ {t("workflow_node.deploy.form.ssh_preset_scripts.button")}
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormSSHFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormTencentCloudCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormTencentCloudCDNFields.tsx
new file mode 100644
index 00000000..3eb146c2
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormTencentCloudCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormTencentCloudCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormTencentCloudCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormTencentCloudCLBFields.tsx b/ui/src/components/workflow/node/DeployNodeFormTencentCloudCLBFields.tsx
new file mode 100644
index 00000000..bc42c108
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormTencentCloudCLBFields.tsx
@@ -0,0 +1,125 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input, Select } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import Show from "@/components/Show";
+import { validDomainName } from "@/utils/validators";
+
+const RESOURCE_TYPE_SSLDEPLOY = "ssl-deploy" as const;
+const RESOURCE_TYPE_LOADBALANCER = "loadbalancer" as const;
+const RESOURCE_TYPE_LISTENER = "listener" as const;
+const RESOURCE_TYPE_RULEDOMAIN = "ruledomain" as const;
+
+const DeployNodeFormTencentCloudCLBFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ resourceType: z.union(
+ [z.literal(RESOURCE_TYPE_SSLDEPLOY), z.literal(RESOURCE_TYPE_LOADBALANCER), z.literal(RESOURCE_TYPE_LISTENER), z.literal(RESOURCE_TYPE_RULEDOMAIN)],
+ { message: t("workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder") }
+ ),
+ region: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_clb_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.tencentcloud_clb_region.placeholder"))
+ .trim(),
+ loadbalancerId: z
+ .string()
+ .min(1, t("workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.placeholder"))
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim(),
+ listenerId: z
+ .string()
+ .max(64, t("common.errmsg.string_max", { max: 64 }))
+ .trim()
+ .nullish()
+ .refine(
+ (v) => ![RESOURCE_TYPE_SSLDEPLOY, RESOURCE_TYPE_LISTENER, RESOURCE_TYPE_RULEDOMAIN].includes(fieldResourceType) || !!v?.trim(),
+ t("workflow_node.deploy.form.tencentcloud_clb_listener_id.placeholder")
+ ),
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_clb_domain.placeholder") })
+ .nullish()
+ .refine((v) => RESOURCE_TYPE_RULEDOMAIN !== fieldResourceType || validDomainName(v!, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const fieldResourceType = Form.useWatch("resourceType", formInst);
+
+ return (
+ <>
+
+
+
+ {t("workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ssl_deploy.label")}
+
+
+ {t("workflow_node.deploy.form.tencentcloud_clb_resource_type.option.loadbalancer.label")}
+
+
+ {t("workflow_node.deploy.form.tencentcloud_clb_resource_type.option.listener.label")}
+
+
+ {t("workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ruledomain.label")}
+
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+
+
+ }
+ >
+
+
+
+ >
+ );
+};
+
+export default DeployNodeFormTencentCloudCLBFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormTencentCloudCOSFields.tsx b/ui/src/components/workflow/node/DeployNodeFormTencentCloudCOSFields.tsx
new file mode 100644
index 00000000..bde2b13f
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormTencentCloudCOSFields.tsx
@@ -0,0 +1,58 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormTencentCloudCOSFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ region: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_cos_region.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.tencentcloud_cos_region.placeholder"))
+ .trim(),
+ bucket: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_cos_bucket.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.tencentcloud_cos_bucket.placeholder"))
+ .trim(),
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_cos_domain.placeholder") })
+ .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+
+ }
+ >
+
+
+
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormTencentCloudCOSFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormTencentCloudECDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormTencentCloudECDNFields.tsx
new file mode 100644
index 00000000..7114b9f9
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormTencentCloudECDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormTencentCloudECDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormTencentCloudECDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormTencentCloudEOFields.tsx b/ui/src/components/workflow/node/DeployNodeFormTencentCloudEOFields.tsx
new file mode 100644
index 00000000..c3e472c7
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormTencentCloudEOFields.tsx
@@ -0,0 +1,45 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormTencentCloudEOFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ zoneId: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_eo_zone_id.placeholder") })
+ .nonempty(t("workflow_node.deploy.form.tencentcloud_eo_zone_id.placeholder"))
+ .trim(),
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.tencentcloud_eo_domain.placeholder") })
+ .refine((v) => validDomainName(v), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormTencentCloudEOFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormVolcEngineCDNFields.tsx b/ui/src/components/workflow/node/DeployNodeFormVolcEngineCDNFields.tsx
new file mode 100644
index 00000000..20771c44
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormVolcEngineCDNFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormVolcEngineCDNFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.volcengine_cdn_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormVolcEngineCDNFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormVolcEngineLiveFields.tsx b/ui/src/components/workflow/node/DeployNodeFormVolcEngineLiveFields.tsx
new file mode 100644
index 00000000..06410a88
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormVolcEngineLiveFields.tsx
@@ -0,0 +1,32 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+import { validDomainName } from "@/utils/validators";
+
+const DeployNodeFormVolcEngineLiveFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ domain: z
+ .string({ message: t("workflow_node.deploy.form.volcengine_live_domain.placeholder") })
+ .refine((v) => validDomainName(v, true), t("common.errmsg.domain_invalid")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormVolcEngineLiveFields;
diff --git a/ui/src/components/workflow/node/DeployNodeFormWebhookFields.tsx b/ui/src/components/workflow/node/DeployNodeFormWebhookFields.tsx
new file mode 100644
index 00000000..d56b94b8
--- /dev/null
+++ b/ui/src/components/workflow/node/DeployNodeFormWebhookFields.tsx
@@ -0,0 +1,50 @@
+import { useTranslation } from "react-i18next";
+import { Form, Input } from "antd";
+import { createSchemaFieldRule } from "antd-zod";
+import { z } from "zod";
+
+const DeployNodeFormWebhookFields = () => {
+ const { t } = useTranslation();
+
+ const formSchema = z.object({
+ webhookData: z.string({ message: t("workflow_node.deploy.form.webhook_data.placeholder") }).refine((v) => {
+ try {
+ JSON.parse(v);
+ return true;
+ } catch {
+ return false;
+ }
+ }, t("workflow_node.deploy.form.webhook_data.placeholder")),
+ });
+ const formRule = createSchemaFieldRule(formSchema);
+ const formInst = Form.useFormInstance();
+
+ const handleWebhookDataBlur = (e: React.FocusEvent) => {
+ const value = e.target.value;
+ try {
+ const json = JSON.stringify(JSON.parse(value), null, 2);
+ formInst.setFieldValue("webhookData", json);
+ } catch {
+ return;
+ }
+ };
+
+ return (
+ <>
+ }
+ >
+
+
+ >
+ );
+};
+
+export default DeployNodeFormWebhookFields;
diff --git a/ui/src/components/workflow/node/NotifyNodeForm.tsx b/ui/src/components/workflow/node/NotifyNodeForm.tsx
index 96394715..cca7800b 100644
--- a/ui/src/components/workflow/node/NotifyNodeForm.tsx
+++ b/ui/src/components/workflow/node/NotifyNodeForm.tsx
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { Button, Form, Input, Select } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import { RightOutlined as RightOutlinedIcon } from "@ant-design/icons";
+import { produce } from "immer";
import { z } from "zod";
import { usePanel } from "../PanelProvider";
@@ -37,14 +38,14 @@ const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => {
const formSchema = z.object({
subject: z
- .string({ message: t("workflow.nodes.notify.form.subject.placeholder") })
- .min(1, t("workflow.nodes.notify.form.subject.placeholder"))
+ .string({ message: t("workflow_node.notify.form.subject.placeholder") })
+ .min(1, t("workflow_node.notify.form.subject.placeholder"))
.max(1000, t("common.errmsg.string_max", { max: 1000 })),
message: z
- .string({ message: t("workflow.nodes.notify.form.message.placeholder") })
- .min(1, t("workflow.nodes.notify.form.message.placeholder"))
+ .string({ message: t("workflow_node.notify.form.message.placeholder") })
+ .min(1, t("workflow_node.notify.form.message.placeholder"))
.max(1000, t("common.errmsg.string_max", { max: 1000 })),
- channel: z.string({ message: t("workflow.nodes.notify.form.channel.placeholder") }).min(1, t("workflow.nodes.notify.form.channel.placeholder")),
+ channel: z.string({ message: t("workflow_node.notify.form.channel.placeholder") }).min(1, t("workflow_node.notify.form.channel.placeholder")),
});
const formRule = createSchemaFieldRule(formSchema);
const {
@@ -54,29 +55,35 @@ const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => {
} = useAntdForm>({
initialValues: data?.config ?? initFormModel(),
onSubmit: async (values) => {
- await updateNode({ ...data, config: { ...values }, validated: true });
+ await formInst.validateFields();
+ await updateNode(
+ produce(data, (draft) => {
+ draft.config = { ...values };
+ draft.validated = true;
+ })
+ );
hidePanel();
},
});
return (
-
+
+
-
-
+
+
-
+
-
{t("workflow.nodes.notify.form.channel.label")}
+
{t("workflow_node.notify.form.channel.label")}
- {t("workflow.nodes.notify.form.channel.button")}
+ {t("workflow_node.notify.form.channel.button")}
@@ -92,7 +99,7 @@ const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => {
label: t(notifyChannelsMap.get(k)?.name ?? k),
value: k,
}))}
- placeholder={t("workflow.nodes.notify.form.channel.placeholder")}
+ placeholder={t("workflow_node.notify.form.channel.placeholder")}
/>
diff --git a/ui/src/components/workflow/node/StartNodeForm.tsx b/ui/src/components/workflow/node/StartNodeForm.tsx
index 0b1f30a2..def12070 100644
--- a/ui/src/components/workflow/node/StartNodeForm.tsx
+++ b/ui/src/components/workflow/node/StartNodeForm.tsx
@@ -3,6 +3,7 @@ import { useTranslation } from "react-i18next";
import { Alert, Button, Form, Input, Radio } from "antd";
import { createSchemaFieldRule } from "antd-zod";
import dayjs from "dayjs";
+import { produce } from "immer";
import { z } from "zod";
import { usePanel } from "../PanelProvider";
@@ -30,7 +31,7 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => {
const formSchema = z
.object({
- executionMethod: z.string({ message: t("workflow.nodes.start.form.trigger.placeholder") }).min(1, t("workflow.nodes.start.form.trigger.placeholder")),
+ executionMethod: z.string({ message: t("workflow_node.start.form.trigger.placeholder") }).min(1, t("workflow_node.start.form.trigger.placeholder")),
crontab: z.string().nullish(),
})
.superRefine((data, ctx) => {
@@ -41,7 +42,7 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => {
if (!validCronExpression(data.crontab!)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
- message: t("workflow.nodes.start.form.trigger_cron.errmsg.invalid"),
+ message: t("workflow_node.start.form.trigger_cron.errmsg.invalid"),
path: ["crontab"],
});
}
@@ -54,7 +55,13 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => {
} = useAntdForm
>({
initialValues: data?.config ?? initFormModel(),
onSubmit: async (values) => {
- await updateNode({ ...data, config: { ...values }, validated: true });
+ await formInst.validateFields();
+ await updateNode(
+ produce(data, (draft) => {
+ draft.config = { ...values };
+ draft.validated = true;
+ })
+ );
hidePanel();
},
});
@@ -82,26 +89,26 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => {
}
+ tooltip={ }
>
handleTriggerTypeChange(e.target.value)}>
- {t("workflow.nodes.start.form.trigger.option.auto.label")}
- {t("workflow.nodes.start.form.trigger.option.manual.label")}
+ {t("workflow_node.start.form.trigger.option.auto.label")}
+ {t("workflow_node.start.form.trigger.option.manual.label")}
}
+ tooltip={ }
extra={
triggerCronLastExecutions.length > 0 ? (
- {t("workflow.nodes.start.form.trigger_cron.extra")}
+ {t("workflow_node.start.form.trigger_cron.extra")}
{triggerCronLastExecutions.map((date, index) => (
@@ -115,11 +122,11 @@ const StartNodeForm = ({ data }: StartNodeFormProps) => {
)
}
>
- handleTriggerCronChange(e.target.value)} />
+ handleTriggerCronChange(e.target.value)} />
- } />
+
} />
diff --git a/ui/src/domain/provider.ts b/ui/src/domain/provider.ts
new file mode 100644
index 00000000..61172540
--- /dev/null
+++ b/ui/src/domain/provider.ts
@@ -0,0 +1,96 @@
+import {
+ ACCESS_PROVIDER_ACMEHTTPREQ,
+ ACCESS_PROVIDER_ALIYUN,
+ ACCESS_PROVIDER_AWS,
+ ACCESS_PROVIDER_BAIDUCLOUD,
+ ACCESS_PROVIDER_BYTEPLUS,
+ ACCESS_PROVIDER_CLOUDFLARE,
+ ACCESS_PROVIDER_DOGECLOUD,
+ ACCESS_PROVIDER_HUAWEICLOUD,
+ ACCESS_PROVIDER_KUBERNETES,
+ ACCESS_PROVIDER_LOCAL,
+ ACCESS_PROVIDER_NAMEDOTCOM,
+ ACCESS_PROVIDER_NAMESILO,
+ ACCESS_PROVIDER_GODADDY,
+ ACCESS_PROVIDER_POWERDNS,
+ ACCESS_PROVIDER_QINIU,
+ ACCESS_PROVIDER_SSH,
+ ACCESS_PROVIDER_TENCENTCLOUD,
+ ACCESS_PROVIDER_VOLCENGINE,
+ ACCESS_PROVIDER_WEBHOOK,
+ type AccessUsageType,
+} from "./access";
+
+export type AccessProvider = {
+ type: string;
+ name: string;
+ icon: string;
+ usage: AccessUsageType;
+};
+
+export const accessProvidersMap: Map = new Map(
+ /*
+ 注意:此处的顺序决定显示在前端的顺序。
+ NOTICE: The following order determines the order displayed at the frontend.
+ */
+ [
+ [ACCESS_PROVIDER_LOCAL, "common.provider.local", "/imgs/providers/local.svg", "deploy"],
+ [ACCESS_PROVIDER_SSH, "common.provider.ssh", "/imgs/providers/ssh.svg", "deploy"],
+ [ACCESS_PROVIDER_WEBHOOK, "common.provider.webhook", "/imgs/providers/webhook.svg", "deploy"],
+ [ACCESS_PROVIDER_KUBERNETES, "common.provider.kubernetes", "/imgs/providers/kubernetes.svg", "deploy"],
+ [ACCESS_PROVIDER_ALIYUN, "common.provider.aliyun", "/imgs/providers/aliyun.svg", "all"],
+ [ACCESS_PROVIDER_TENCENTCLOUD, "common.provider.tencentcloud", "/imgs/providers/tencentcloud.svg", "all"],
+ [ACCESS_PROVIDER_HUAWEICLOUD, "common.provider.huaweicloud", "/imgs/providers/huaweicloud.svg", "all"],
+ [ACCESS_PROVIDER_BAIDUCLOUD, "common.provider.baiducloud", "/imgs/providers/baiducloud.svg", "all"],
+ [ACCESS_PROVIDER_QINIU, "common.provider.qiniu", "/imgs/providers/qiniu.svg", "deploy"],
+ [ACCESS_PROVIDER_DOGECLOUD, "common.provider.dogecloud", "/imgs/providers/dogecloud.svg", "deploy"],
+ [ACCESS_PROVIDER_VOLCENGINE, "common.provider.volcengine", "/imgs/providers/volcengine.svg", "all"],
+ [ACCESS_PROVIDER_BYTEPLUS, "common.provider.byteplus", "/imgs/providers/byteplus.svg", "all"],
+ [ACCESS_PROVIDER_AWS, "common.provider.aws", "/imgs/providers/aws.svg", "apply"],
+ [ACCESS_PROVIDER_CLOUDFLARE, "common.provider.cloudflare", "/imgs/providers/cloudflare.svg", "apply"],
+ [ACCESS_PROVIDER_NAMEDOTCOM, "common.provider.namedotcom", "/imgs/providers/namedotcom.svg", "apply"],
+ [ACCESS_PROVIDER_NAMESILO, "common.provider.namesilo", "/imgs/providers/namesilo.svg", "apply"],
+ [ACCESS_PROVIDER_GODADDY, "common.provider.godaddy", "/imgs/providers/godaddy.svg", "apply"],
+ [ACCESS_PROVIDER_POWERDNS, "common.provider.powerdns", "/imgs/providers/powerdns.svg", "apply"],
+ [ACCESS_PROVIDER_ACMEHTTPREQ, "common.provider.acmehttpreq", "/imgs/providers/acmehttpreq.svg", "apply"],
+ ].map(([type, name, icon, usage]) => [type, { type, name, icon, usage: usage as AccessUsageType }])
+);
+
+export type DeployProvider = {
+ type: string;
+ name: string;
+ icon: string;
+ provider: AccessProvider["type"];
+};
+
+export const deployProvidersMap: Map = new Map(
+ [
+ /*
+ 注意:此处的顺序决定显示在前端的顺序。
+ NOTICE: The following order determines the order displayed at the frontend.
+ */
+ [`${ACCESS_PROVIDER_LOCAL}`, "common.provider.local"],
+ [`${ACCESS_PROVIDER_SSH}`, "common.provider.ssh"],
+ [`${ACCESS_PROVIDER_WEBHOOK}`, "common.provider.webhook"],
+ [`${ACCESS_PROVIDER_KUBERNETES}-secret`, "common.provider.kubernetes.secret"],
+ [`${ACCESS_PROVIDER_ALIYUN}-oss`, "common.provider.aliyun.oss"],
+ [`${ACCESS_PROVIDER_ALIYUN}-cdn`, "common.provider.aliyun.cdn"],
+ [`${ACCESS_PROVIDER_ALIYUN}-dcdn`, "common.provider.aliyun.dcdn"],
+ [`${ACCESS_PROVIDER_ALIYUN}-clb`, "common.provider.aliyun.clb"],
+ [`${ACCESS_PROVIDER_ALIYUN}-alb`, "common.provider.aliyun.alb"],
+ [`${ACCESS_PROVIDER_ALIYUN}-nlb`, "common.provider.aliyun.nlb"],
+ [`${ACCESS_PROVIDER_TENCENTCLOUD}-cdn`, "common.provider.tencentcloud.cdn"],
+ [`${ACCESS_PROVIDER_TENCENTCLOUD}-ecdn`, "common.provider.tencentcloud.ecdn"],
+ [`${ACCESS_PROVIDER_TENCENTCLOUD}-clb`, "common.provider.tencentcloud.clb"],
+ [`${ACCESS_PROVIDER_TENCENTCLOUD}-cos`, "common.provider.tencentcloud.cos"],
+ [`${ACCESS_PROVIDER_TENCENTCLOUD}-eo`, "common.provider.tencentcloud.eo"],
+ [`${ACCESS_PROVIDER_HUAWEICLOUD}-cdn`, "common.provider.huaweicloud.cdn"],
+ [`${ACCESS_PROVIDER_HUAWEICLOUD}-elb`, "common.provider.huaweicloud.elb"],
+ [`${ACCESS_PROVIDER_BAIDUCLOUD}-cdn`, "common.provider.baiducloud.cdn"],
+ [`${ACCESS_PROVIDER_VOLCENGINE}-cdn`, "common.provider.volcengine.cdn"],
+ [`${ACCESS_PROVIDER_VOLCENGINE}-live`, "common.provider.volcengine.live"],
+ [`${ACCESS_PROVIDER_QINIU}-cdn`, "common.provider.qiniu.cdn"],
+ [`${ACCESS_PROVIDER_DOGECLOUD}-cdn`, "common.provider.dogecloud.cdn"],
+ [`${ACCESS_PROVIDER_BYTEPLUS}-cdn`, "common.provider.byteplus.cdn"],
+ ].map(([type, name]) => [type, { type, name, icon: accessProvidersMap.get(type.split("-")[0])!.icon, provider: type.split("-")[0] }])
+);
diff --git a/ui/src/domain/workflow.ts b/ui/src/domain/workflow.ts
index f919a79e..d929d4e2 100644
--- a/ui/src/domain/workflow.ts
+++ b/ui/src/domain/workflow.ts
@@ -2,7 +2,7 @@ import { produce } from "immer";
import { nanoid } from "nanoid";
import i18n from "@/i18n";
-import { deployTargets } from "./domain";
+import { deployProvidersMap } from "./provider";
/**
* @deprecated
@@ -346,7 +346,6 @@ export const getWorkflowOutputBeforeId = (node: WorkflowNode | WorkflowBranchNod
if (isWorkflowBranchNode(current)) {
const currentLength = output.length;
- console.log(currentLength);
for (const branch of current.branches) {
if (traverse(branch, output)) {
return true;
@@ -424,7 +423,7 @@ export type WorkflowNodeDropdwonItemIcon = {
name: string;
};
-const workflowNodeDropdownDeployList: WorkflowNodeDropdwonItem[] = deployTargets.map((item) => {
+const workflowNodeDropdownDeployList: WorkflowNodeDropdwonItem[] = Array.from(deployProvidersMap.values()).map((item) => {
return {
type: WorkflowNodeType.Apply,
providerType: item.type,
diff --git a/ui/src/i18n/locales/en/index.ts b/ui/src/i18n/locales/en/index.ts
index b23a3bf7..0ffa606b 100644
--- a/ui/src/i18n/locales/en/index.ts
+++ b/ui/src/i18n/locales/en/index.ts
@@ -5,6 +5,8 @@ import nlsSettings from "./nls.settings.json";
import nlsDomain from "./nls.domain.json";
import nlsAccess from "./nls.access.json";
import nlsWorkflow from "./nls.workflow.json";
+import nlsWorkflowNodes from "./nls.workflow.nodes.json";
+import nlsWorkflowRuns from "./nls.workflow.runs.json";
import nlsCertificate from "./nls.certificate.json";
export default Object.freeze({
@@ -15,5 +17,7 @@ export default Object.freeze({
...nlsDomain,
...nlsAccess,
...nlsWorkflow,
+ ...nlsWorkflowNodes,
+ ...nlsWorkflowRuns,
...nlsCertificate,
});
diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json
index 0d00395a..031dbc3a 100644
--- a/ui/src/i18n/locales/en/nls.access.json
+++ b/ui/src/i18n/locales/en/nls.access.json
@@ -5,7 +5,7 @@
"access.action.add": "Create Authorization",
"access.action.edit": "Edit Authorization",
- "access.action.copy": "Copy Authorization",
+ "access.action.duplicate": "Duplicate Authorization",
"access.action.delete": "Delete Authorization",
"access.action.delete.confirm": "Are you sure to delete this authorization?",
@@ -46,7 +46,7 @@
"access.form.aws_secret_access_key.placeholder": "Please enter AWS Secret Access Key",
"access.form.aws_secret_access_key.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/IAM/latest/UserGuide/id_credentials_access-keys.html ",
"access.form.aws_region.label": "AWS Region",
- "access.form.aws_region.placeholder": "Please enter AWS Region (example: us-east-1)",
+ "access.form.aws_region.placeholder": "Please enter AWS Region (e.g. us-east-1)",
"access.form.aws_region.tooltip": "For more information, see https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints ",
"access.form.aws_hosted_zone_id.label": "AWS Hosted Zone ID",
"access.form.aws_hosted_zone_id.placeholder": "Please enter AWS Hosted Zone ID",
@@ -85,7 +85,7 @@
"access.form.huaweicloud_secret_access_key.placeholder": "Please enter Huawei Cloud Secret Access Key",
"access.form.huaweicloud_secret_access_key.tooltip": "For more information, see https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html ",
"access.form.huaweicloud_region.label": "Huawei Cloud Region",
- "access.form.huaweicloud_region.placeholder": "Please enter Huawei Cloud Region (example: cn-north-1)",
+ "access.form.huaweicloud_region.placeholder": "Please enter Huawei Cloud Region (e.g. cn-north-1)",
"access.form.huaweicloud_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint ",
"access.form.k8s_kubeconfig.label": "KubeConfig",
"access.form.k8s_kubeconfig.placeholder": "Please enter KubeConfig file",
diff --git a/ui/src/i18n/locales/en/nls.common.json b/ui/src/i18n/locales/en/nls.common.json
index aab8b37d..2ab6c76e 100644
--- a/ui/src/i18n/locales/en/nls.common.json
+++ b/ui/src/i18n/locales/en/nls.common.json
@@ -29,10 +29,10 @@
"common.errmsg.string_max": "Please enter no more than {{max}} characters",
"common.errmsg.email_invalid": "Please enter a valid email address",
- "common.errmsg.domain_invalid": "Please enter domain",
- "common.errmsg.host_invalid": "Please enter a valid domain name or IP",
+ "common.errmsg.domain_invalid": "Please enter a valid domain name",
+ "common.errmsg.host_invalid": "Please enter a valid domain name or IP address",
"common.errmsg.port_invalid": "Please enter a valid port",
- "common.errmsg.ip_invalid": "Please enter a valid IP",
+ "common.errmsg.ip_invalid": "Please enter a valid IP address",
"common.errmsg.url_invalid": "Please enter a valid URL",
"common.provider.acmehttpreq": "Http Request (ACME Proxy)",
diff --git a/ui/src/i18n/locales/en/nls.workflow.json b/ui/src/i18n/locales/en/nls.workflow.json
index 8dd664ee..b86e38aa 100644
--- a/ui/src/i18n/locales/en/nls.workflow.json
+++ b/ui/src/i18n/locales/en/nls.workflow.json
@@ -29,59 +29,6 @@
"workflow.baseinfo.form.description.label": "Description",
"workflow.baseinfo.form.description.placeholder": "Please enter description",
- "workflow.nodes.start.form.trigger.label": "Trigger",
- "workflow.nodes.start.form.trigger.placeholder": "Please select trigger",
- "workflow.nodes.start.form.trigger.tooltip": "Auto: Time triggered based on cron expression. Manual: Manually triggered.",
- "workflow.nodes.start.form.trigger.option.auto.label": "Auto",
- "workflow.nodes.start.form.trigger.option.manual.label": "Manual",
- "workflow.nodes.start.form.trigger_cron.label": "Cron Expression",
- "workflow.nodes.start.form.trigger_cron.placeholder": "Please enter cron expression",
- "workflow.nodes.start.form.trigger_cron.errmsg.invalid": "Please enter a valid cron expression",
- "workflow.nodes.start.form.trigger_cron.tooltip": "Time zone is based on the server.",
- "workflow.nodes.start.form.trigger_cron.extra": "Expected execution time for the last 5 times:",
- "workflow.nodes.start.form.trigger_cron_alert.content": "Tips: If you have multiple workflows, it is recommended to set them to run at multiple times of the day instead of always running at specific times. Reference links: 1. Let’s Encrypt rate limits 2. Why should my Let’s Encrypt (ACME) client run at a random time? ",
- "workflow.nodes.apply.form.domains.label": "Domains",
- "workflow.nodes.apply.form.domains.placeholder": "Please enter domains (separated by semicolons)",
- "workflow.nodes.apply.form.domains.tooltip": "Wildcard domain: *.example.com",
- "workflow.nodes.apply.form.domains.multiple_input_modal.title": "Change Domains",
- "workflow.nodes.apply.form.domains.multiple_input_modal.placeholder": "Please enter domain",
- "workflow.nodes.apply.form.email.label": "Contact Email",
- "workflow.nodes.apply.form.email.placeholder": "Please enter contact email",
- "workflow.nodes.apply.form.email.tooltip": "Contact information required for SSL certificate application. Please pay attention to the rate limits .",
- "workflow.nodes.apply.form.access.label": "DNS Provider Authorization",
- "workflow.nodes.apply.form.access.placeholder": "Please select an authorization of DNS provider",
- "workflow.nodes.apply.form.access.tooltip": "Used to manage DNS records during ACME DNS-01 authentication.",
- "workflow.nodes.apply.form.access.button": "Create",
- "workflow.nodes.apply.form.advanced_settings.label": "Advanced Settings",
- "workflow.nodes.apply.form.key_algorithm.label": "Certificate Key Algorithm",
- "workflow.nodes.apply.form.key_algorithm.placeholder": "Please select certificate key algorithm",
- "workflow.nodes.apply.form.nameservers.label": "DNS Recursive Nameservers",
- "workflow.nodes.apply.form.nameservers.placeholder": "Please enter DNS recursive nameservers (separated by semicolons)",
- "workflow.nodes.apply.form.nameservers.tooltip": "It determines whether to custom DNS recursive nameservers during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.",
- "workflow.nodes.apply.form.nameservers.multiple_input_modal.title": "Change Nameservers",
- "workflow.nodes.apply.form.nameservers.multiple_input_modal.placeholder": "Please enter nameserver",
- "workflow.nodes.apply.form.propagation_timeout.label": "DNS Propagation Timeout",
- "workflow.nodes.apply.form.propagation_timeout.placeholder": "Please enter DNS propagation timeout",
- "workflow.nodes.apply.form.propagation_timeout.suffix": "Seconds",
- "workflow.nodes.apply.form.propagation_timeout.tooltip": "It determines the maximum waiting time for DNS propagation checks during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.",
- "workflow.nodes.apply.form.disable_follow_cname.label": "Disable CNAME following",
- "workflow.nodes.apply.form.disable_follow_cname.tooltip": "It determines whether to disable CNAME following during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.Learn more .",
- "workflow.nodes.notify.form.subject.label": "Subject",
- "workflow.nodes.notify.form.subject.placeholder": "Please enter subject",
- "workflow.nodes.notify.form.message.label": "Message",
- "workflow.nodes.notify.form.message.placeholder": "Please enter message",
- "workflow.nodes.notify.form.channel.label": "Channel",
- "workflow.nodes.notify.form.channel.placeholder": "Please select channel",
- "workflow.nodes.notify.form.channel.button": "Configure",
-
- "workflow_run.props.id": "ID",
- "workflow_run.props.status": "Status",
- "workflow_run.props.status.succeeded": "Succeeded",
- "workflow_run.props.status.failed": "Failed",
- "workflow_run.props.trigger": "Trigger",
- "workflow_run.props.started_at": "Started At",
- "workflow_run.props.completed_at": "Completed At",
-
"workflow.detail.action.save": "Save updates",
"workflow.detail.action.save.failed": "Save failed",
"workflow.detail.action.save.failed.uncompleted": "Please complete the orchestration and publish the changes first",
diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json
new file mode 100644
index 00000000..52d740ed
--- /dev/null
+++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json
@@ -0,0 +1,269 @@
+{
+ "workflow_node.start.form.trigger.label": "Trigger",
+ "workflow_node.start.form.trigger.placeholder": "Please select trigger",
+ "workflow_node.start.form.trigger.tooltip": "Auto: Time triggered based on cron expression. Manual: Manually triggered.",
+ "workflow_node.start.form.trigger.option.auto.label": "Auto",
+ "workflow_node.start.form.trigger.option.manual.label": "Manual",
+ "workflow_node.start.form.trigger_cron.label": "Cron Expression",
+ "workflow_node.start.form.trigger_cron.placeholder": "Please enter cron expression",
+ "workflow_node.start.form.trigger_cron.errmsg.invalid": "Please enter a valid cron expression",
+ "workflow_node.start.form.trigger_cron.tooltip": "Time zone is based on the server.",
+ "workflow_node.start.form.trigger_cron.extra": "Expected execution time for the last 5 times:",
+ "workflow_node.start.form.trigger_cron_alert.content": "Tips: If you have multiple workflows, it is recommended to set them to run at multiple times of the day instead of always running at specific times. Reference links: 1. Let’s Encrypt rate limits 2. Why should my Let’s Encrypt (ACME) client run at a random time? ",
+
+ "workflow_node.apply.form.domains.label": "Domains",
+ "workflow_node.apply.form.domains.placeholder": "Please enter domains (separated by semicolons)",
+ "workflow_node.apply.form.domains.tooltip": "Wildcard domain: *.example.com",
+ "workflow_node.apply.form.domains.multiple_input_modal.title": "Change Domains",
+ "workflow_node.apply.form.domains.multiple_input_modal.placeholder": "Please enter domain",
+ "workflow_node.apply.form.email.label": "Contact Email",
+ "workflow_node.apply.form.email.placeholder": "Please enter contact email",
+ "workflow_node.apply.form.email.tooltip": "Contact information required for SSL certificate application. Please pay attention to the rate limits .",
+ "workflow_node.apply.form.access.label": "DNS Provider Authorization",
+ "workflow_node.apply.form.access.placeholder": "Please select an authorization of DNS provider",
+ "workflow_node.apply.form.access.tooltip": "Used to manage DNS records during ACME DNS-01 authentication.",
+ "workflow_node.apply.form.access.button": "Create",
+ "workflow_node.apply.form.advanced_config.label": "Advanced Settings",
+ "workflow_node.apply.form.key_algorithm.label": "Certificate Key Algorithm",
+ "workflow_node.apply.form.key_algorithm.placeholder": "Please select certificate key algorithm",
+ "workflow_node.apply.form.nameservers.label": "DNS Recursive Nameservers (Optional)",
+ "workflow_node.apply.form.nameservers.placeholder": "Please enter DNS recursive nameservers (separated by semicolons)",
+ "workflow_node.apply.form.nameservers.tooltip": "It determines whether to custom DNS recursive nameservers during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.",
+ "workflow_node.apply.form.nameservers.multiple_input_modal.title": "Change DNS Recursive Nameservers",
+ "workflow_node.apply.form.nameservers.multiple_input_modal.placeholder": "Please enter DNS recursive nameserver",
+ "workflow_node.apply.form.propagation_timeout.label": "DNS Propagation Timeout (Optional)",
+ "workflow_node.apply.form.propagation_timeout.placeholder": "Please enter DNS propagation timeout",
+ "workflow_node.apply.form.propagation_timeout.suffix": "Seconds",
+ "workflow_node.apply.form.propagation_timeout.tooltip": "It determines the maximum waiting time for DNS propagation checks during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.",
+ "workflow_node.apply.form.disable_follow_cname.label": "Disable CNAME following",
+ "workflow_node.apply.form.disable_follow_cname.tooltip": "It determines whether to disable CNAME following during ACME DNS-01 authentication. If you don't understand this option, just keep it by default.Learn more .",
+
+ "workflow_node.deploy.form.provider_type.label": "Deploy Target",
+ "workflow_node.deploy.form.provider_type.placeholder": "Please select deploy target",
+ "workflow_node.deploy.form.provider_access.label": "Host Provider Authorization",
+ "workflow_node.deploy.form.provider_access.placeholder": "Please select an authorization of host provider",
+ "workflow_node.deploy.form.provider_access.tooltip": "Used to deploy certificates.",
+ "workflow_node.deploy.form.provider_access.button": "Create",
+ "workflow_node.deploy.form.certificate.label": "Certificate",
+ "workflow_node.deploy.form.certificate.placeholder": "Please select certificate",
+ "workflow_node.deploy.form.certificate.tooltip": "The certificate to be deployed comes from the previous application stage node.",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.label": "Resource Type",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "ALB Load Balancer",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.option.listener.label": "ALB Listener",
+ "workflow_node.deploy.form.aliyun_alb_region.label": "Aliyun Region",
+ "workflow_node.deploy.form.aliyun_alb_region.placeholder": "Please enter Aliyun region (e.g. cn-hangzhou)",
+ "workflow_node.deploy.form.aliyun_alb_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/slb/application-load-balancer/product-overview/supported-regions-and-zones ",
+ "workflow_node.deploy.form.aliyun_alb_loadbalancer_id.label": "Aliyun ALB Load Balancer ID",
+ "workflow_node.deploy.form.aliyun_alb_loadbalancer_id.placeholder": "Please enter Aliyun ALB load balancer ID",
+ "workflow_node.deploy.form.aliyun_alb_loadbalancer_id.tooltip": "For more information, see https://slb.console.aliyun.com/alb ",
+ "workflow_node.deploy.form.aliyun_alb_listener_id.label": "Aliyun ALB Listener ID",
+ "workflow_node.deploy.form.aliyun_alb_listener_id.placeholder": "Please enter Aliyun ALB listener ID",
+ "workflow_node.deploy.form.aliyun_alb_listener_id.tooltip": "For more information, see https://slb.console.aliyun.com/alb ",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.label": "Resource Type",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.option.loadbalancer.label": "CLB Load Balancer",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.option.listener.label": "CLB Listener",
+ "workflow_node.deploy.form.aliyun_clb_region.label": "Aliyun Region",
+ "workflow_node.deploy.form.aliyun_clb_region.placeholder": "Please enter Aliyun region (e.g. cn-hangzhou)",
+ "workflow_node.deploy.form.aliyun_clb_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/slb/classic-load-balancer/product-overview/regions-that-support-clb ",
+ "workflow_node.deploy.form.aliyun_clb_loadbalancer_id.label": "Aliyun CLB Load Balancer ID",
+ "workflow_node.deploy.form.aliyun_clb_loadbalancer_id.placeholder": "Please enter Aliyun CLB load balancer ID",
+ "workflow_node.deploy.form.aliyun_clb_loadbalancer_id.tooltip": "For more information, see https://slb.console.aliyun.com/clb ",
+ "workflow_node.deploy.form.aliyun_clb_listener_port.label": "Aliyun CLB Listener Port",
+ "workflow_node.deploy.form.aliyun_clb_listener_port.placeholder": "Please enter Aliyun CLB listener port",
+ "workflow_node.deploy.form.aliyun_clb_listener_port.tooltip": "For more information, see https://slb.console.aliyun.com/clb ",
+ "workflow_node.deploy.form.aliyun_cdn_domain.label": "Aliyun CDN Domain",
+ "workflow_node.deploy.form.aliyun_cdn_domain.placeholder": "Please enter Aliyun CDN domain name",
+ "workflow_node.deploy.form.aliyun_cdn_domain.tooltip": "For more information, see https://cdn.console.aliyun.com ",
+ "workflow_node.deploy.form.aliyun_dcdn_domain.label": "Aliyun DCDN Domain",
+ "workflow_node.deploy.form.aliyun_dcdn_domain.placeholder": "Please enter Aliyun DCDN domain name",
+ "workflow_node.deploy.form.aliyun_dcdn_domain.tooltip": "For more information, see https://dcdn.console.aliyun.com ",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.label": "Resource Type",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.option.loadbalancer.label": "NLB Load Balancer",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.option.listener.label": "NLB Listener",
+ "workflow_node.deploy.form.aliyun_nlb_region.label": "Aliyun Region",
+ "workflow_node.deploy.form.aliyun_nlb_region.placeholder": "Please enter Aliyun region (e.g. cn-hangzhou)",
+ "workflow_node.deploy.form.aliyun_nlb_region.tooltip": "For more information, see https://www.alibabacloud.com/help/en/slb/network-load-balancer/product-overview/regions-that-support-nlb ",
+ "workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.label": "Aliyun NLB Load Balancer ID",
+ "workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.placeholder": "Please enter Aliyun NLB load balancer ID",
+ "workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.tooltip": "For more information, see https://slb.console.aliyun.com/nlb ",
+ "workflow_node.deploy.form.aliyun_nlb_listener_id.label": "Aliyun NLB Listener ID",
+ "workflow_node.deploy.form.aliyun_nlb_listener_id.placeholder": "Please enter Aliyun NLB listener ID",
+ "workflow_node.deploy.form.aliyun_nlb_listener_id.tooltip": "For more information, see https://slb.console.aliyun.com/nlb ",
+ "workflow_node.deploy.form.aliyun_oss_endpoint.label": "Aliyun OSS Endpoint",
+ "workflow_node.deploy.form.aliyun_oss_endpoint.placeholder": "Please enter Aliyun OSS endpoint",
+ "workflow_node.deploy.form.aliyun_oss_endpoint.tooltip": "For more information, see https://www.alibabacloud.com/help/en/oss/user-guide/regions-and-endpoints ",
+ "workflow_node.deploy.form.aliyun_oss_bucket.label": "Aliyun OSS Bucket",
+ "workflow_node.deploy.form.aliyun_oss_bucket.placeholder": "Please enter Aliyun OSS bucket name",
+ "workflow_node.deploy.form.aliyun_oss_bucket.tooltip": "For more information, see https://oss.console.aliyun.com ",
+ "workflow_node.deploy.form.aliyun_oss_domain.label": "Aliyun OSS Domain",
+ "workflow_node.deploy.form.aliyun_oss_domain.placeholder": "Please enter Aliyun OSS domain name",
+ "workflow_node.deploy.form.aliyun_oss_domain.tooltip": "For more information, see https://oss.console.aliyun.com ",
+ "workflow_node.deploy.form.baiducloud_cdn_domain.label": "Baidu Cloud CDN Domain",
+ "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "Please enter Baidu Cloud CDN domain name",
+ "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "For more information, see https://console.bce.baidu.com/cdn ",
+ "workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN Domain",
+ "workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "Please enter BytePlus CDN domain name",
+ "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "For more information, see https://console.byteplus.com/cdn ",
+ "workflow_node.deploy.form.dogecloud_cdn_domain.label": "Doge Cloud CDN Domain",
+ "workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "Please enter Doge Cloud CDN domain name",
+ "workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "For more information, see https://console.dogecloud.com/ ",
+ "workflow_node.deploy.form.huaweicloud_cdn_region.label": "Huawei Cloud Region",
+ "workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "Please enter Huawei Cloud region (e.g. cn-north-1)",
+ "workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint ",
+ "workflow_node.deploy.form.huaweicloud_cdn_domain.label": "Huawei Cloud CDN Domain",
+ "workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "Please enter Huawei Cloud CDN domain name",
+ "workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "For more information, see https://console-intl.huaweicloud.com/cdn ",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.label": "Resource Type",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.option.certificate.label": "ELB Certificate",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "ELB Load Balancer",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.option.listener.label": "ELB Listener",
+ "workflow_node.deploy.form.huaweicloud_elb_region.label": "Huawei Cloud Region",
+ "workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "Please enter Huawei Cloud region (e.g. cn-north-1)",
+ "workflow_node.deploy.form.huaweicloud_elb_region.tooltip": "For more information, see https://console-intl.huaweicloud.com/apiexplorer/#/endpoint ",
+ "workflow_node.deploy.form.huaweicloud_elb_certificate_id.label": "Huawei Cloud ELB Certificate ID",
+ "workflow_node.deploy.form.huaweicloud_elb_certificate_id.placeholder": "Please enter Huawei Cloud ELB certificate ID",
+ "workflow_node.deploy.form.huaweicloud_elb_certificate_id.tooltip": "For more information, see https://console-intl.huaweicloud.com/vpc/#/elb/elbCert ",
+ "workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.label": "Huawei Cloud ELB Load Balancer ID",
+ "workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.placeholder": "Please enter Huawei Cloud ELB load balancer ID",
+ "workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.tooltip": "For more information, see https://console-intl.huaweicloud.com/vpc/#/elb/list/grid ",
+ "workflow_node.deploy.form.huaweicloud_elb_listener_id.label": "Huawei Cloud ELB Listener ID",
+ "workflow_node.deploy.form.huaweicloud_elb_listener_id.placeholder": "Please enter Huawei Cloud ELB listener ID",
+ "workflow_node.deploy.form.huaweicloud_elb_listener_id.tooltip": "For more information, see https://console-intl.huaweicloud.com/vpc/#/elb/list/grid ",
+ "workflow_node.deploy.form.k8s_namespace.label": "Kubernetes Namespace",
+ "workflow_node.deploy.form.k8s_namespace.placeholder": "Please enter Kubernetes namespace",
+ "workflow_node.deploy.form.k8s_namespace.tooltip": "For more information, see https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ ",
+ "workflow_node.deploy.form.k8s_secret_name.label": "Kubernetes Secret Name",
+ "workflow_node.deploy.form.k8s_secret_name.placeholder": "Please enter Kubernetes secret name",
+ "workflow_node.deploy.form.k8s_secret_name.tooltip": "For more information, see https://kubernetes.io/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_crt.label": "Kubernetes Secret Data Key for Certificate",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_crt.placeholder": "Please enter secret data key for certificate",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_crt.tooltip": "For more information, see https://kubernetes.io/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_key.label": "Kubernetes Secret Data Key for Private Key",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder": "Please enter secret data key for private key",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_key.tooltip": "For more information, see https://kubernetes.io/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.local_format.label": "File Format",
+ "workflow_node.deploy.form.local_format.placeholder": "Please select file format",
+ "workflow_node.deploy.form.local_format.option.pem.label": "PEM (*.pem, *.crt, *.key)",
+ "workflow_node.deploy.form.local_format.option.pfx.label": "PFX (*.pfx)",
+ "workflow_node.deploy.form.local_format.option.jks.label": "JKS (*.jks)",
+ "workflow_node.deploy.form.local_cert_path.label": "Certificate File Saving Path",
+ "workflow_node.deploy.form.local_cert_path.placeholder": "Please enter saving path for certificate file",
+ "workflow_node.deploy.form.local_cert_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
+ "workflow_node.deploy.form.local_key_path.label": "Private Key File Saving Path",
+ "workflow_node.deploy.form.local_key_path.placeholder": "Please enter saving path for private key file",
+ "workflow_node.deploy.form.local_key_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
+ "workflow_node.deploy.form.local_pfx_password.label": "PFX Output Password",
+ "workflow_node.deploy.form.local_pfx_password.placeholder": "Please enter PFX output password",
+ "workflow_node.deploy.form.local_jks_alias.label": "JKS Alias (KeyStore Alias)",
+ "workflow_node.deploy.form.local_jks_alias.placeholder": "Please enter JKS alias",
+ "workflow_node.deploy.form.local_jks_keypass.label": "JKS Key Password (KeyStore Keypass)",
+ "workflow_node.deploy.form.local_jks_keypass.placeholder": "Please enter JKS key password",
+ "workflow_node.deploy.form.local_jks_storepass.label": "JKS Store Password (KeyStore Storepass)",
+ "workflow_node.deploy.form.local_jks_storepass.placeholder": "Please enter JKS store password",
+ "workflow_node.deploy.form.local_shell_env.label": "Shell",
+ "workflow_node.deploy.form.local_shell_env.placeholder": "Please select shell environment",
+ "workflow_node.deploy.form.local_shell_env.option.sh.label": "POSIX Bash (on Linux / macOS)",
+ "workflow_node.deploy.form.local_shell_env.option.cmd.label": "CMD (on Windows)",
+ "workflow_node.deploy.form.local_shell_env.option.powershell.label": "PowerShell (on Windows)",
+ "workflow_node.deploy.form.local_pre_command.label": "Pre-Command",
+ "workflow_node.deploy.form.local_pre_command.placeholder": "Please enter command to be executed before saving files",
+ "workflow_node.deploy.form.local_post_command.label": "Post-Command",
+ "workflow_node.deploy.form.local_post_command.placeholder": "Please enter command to be executed after saving files",
+ "workflow_node.deploy.form.local_preset_scripts.button": "Use Preset Scripts",
+ "workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label": "POSIX Bash - Reload Nginx",
+ "workflow_node.deploy.form.local_preset_scripts.option.binding_iis.label": "PowerShell - Binding IIS",
+ "workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label": "PowerShell - Binding netsh",
+ "workflow_node.deploy.form.qiniu_cdn_domain.label": "Qiniu CDN Domain",
+ "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "Please enter Qiniu CDN domain name",
+ "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "For more information, see https://portal.qiniu.com/ ",
+ "workflow_node.deploy.form.ssh_format.label": "File Format",
+ "workflow_node.deploy.form.ssh_format.placeholder": "Please select file format",
+ "workflow_node.deploy.form.ssh_format.option.pem.label": "PEM (*.pem, *.crt, *.key)",
+ "workflow_node.deploy.form.ssh_format.option.pfx.label": "PFX (*.pfx)",
+ "workflow_node.deploy.form.ssh_format.option.jks.label": "JKS (*.jks)",
+ "workflow_node.deploy.form.ssh_cert_path.label": "Certificate File Uploading Path",
+ "workflow_node.deploy.form.ssh_cert_path.placeholder": "Please enter uploading path for certificate file",
+ "workflow_node.deploy.form.ssh_cert_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
+ "workflow_node.deploy.form.ssh_key_path.label": "Private Key File Uploading Path",
+ "workflow_node.deploy.form.ssh_key_path.placeholder": "Please enter uploading path for private key file",
+ "workflow_node.deploy.form.ssh_key_path.tooltip": "Note that the path should include the complete file name, not just the directory.",
+ "workflow_node.deploy.form.ssh_pfx_password.label": "PFX Output Password",
+ "workflow_node.deploy.form.ssh_pfx_password.placeholder": "Please enter PFX output password",
+ "workflow_node.deploy.form.ssh_jks_alias.label": "JKS Alias (KeyStore Alias)",
+ "workflow_node.deploy.form.ssh_jks_alias.placeholder": "Please enter JKS alias",
+ "workflow_node.deploy.form.ssh_jks_keypass.label": "JKS Key Password (KeyStore Keypass)",
+ "workflow_node.deploy.form.ssh_jks_keypass.placeholder": "Please enter JKS key password",
+ "workflow_node.deploy.form.ssh_jks_storepass.label": "JKS Store Password (KeyStore Storepass)",
+ "workflow_node.deploy.form.ssh_jks_storepass.placeholder": "Please enter JKS store password",
+ "workflow_node.deploy.form.ssh_shell_env.label": "Shell",
+ "workflow_node.deploy.form.ssh_shell_env.value": "POSIX Bash (on Linux / macOS)",
+ "workflow_node.deploy.form.ssh_pre_command.label": "Pre-Command",
+ "workflow_node.deploy.form.ssh_pre_command.placeholder": "Please enter command to be executed before uploading files",
+ "workflow_node.deploy.form.ssh_post_command.label": "Post-Command",
+ "workflow_node.deploy.form.ssh_post_command.placeholder": "Please enter command to be executed after uploading files",
+ "workflow_node.deploy.form.ssh_preset_scripts.button": "Use Preset Scripts",
+ "workflow_node.deploy.form.ssh_preset_scripts.option.reload_nginx.label": "POSIX Bash - Reload Nginx",
+ "workflow_node.deploy.form.tencentcloud_cdn_domain.label": "Tencent Cloud CDN Domain",
+ "workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder": "Please enter Tencent Cloud CDN domain name",
+ "workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "For more information, see https://console.tencentcloud.com/cdn ",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.label": "Resource Type",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder": "Please select resource type",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ssl_deploy.label": "Through SSL Deploy",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.loadbalancer.label": "CLB Load Balancer",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.listener.label": "CLB Listener",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ruledomain.label": "CLB Rule Domain",
+ "workflow_node.deploy.form.tencentcloud_clb_region.label": "Tencent Cloud Region",
+ "workflow_node.deploy.form.tencentcloud_clb_region.placeholder": "Please enter Tencent Cloud region (e.g. ap-guangzhou)",
+ "workflow_node.deploy.form.tencentcloud_clb_region.tooltip": "For more information, see https://www.tencentcloud.com/document/product/214/13629 ",
+ "workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.label": "Tencent Cloud CLB Instance ID",
+ "workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.placeholder": "Please enter Tencent Cloud CLB instance ID",
+ "workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.tooltip": "For more information, see https://console.tencentcloud.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_clb_listener_id.label": "Tencent Cloud CLB Listener ID",
+ "workflow_node.deploy.form.tencentcloud_clb_listener_id.placeholder": "Please enter Tencent Cloud CLB listener ID",
+ "workflow_node.deploy.form.tencentcloud_clb_listener_id.tooltip": "For more information, see https://console.tencentcloud.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_clb_snidomain.label": "Tencent Cloud CLB Domain (Optional)",
+ "workflow_node.deploy.form.tencentcloud_clb_snidomain.placeholder": "Please enter Tencent Cloud CLB domain name",
+ "workflow_node.deploy.form.tencentcloud_clb_snidomain.tooltip": "For more information, see https://console.tencentcloud.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_clb_ruledomain.label": "Tencent Cloud CLB Domain",
+ "workflow_node.deploy.form.tencentcloud_clb_ruledomain.placeholder": "Please enter Tencent Cloud CLB domain name",
+ "workflow_node.deploy.form.tencentcloud_clb_ruledomain.tooltip": "For more information, see https://console.tencentcloud.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_cos_region.label": "Tencent Cloud Region",
+ "workflow_node.deploy.form.tencentcloud_cos_region.placeholder": "Please enter Tencent Cloud region (e.g. ap-guangzhou)",
+ "workflow_node.deploy.form.tencentcloud_cos_region.tooltip": "For more information, see https://www.tencentcloud.com/document/product/436/6224 ",
+ "workflow_node.deploy.form.tencentcloud_cos_bucket.label": "Tencent Cloud COS Bucket",
+ "workflow_node.deploy.form.tencentcloud_cos_bucket.placeholder": "Please enter Tencent Cloud COS bucket name",
+ "workflow_node.deploy.form.tencentcloud_cos_bucket.tooltip": "For more information, see https://console.tencentcloud.com/cos ",
+ "workflow_node.deploy.form.tencentcloud_cos_domain.label": "Tencent Cloud COS Domain",
+ "workflow_node.deploy.form.tencentcloud_cos_domain.placeholder": "Please enter Tencent Cloud COS domain name",
+ "workflow_node.deploy.form.tencentcloud_cos_domain.tooltip": "For more information, see https://console.tencentcloud.com/cos ",
+ "workflow_node.deploy.form.tencentcloud_ecdn_domain.label": "Tencent Cloud ECDN Domain",
+ "workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder": "Please enter Tencent Cloud ECDN domain name",
+ "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "For more information, see https://console.tencentcloud.com/cdn ",
+ "workflow_node.deploy.form.tencentcloud_eo_zone_id.label": "Tencent Cloud EdgeOne Zone ID",
+ "workflow_node.deploy.form.tencentcloud_eo_zone_id.placeholder": "Please enter Tencent Cloud EdgeOne zone ID",
+ "workflow_node.deploy.form.tencentcloud_eo_zone_id.tooltip": "For more information, see https://console.tencentcloud.com/edgeone ",
+ "workflow_node.deploy.form.tencentcloud_eo_domain.label": "Tencent Cloud EdgeOne Domain",
+ "workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "Please enter Tencent Cloud EdgeOne domain name",
+ "workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "For more information, see https://console.tencentcloud.com/edgeone ",
+ "workflow_node.deploy.form.volcengine_cdn_domain.label": "VolcEngine CDN Domain",
+ "workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "Please enter VolcEngine CDN domain name",
+ "workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "For more information, see https://console.volcengine.com/cdn/homepage ",
+ "workflow_node.deploy.form.volcengine_live_domain.label": "VolcEngine Live Streaming Domain",
+ "workflow_node.deploy.form.volcengine_live_domain.placeholder": "Please enter VolcEngine live streaming domain name",
+ "workflow_node.deploy.form.volcengine_live_domain.tooltip": "For more information, see https://console.volcengine.com/live ",
+ "workflow_node.deploy.form.webhook_data.label": "Webhook Data (JSON format)",
+ "workflow_node.deploy.form.webhook_data.placeholder": "Please enter Webhook data",
+
+ "workflow_node.deploy.form.params_config.label": "Parameter Settings",
+ "workflow_node.notify.form.subject.label": "Subject",
+ "workflow_node.notify.form.subject.placeholder": "Please enter subject",
+ "workflow_node.notify.form.message.label": "Message",
+ "workflow_node.notify.form.message.placeholder": "Please enter message",
+ "workflow_node.notify.form.channel.label": "Channel",
+ "workflow_node.notify.form.channel.placeholder": "Please select channel",
+ "workflow_node.notify.form.channel.button": "Configure"
+}
diff --git a/ui/src/i18n/locales/en/nls.workflow.runs.json b/ui/src/i18n/locales/en/nls.workflow.runs.json
new file mode 100644
index 00000000..8fe4d1d1
--- /dev/null
+++ b/ui/src/i18n/locales/en/nls.workflow.runs.json
@@ -0,0 +1,9 @@
+{
+ "workflow_run.props.id": "ID",
+ "workflow_run.props.status": "Status",
+ "workflow_run.props.status.succeeded": "Succeeded",
+ "workflow_run.props.status.failed": "Failed",
+ "workflow_run.props.trigger": "Trigger",
+ "workflow_run.props.started_at": "Started At",
+ "workflow_run.props.completed_at": "Completed At"
+}
diff --git a/ui/src/i18n/locales/zh/index.ts b/ui/src/i18n/locales/zh/index.ts
index b23a3bf7..0ffa606b 100644
--- a/ui/src/i18n/locales/zh/index.ts
+++ b/ui/src/i18n/locales/zh/index.ts
@@ -5,6 +5,8 @@ import nlsSettings from "./nls.settings.json";
import nlsDomain from "./nls.domain.json";
import nlsAccess from "./nls.access.json";
import nlsWorkflow from "./nls.workflow.json";
+import nlsWorkflowNodes from "./nls.workflow.nodes.json";
+import nlsWorkflowRuns from "./nls.workflow.runs.json";
import nlsCertificate from "./nls.certificate.json";
export default Object.freeze({
@@ -15,5 +17,7 @@ export default Object.freeze({
...nlsDomain,
...nlsAccess,
...nlsWorkflow,
+ ...nlsWorkflowNodes,
+ ...nlsWorkflowRuns,
...nlsCertificate,
});
diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json
index 0de78b3c..72efc7d9 100644
--- a/ui/src/i18n/locales/zh/nls.access.json
+++ b/ui/src/i18n/locales/zh/nls.access.json
@@ -5,7 +5,7 @@
"access.action.add": "新建授权",
"access.action.edit": "编辑授权",
- "access.action.copy": "复制授权",
+ "access.action.duplicate": "复制授权",
"access.action.delete": "删除授权",
"access.action.delete.confirm": "确定要删除此授权吗?",
@@ -84,7 +84,7 @@
"access.form.huaweicloud_secret_access_key.label": "华为云 Secret Access Key",
"access.form.huaweicloud_secret_access_key.placeholder": "请输入华为云 Secret Access Key",
"access.form.huaweicloud_secret_access_key.tooltip": "这是什么?请参阅 https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html ",
- "access.form.huaweicloud_region.label": "华为云 DNS 产品区域",
+ "access.form.huaweicloud_region.label": "华为云区域",
"access.form.huaweicloud_region.placeholder": "请输入华为云区域(例如:cn-north-1)",
"access.form.huaweicloud_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint ",
"access.form.k8s_kubeconfig.label": "KubeConfig",
diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json
index 44d4e2ea..8d3fc779 100644
--- a/ui/src/i18n/locales/zh/nls.common.json
+++ b/ui/src/i18n/locales/zh/nls.common.json
@@ -47,7 +47,7 @@
"common.provider.baiducloud": "百度智能云",
"common.provider.baiducloud.cdn": "百度智能云 - 内容分发网络 CDN",
"common.provider.byteplus": "BytePlus",
- "common.provider.byteplus.cdn": "BytePlus - CDN",
+ "common.provider.byteplus.cdn": "BytePlus - 内容分发网络 CDN",
"common.provider.cloudflare": "Cloudflare",
"common.provider.dogecloud": "多吉云",
"common.provider.dogecloud.cdn": "多吉云 - 内容分发网络 CDN",
@@ -71,8 +71,8 @@
"common.provider.tencentcloud.ecdn": "腾讯云 - 全站加速网络 ECDN",
"common.provider.tencentcloud.eo": "腾讯云 - 边缘安全加速平台 EdgeOne",
"common.provider.volcengine": "火山引擎",
- "common.provider.volcengine.cdn": "火山引擎 - CDN",
- "common.provider.volcengine.live": "火山引擎 - 视频直播",
+ "common.provider.volcengine.cdn": "火山引擎 - 内容分发网络 CDN",
+ "common.provider.volcengine.live": "火山引擎 - 视频直播 Live",
"common.provider.webhook": "Webhook",
"common.notifier.bark": "Bark",
diff --git a/ui/src/i18n/locales/zh/nls.workflow.json b/ui/src/i18n/locales/zh/nls.workflow.json
index 728a6d56..06935159 100644
--- a/ui/src/i18n/locales/zh/nls.workflow.json
+++ b/ui/src/i18n/locales/zh/nls.workflow.json
@@ -29,59 +29,6 @@
"workflow.baseinfo.form.description.label": "描述",
"workflow.baseinfo.form.description.placeholder": "请输入工作流描述",
- "workflow.nodes.start.form.trigger.label": "触发方式",
- "workflow.nodes.start.form.trigger.placeholder": "请选择触发方式",
- "workflow.nodes.start.form.trigger.tooltip": "自动触发:基于 Cron 表达式定时触发。 手动触发:手动点击执行触发。",
- "workflow.nodes.start.form.trigger.option.auto.label": "自动触发",
- "workflow.nodes.start.form.trigger.option.manual.label": "手动触发",
- "workflow.nodes.start.form.trigger_cron.label": "Cron 表达式",
- "workflow.nodes.start.form.trigger_cron.placeholder": "请输入 Cron 表达式",
- "workflow.nodes.start.form.trigger_cron.errmsg.invalid": "请输入正确的 Cron 表达式",
- "workflow.nodes.start.form.trigger_cron.tooltip": "时区以服务器设置为准。",
- "workflow.nodes.start.form.trigger_cron.extra": "预计最近 5 次执行时间:",
- "workflow.nodes.start.form.trigger_cron_alert.content": "小贴士:如果你有多个工作流,建议将它们设置为在一天中的多个时间段运行,而非总是在相同的特定时间。 参考链接: 1. Let’s Encrypt 速率限制 2. 为什么我的 Let’s Encrypt (ACME) 客户端启动时间应当随机? ",
- "workflow.nodes.apply.form.domains.label": "域名",
- "workflow.nodes.apply.form.domains.placeholder": "请输入域名(多个值请用半角分号隔开)",
- "workflow.nodes.apply.form.domains.tooltip": "泛域名表示形式为:*.example.com",
- "workflow.nodes.apply.form.domains.multiple_input_modal.title": "修改域名",
- "workflow.nodes.apply.form.domains.multiple_input_modal.placeholder": "请输入域名",
- "workflow.nodes.apply.form.email.label": "联系邮箱",
- "workflow.nodes.apply.form.email.placeholder": "请输入联系邮箱",
- "workflow.nodes.apply.form.email.tooltip": "申请签发 SSL 证书时所需的联系方式。请注意 Let's Encrypt 账户注册的速率限制(点此了解更多) 。",
- "workflow.nodes.apply.form.access.label": "DNS 提供商授权",
- "workflow.nodes.apply.form.access.placeholder": "请选择 DNS 提供商授权",
- "workflow.nodes.apply.form.access.tooltip": "用于 ACME DNS-01 认证时操作域名解析记录,注意与部署阶段所需的主机提供商相区分。",
- "workflow.nodes.apply.form.access.button": "新建",
- "workflow.nodes.apply.form.advanced_settings.label": "高级设置",
- "workflow.nodes.apply.form.key_algorithm.label": "数字证书算法",
- "workflow.nodes.apply.form.key_algorithm.placeholder": "请选择数字证书算法",
- "workflow.nodes.apply.form.nameservers.label": "DNS 递归服务器",
- "workflow.nodes.apply.form.nameservers.placeholder": "请输入 DNS 递归服务器(多个值请用半角分号隔开)",
- "workflow.nodes.apply.form.nameservers.tooltip": "在 ACME DNS-01 认证时使用自定义的 DNS 递归服务器。如果你不了解该选项的用途,保持默认即可。",
- "workflow.nodes.apply.form.nameservers.multiple_input_modal.title": "修改 DNS 递归服务器",
- "workflow.nodes.apply.form.nameservers.multiple_input_modal.placeholder": "请输入 DNS 递归服务器",
- "workflow.nodes.apply.form.propagation_timeout.label": "DNS 传播检查超时时间",
- "workflow.nodes.apply.form.propagation_timeout.placeholder": "请输入 DNS 传播检查超时时间",
- "workflow.nodes.apply.form.propagation_timeout.suffix": "秒",
- "workflow.nodes.apply.form.propagation_timeout.tooltip": "在 ACME DNS-01 认证时等待 DNS 传播检查的最长时间。如果你不了解此选项的用途,保持默认即可。",
- "workflow.nodes.apply.form.disable_follow_cname.label": "禁止 CNAME 跟随",
- "workflow.nodes.apply.form.disable_follow_cname.tooltip": "在 ACME DNS-01 认证时是否禁止 CNAME 跟随。如果你不了解该选项的用途,保持默认即可。点此了解更多 。",
- "workflow.nodes.notify.form.subject.label": "通知主题",
- "workflow.nodes.notify.form.subject.placeholder": "请输入通知主题",
- "workflow.nodes.notify.form.message.label": "通知内容",
- "workflow.nodes.notify.form.message.placeholder": "请输入通知内容",
- "workflow.nodes.notify.form.channel.label": "通知渠道",
- "workflow.nodes.notify.form.channel.placeholder": "请选择通知渠道",
- "workflow.nodes.notify.form.channel.button": "去配置",
-
- "workflow_run.props.id": "ID",
- "workflow_run.props.status": "状态",
- "workflow_run.props.status.succeeded": "成功",
- "workflow_run.props.status.failed": "失败",
- "workflow_run.props.trigger": "触发方式",
- "workflow_run.props.started_at": "开始时间",
- "workflow_run.props.completed_at": "完成时间",
-
"workflow.detail.action.save": "保存变更",
"workflow.detail.action.save.failed": "保存失败",
"workflow.detail.action.save.failed.uncompleted": "请先完成流程编排并发布更改",
diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json
new file mode 100644
index 00000000..563a623e
--- /dev/null
+++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json
@@ -0,0 +1,269 @@
+{
+ "workflow_node.start.form.trigger.label": "触发方式",
+ "workflow_node.start.form.trigger.placeholder": "请选择触发方式",
+ "workflow_node.start.form.trigger.tooltip": "自动触发:基于 Cron 表达式定时触发。 手动触发:手动点击执行触发。",
+ "workflow_node.start.form.trigger.option.auto.label": "自动触发",
+ "workflow_node.start.form.trigger.option.manual.label": "手动触发",
+ "workflow_node.start.form.trigger_cron.label": "Cron 表达式",
+ "workflow_node.start.form.trigger_cron.placeholder": "请输入 Cron 表达式",
+ "workflow_node.start.form.trigger_cron.errmsg.invalid": "请输入正确的 Cron 表达式",
+ "workflow_node.start.form.trigger_cron.tooltip": "时区以服务器设置为准。",
+ "workflow_node.start.form.trigger_cron.extra": "预计最近 5 次执行时间:",
+ "workflow_node.start.form.trigger_cron_alert.content": "小贴士:如果你有多个工作流,建议将它们设置为在一天中的多个时间段运行,而非总是在相同的特定时间。 参考链接: 1. Let’s Encrypt 速率限制 2. 为什么我的 Let’s Encrypt (ACME) 客户端启动时间应当随机? ",
+
+ "workflow_node.apply.form.domains.label": "域名",
+ "workflow_node.apply.form.domains.placeholder": "请输入域名(多个值请用半角分号隔开)",
+ "workflow_node.apply.form.domains.tooltip": "泛域名表示形式为:*.example.com",
+ "workflow_node.apply.form.domains.multiple_input_modal.title": "修改域名",
+ "workflow_node.apply.form.domains.multiple_input_modal.placeholder": "请输入域名",
+ "workflow_node.apply.form.email.label": "联系邮箱",
+ "workflow_node.apply.form.email.placeholder": "请输入联系邮箱",
+ "workflow_node.apply.form.email.tooltip": "申请签发 SSL 证书时所需的联系方式。请注意 Let's Encrypt 账户注册的速率限制(点此了解更多) 。",
+ "workflow_node.apply.form.access.label": "DNS 提供商授权",
+ "workflow_node.apply.form.access.placeholder": "请选择 DNS 提供商授权",
+ "workflow_node.apply.form.access.tooltip": "用于 ACME DNS-01 认证时操作域名解析记录,注意与部署阶段所需的主机提供商相区分。",
+ "workflow_node.apply.form.access.button": "新建",
+ "workflow_node.apply.form.advanced_config.label": "高级设置",
+ "workflow_node.apply.form.key_algorithm.label": "数字证书算法",
+ "workflow_node.apply.form.key_algorithm.placeholder": "请选择数字证书算法",
+ "workflow_node.apply.form.nameservers.label": "DNS 递归服务器(可选)",
+ "workflow_node.apply.form.nameservers.placeholder": "请输入 DNS 递归服务器(多个值请用半角分号隔开)",
+ "workflow_node.apply.form.nameservers.tooltip": "在 ACME DNS-01 认证时使用自定义的 DNS 递归服务器。如果你不了解该选项的用途,保持默认即可。",
+ "workflow_node.apply.form.nameservers.multiple_input_modal.title": "修改 DNS 递归服务器",
+ "workflow_node.apply.form.nameservers.multiple_input_modal.placeholder": "请输入 DNS 递归服务器",
+ "workflow_node.apply.form.propagation_timeout.label": "DNS 传播检查超时时间(可选)",
+ "workflow_node.apply.form.propagation_timeout.placeholder": "请输入 DNS 传播检查超时时间",
+ "workflow_node.apply.form.propagation_timeout.suffix": "秒",
+ "workflow_node.apply.form.propagation_timeout.tooltip": "在 ACME DNS-01 认证时等待 DNS 传播检查的最长时间。如果你不了解此选项的用途,保持默认即可。",
+ "workflow_node.apply.form.disable_follow_cname.label": "禁止 CNAME 跟随",
+ "workflow_node.apply.form.disable_follow_cname.tooltip": "在 ACME DNS-01 认证时是否禁止 CNAME 跟随。如果你不了解该选项的用途,保持默认即可。点此了解更多 。",
+
+ "workflow_node.deploy.form.provider_type.label": "部署目标",
+ "workflow_node.deploy.form.provider_type.placeholder": "请选择部署目标",
+ "workflow_node.deploy.form.provider_access.label": "主机提供商授权",
+ "workflow_node.deploy.form.provider_access.placeholder": "请选择主机提供商授权",
+ "workflow_node.deploy.form.provider_access.tooltip": "用于部署证书,注意与申请阶段所需的 DNS 提供商相区分。",
+ "workflow_node.deploy.form.provider_access.button": "新建",
+ "workflow_node.deploy.form.certificate.label": "待部署证书",
+ "workflow_node.deploy.form.certificate.placeholder": "请选择待部署证书",
+ "workflow_node.deploy.form.certificate.tooltip": "待部署证书来自之前的申请阶段。如果选项为空请先确保前序节点配置正确。",
+ "workflow_node.deploy.form.params_config.label": "参数设置",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.label": "证书替换方式",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书",
+ "workflow_node.deploy.form.aliyun_alb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
+ "workflow_node.deploy.form.aliyun_alb_region.label": "阿里云地域",
+ "workflow_node.deploy.form.aliyun_alb_region.placeholder": "请输入阿里云地域(例如:cn-hangzhou)",
+ "workflow_node.deploy.form.aliyun_alb_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/slb/application-load-balancer/product-overview/supported-regions-and-zones ",
+ "workflow_node.deploy.form.aliyun_alb_loadbalancer_id.label": "阿里云 ALB 负载均衡器 ID",
+ "workflow_node.deploy.form.aliyun_alb_loadbalancer_id.placeholder": "请输入阿里云 ALB 负载均衡器 ID",
+ "workflow_node.deploy.form.aliyun_alb_loadbalancer_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/alb ",
+ "workflow_node.deploy.form.aliyun_alb_listener_id.label": "阿里云 ALB 监听器 ID",
+ "workflow_node.deploy.form.aliyun_alb_listener_id.placeholder": "请输入阿里云 ALB 监听器 ID",
+ "workflow_node.deploy.form.aliyun_alb_listener_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/alb ",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.label": "证书替换方式",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听的证书",
+ "workflow_node.deploy.form.aliyun_clb_resource_type.option.listener.label": "替换指定负载均衡监听的证书",
+ "workflow_node.deploy.form.aliyun_clb_region.label": "阿里云地域",
+ "workflow_node.deploy.form.aliyun_clb_region.placeholder": "请输入阿里云地域(例如:cn-hangzhou)",
+ "workflow_node.deploy.form.aliyun_clb_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/slb/classic-load-balancer/product-overview/regions-that-support-clb ",
+ "workflow_node.deploy.form.aliyun_clb_loadbalancer_id.label": "阿里云 CLB 负载均衡器 ID",
+ "workflow_node.deploy.form.aliyun_clb_loadbalancer_id.placeholder": "请输入阿里云 CLB 负载均衡器 ID",
+ "workflow_node.deploy.form.aliyun_clb_loadbalancer_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/clb ",
+ "workflow_node.deploy.form.aliyun_clb_listener_id.label": "阿里云 CLB 监听端口",
+ "workflow_node.deploy.form.aliyun_clb_listener_id.placeholder": "请输入阿里云 CLB 监听端口",
+ "workflow_node.deploy.form.aliyun_clb_listener_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/clb ",
+ "workflow_node.deploy.form.aliyun_cdn_domain.label": "阿里云 CDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.aliyun_cdn_domain.placeholder": "请输入阿里云 CDN 加速域名",
+ "workflow_node.deploy.form.aliyun_cdn_domain.tooltip": "这是什么?请参阅 https://cdn.console.aliyun.com ",
+ "workflow_node.deploy.form.aliyun_dcdn_domain.label": "阿里云 DCDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.aliyun_dcdn_domain.placeholder": "请输入阿里云 DCDN 加速域名",
+ "workflow_node.deploy.form.aliyun_dcdn_domain.tooltip": "这是什么?请参阅 https://dcdn.console.aliyun.com ",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.label": "证书替换方式",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS/QUIC 监听的证书",
+ "workflow_node.deploy.form.aliyun_nlb_resource_type.option.listener.label": "替换指定负载均衡监听器的证书",
+ "workflow_node.deploy.form.aliyun_nlb_region.label": "阿里云地域",
+ "workflow_node.deploy.form.aliyun_nlb_region.placeholder": "请输入阿里云地域(例如:cn-hangzhou)",
+ "workflow_node.deploy.form.aliyun_nlb_region.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/slb/network-load-balancer/product-overview/regions-that-support-nlb ",
+ "workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.label": "阿里云 NLB 负载均衡器 ID",
+ "workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.placeholder": "请输入阿里云 NLB 负载均衡器 ID",
+ "workflow_node.deploy.form.aliyun_nlb_loadbalancer_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/nlb ",
+ "workflow_node.deploy.form.aliyun_nlb_listener_id.label": "阿里云 NLB 监听器 ID",
+ "workflow_node.deploy.form.aliyun_nlb_listener_id.placeholder": "请输入阿里云 NLB 监听器 ID",
+ "workflow_node.deploy.form.aliyun_nlb_listener_id.tooltip": "这是什么?请参阅 https://slb.console.aliyun.com/nlb ",
+ "workflow_node.deploy.form.aliyun_oss_endpoint.label": "阿里云 OSS Endpoint",
+ "workflow_node.deploy.form.aliyun_oss_endpoint.placeholder": "请输入阿里云 OSS Endpoint",
+ "workflow_node.deploy.form.aliyun_oss_endpoint.tooltip": "这是什么?请参阅 https://help.aliyun.com/zh/oss/user-guide/regions-and-endpoints ",
+ "workflow_node.deploy.form.aliyun_oss_bucket.label": "阿里云 OSS 存储桶名",
+ "workflow_node.deploy.form.aliyun_oss_bucket.placeholder": "请输入阿里云 OSS 存储桶名",
+ "workflow_node.deploy.form.aliyun_oss_bucket.tooltip": "这是什么?请参阅 https://oss.console.aliyun.com ",
+ "workflow_node.deploy.form.aliyun_oss_domain.label": "阿里云 OSS 自定义域名",
+ "workflow_node.deploy.form.aliyun_oss_domain.placeholder": "请输入阿里云 OSS 自定义域名",
+ "workflow_node.deploy.form.aliyun_oss_domain.tooltip": "这是什么?请参阅 see https://oss.console.aliyun.com ",
+ "workflow_node.deploy.form.baiducloud_cdn_domain.label": "百度智能云 CDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.baiducloud_cdn_domain.placeholder": "请输入百度智能云 CDN 加速域名",
+ "workflow_node.deploy.form.baiducloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.bce.baidu.com/cdn ",
+ "workflow_node.deploy.form.byteplus_cdn_domain.label": "BytePlus CDN 域名(支持泛域名)",
+ "workflow_node.deploy.form.byteplus_cdn_domain.placeholder": "请输入 BytePlus CDN 域名",
+ "workflow_node.deploy.form.byteplus_cdn_domain.tooltip": "这是什么?请参阅 https://console.byteplus.com/cdn ",
+ "workflow_node.deploy.form.dogecloud_cdn_domain.label": "多吉云 CDN 加速域名",
+ "workflow_node.deploy.form.dogecloud_cdn_domain.placeholder": "请输入多吉云 CDN 加速域名",
+ "workflow_node.deploy.form.dogecloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.dogecloud.com ",
+ "workflow_node.deploy.form.huaweicloud_cdn_region.label": "华为云区域",
+ "workflow_node.deploy.form.huaweicloud_cdn_region.placeholder": "请输入华为云区域(例如:cn-north-1)",
+ "workflow_node.deploy.form.huaweicloud_cdn_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint ",
+ "workflow_node.deploy.form.huaweicloud_cdn_domain.label": "华为云 CDN 加速域名",
+ "workflow_node.deploy.form.huaweicloud_cdn_domain.placeholder": "请输入华为云 CDN 加速域名",
+ "workflow_node.deploy.form.huaweicloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/cdn ",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.label": "证书替换方式",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.option.certificate.label": "替换指定证书",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.option.loadbalancer.label": "替换指定负载均衡器下的全部 HTTPS 监听器的证书",
+ "workflow_node.deploy.form.huaweicloud_elb_resource_type.option.listener.label": "替换指定监听器的证书",
+ "workflow_node.deploy.form.huaweicloud_elb_region.label": "华为云区域",
+ "workflow_node.deploy.form.huaweicloud_elb_region.placeholder": "请输入华为云区域(例如:cn-north-1)",
+ "workflow_node.deploy.form.huaweicloud_elb_region.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/apiexplorer/#/endpoint ",
+ "workflow_node.deploy.form.huaweicloud_elb_certificate_id.label": "华为云 ELB 证书 ID",
+ "workflow_node.deploy.form.huaweicloud_elb_certificate_id.placeholder": "请输入华为云 ELB 证书 ID",
+ "workflow_node.deploy.form.huaweicloud_elb_certificate_id.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/vpc/#/elb/elbCert ",
+ "workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.label": "华为云 ELB 负载均衡器 ID",
+ "workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.placeholder": "请输入华为云 ELB 负载均衡器 ID",
+ "workflow_node.deploy.form.huaweicloud_elb_loadbalancer_id.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/vpc/#/elb/list/grid ",
+ "workflow_node.deploy.form.huaweicloud_elb_listener_id.label": "华为云 ELB 监听器 ID",
+ "workflow_node.deploy.form.huaweicloud_elb_listener_id.placeholder": "请输入华为云 ELB 监听器 ID",
+ "workflow_node.deploy.form.huaweicloud_elb_listener_id.tooltip": "这是什么?请参阅 https://console.huaweicloud.com/vpc/#/elb/list/grid ",
+ "workflow_node.deploy.form.k8s_namespace.label": "Kubernetes 命名空间",
+ "workflow_node.deploy.form.k8s_namespace.placeholder": "请输入 Kubernetes 命名空间",
+ "workflow_node.deploy.form.k8s_namespace.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/overview/working-with-objects/namespaces/ ",
+ "workflow_node.deploy.form.k8s_secret_name.label": "Kubernetes Secret 名称",
+ "workflow_node.deploy.form.k8s_secret_name.placeholder": "请输入 Kubernetes Secret 名称",
+ "workflow_node.deploy.form.k8s_secret_name.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_crt.label": "Kubernetes Secret 数据键(用于存放证书的字段)",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_crt.placeholder": "请输入 Kubernetes Secret 中用于存放证书的数据键",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_crt.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_key.label": "Kubernetes Secret 数据键(用于存放私钥的字段)",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_key.placeholder": "请输入 Kubernetes Secret 中用于存放私钥的数据键",
+ "workflow_node.deploy.form.k8s_secret_data_key_for_key.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.local_format.label": "文件格式",
+ "workflow_node.deploy.form.local_format.placeholder": "请选择文件格式",
+ "workflow_node.deploy.form.local_format.option.pem.label": "PEM 格式(*.pem, *.crt, *.key)",
+ "workflow_node.deploy.form.local_format.option.pfx.label": "PFX 格式(*.pfx)",
+ "workflow_node.deploy.form.local_format.option.jks.label": "JKS 格式(*.jks)",
+ "workflow_node.deploy.form.local_cert_path.label": "证书文件保存路径",
+ "workflow_node.deploy.form.local_cert_path.placeholder": "请输入证书文件保存路径",
+ "workflow_node.deploy.form.local_cert_path.tooltip": "注意,路径需包含完整的文件名,而不是仅目录。",
+ "workflow_node.deploy.form.local_key_path.label": "私钥文件保存路径",
+ "workflow_node.deploy.form.local_key_path.placeholder": "请输入私钥文件保存路径",
+ "workflow_node.deploy.form.local_key_path.tooltip": "注意,路径需包含完整的文件名,而不是仅目录。",
+ "workflow_node.deploy.form.local_pfx_password.label": "PFX 导出密码",
+ "workflow_node.deploy.form.local_pfx_password.placeholder": "请输入 PFX 导出密码",
+ "workflow_node.deploy.form.local_jks_alias.label": "JKS 别名(KeyStore Alias)",
+ "workflow_node.deploy.form.local_jks_alias.placeholder": "请输入 JKS 别名",
+ "workflow_node.deploy.form.local_jks_keypass.label": "JKS 私钥访问口令(KeyStore Keypass)",
+ "workflow_node.deploy.form.local_jks_keypass.placeholder": "请输入 JKS 私钥访问口令",
+ "workflow_node.deploy.form.local_jks_storepass.label": "JKS 密钥库存储口令(KeyStore Storepass)",
+ "workflow_node.deploy.form.local_jks_storepass.placeholder": "请输入 JKS 密钥库存储口令",
+ "workflow_node.deploy.form.local_shell_env.label": "命令执行环境",
+ "workflow_node.deploy.form.local_shell_env.placeholder": "请选择命令执行环境",
+ "workflow_node.deploy.form.local_shell_env.option.sh.label": "POSIX Bash(Linux / macOS)",
+ "workflow_node.deploy.form.local_shell_env.option.cmd.label": "CMD(Windows)",
+ "workflow_node.deploy.form.local_shell_env.option.powershell.label": "PowerShell(Windows)",
+ "workflow_node.deploy.form.local_pre_command.label": "前置命令",
+ "workflow_node.deploy.form.local_pre_command.placeholder": "请输入保存文件前执行的命令",
+ "workflow_node.deploy.form.local_post_command.label": "后置命令",
+ "workflow_node.deploy.form.local_post_command.placeholder": "请输入保存文件后执行的命令",
+ "workflow_node.deploy.form.local_preset_scripts.button": "使用预设脚本",
+ "workflow_node.deploy.form.local_preset_scripts.option.reload_nginx.label": "POSIX Bash - 重启 nginx 进程",
+ "workflow_node.deploy.form.local_preset_scripts.option.binding_iis.label": "PowerShell - 导入并绑定到 IIS(需管理员权限)",
+ "workflow_node.deploy.form.local_preset_scripts.option.binding_netsh.label": "PowerShell - 导入并绑定到 netsh(需管理员权限)",
+ "workflow_node.deploy.form.qiniu_cdn_domain.label": "七牛云 CDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.qiniu_cdn_domain.placeholder": "请输入七牛云 CDN 加速域名",
+ "workflow_node.deploy.form.qiniu_cdn_domain.tooltip": "这是什么?请参阅 https://kubernetes.io/zh-cn/docs/concepts/configuration/secret/ ",
+ "workflow_node.deploy.form.ssh_format.label": "文件格式",
+ "workflow_node.deploy.form.ssh_format.placeholder": "请选择文件格式",
+ "workflow_node.deploy.form.ssh_format.option.pem.label": "PEM 格式(*.pem, *.crt, *.key)",
+ "workflow_node.deploy.form.ssh_format.option.pfx.label": "PFX 格式(*.pfx)",
+ "workflow_node.deploy.form.ssh_format.option.jks.label": "JKS 格式(*.jks)",
+ "workflow_node.deploy.form.ssh_cert_path.label": "证书文件上传路径",
+ "workflow_node.deploy.form.ssh_cert_path.placeholder": "请输入证书文件上传路径",
+ "workflow_node.deploy.form.ssh_cert_path.tooltip": "注意,路径需包含完整的文件名,而不是仅目录。",
+ "workflow_node.deploy.form.ssh_key_path.label": "私钥文件上传路径",
+ "workflow_node.deploy.form.ssh_key_path.placeholder": "请输入私钥文件上传路径",
+ "workflow_node.deploy.form.ssh_key_path.tooltip": "注意,路径需包含完整的文件名,而不是仅目录。",
+ "workflow_node.deploy.form.ssh_pfx_password.label": "PFX 导出密码",
+ "workflow_node.deploy.form.ssh_pfx_password.placeholder": "请输入 PFX 导出密码",
+ "workflow_node.deploy.form.ssh_jks_alias.label": "JKS 别名(KeyStore Alias)",
+ "workflow_node.deploy.form.ssh_jks_alias.placeholder": "请输入 JKS 别名",
+ "workflow_node.deploy.form.ssh_jks_keypass.label": "JKS 私钥访问口令(KeyStore Keypass)",
+ "workflow_node.deploy.form.ssh_jks_keypass.placeholder": "请输入 JKS 私钥访问口令",
+ "workflow_node.deploy.form.ssh_jks_storepass.label": "JKS 密钥库存储口令(KeyStore Storepass)",
+ "workflow_node.deploy.form.ssh_jks_storepass.placeholder": "请输入 JKS 密钥库存储口令",
+ "workflow_node.deploy.form.ssh_shell_env.label": "命令执行环境",
+ "workflow_node.deploy.form.ssh_shell_env.value": "POSIX Bash(Linux / macOS)",
+ "workflow_node.deploy.form.ssh_pre_command.label": "前置命令",
+ "workflow_node.deploy.form.ssh_pre_command.placeholder": "请输入保存文件前执行的命令",
+ "workflow_node.deploy.form.ssh_post_command.label": "后置命令",
+ "workflow_node.deploy.form.ssh_post_command.placeholder": "请输入保存文件后执行的命令",
+ "workflow_node.deploy.form.ssh_preset_scripts.button": "使用预设脚本",
+ "workflow_node.deploy.form.ssh_preset_scripts.option.reload_nginx.label": "POSIX Bash - 重启 nginx 进程",
+ "workflow_node.deploy.form.tencentcloud_cdn_domain.label": "腾讯云 CDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.tencentcloud_cdn_domain.placeholder": "请输入腾讯云 CDN 加速域名",
+ "workflow_node.deploy.form.tencentcloud_cdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn ",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.label": "证书替换方式",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.placeholder": "请选择证书替换方式",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ssl_deploy.label": "通过 SSL 服务部署到云资源实例",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.loadbalancer.label": "替换指定实例下的全部 HTTPS/TCPSSL/QUIC 监听器的证书",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.listener.label": "替换指定监听器的证书",
+ "workflow_node.deploy.form.tencentcloud_clb_resource_type.option.ruledomain.label": "替换指定七层监听转发规则域名的证书",
+ "workflow_node.deploy.form.tencentcloud_clb_region.label": "腾讯云地域",
+ "workflow_node.deploy.form.tencentcloud_clb_region.placeholder": "请输入腾讯云地域(例如:ap-guangzhou)",
+ "workflow_node.deploy.form.tencentcloud_clb_region.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/214/33415 ",
+ "workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.label": "腾讯云 CLB 实例 ID",
+ "workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.placeholder": "请输入腾讯云 CLB 实例 ID",
+ "workflow_node.deploy.form.tencentcloud_clb_loadbalancer_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_clb_listener_id.label": "腾讯云 CLB 监听器 ID",
+ "workflow_node.deploy.form.tencentcloud_clb_listener_id.placeholder": "请输入腾讯云 CLB 监听器 ID",
+ "workflow_node.deploy.form.tencentcloud_clb_listener_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_clb_snidomain.label": "腾讯云 CLB SNI 域名(可选)",
+ "workflow_node.deploy.form.tencentcloud_clb_snidomain.placeholder": "请输入腾讯云 CLB SNI 域名",
+ "workflow_node.deploy.form.tencentcloud_clb_snidomain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_clb_ruledomain.label": "腾讯云 CLB 七层转发规则域名",
+ "workflow_node.deploy.form.tencentcloud_clb_ruledomain.placeholder": "请输入腾讯云 CLB 七层转发规则域名",
+ "workflow_node.deploy.form.tencentcloud_clb_ruledomain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/clb ",
+ "workflow_node.deploy.form.tencentcloud_cos_region.label": "腾讯云地域",
+ "workflow_node.deploy.form.tencentcloud_cos_region.placeholder": "请输入腾讯云地域(例如:ap-guangzhou)",
+ "workflow_node.deploy.form.tencentcloud_cos_region.tooltip": "这是什么?请参阅 https://cloud.tencent.com/document/product/436/6224 ",
+ "workflow_node.deploy.form.tencentcloud_cos_bucket.label": "腾讯云 COS 存储桶名",
+ "workflow_node.deploy.form.tencentcloud_cos_bucket.placeholder": "请输入腾讯云 COS 存储桶名",
+ "workflow_node.deploy.form.tencentcloud_cos_bucket.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cos ",
+ "workflow_node.deploy.form.tencentcloud_cos_domain.label": "腾讯云 COS 自定义域名",
+ "workflow_node.deploy.form.tencentcloud_cos_domain.placeholder": "请输入腾讯云 COS 自定义域名",
+ "workflow_node.deploy.form.tencentcloud_cos_domain.tooltip": "这是什么?请参阅 see https://console.cloud.tencent.com/cos ",
+ "workflow_node.deploy.form.tencentcloud_ecdn_domain.label": "腾讯云 ECDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.tencentcloud_ecdn_domain.placeholder": "请输入腾讯云 ECDN 加速域名",
+ "workflow_node.deploy.form.tencentcloud_ecdn_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/cdn ",
+ "workflow_node.deploy.form.tencentcloud_eo_zone_id.label": "腾讯云 EdgeOne 站点 ID",
+ "workflow_node.deploy.form.tencentcloud_eo_zone_id.placeholder": "请输入腾讯云 EdgeOne 站点 ID",
+ "workflow_node.deploy.form.tencentcloud_eo_zone_id.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/edgeone ",
+ "workflow_node.deploy.form.tencentcloud_eo_domain.label": "腾讯云 EdgeOne 加速域名",
+ "workflow_node.deploy.form.tencentcloud_eo_domain.placeholder": "请输入腾讯云 EdgeOne 加速域名",
+ "workflow_node.deploy.form.tencentcloud_eo_domain.tooltip": "这是什么?请参阅 https://console.cloud.tencent.com/edgeone ",
+ "workflow_node.deploy.form.volcengine_cdn_domain.label": "火山引擎 CDN 加速域名(支持泛域名)",
+ "workflow_node.deploy.form.volcengine_cdn_domain.placeholder": "请输入火山引擎 CDN 加速域名",
+ "workflow_node.deploy.form.volcengine_cdn_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/cdn/homepage ",
+ "workflow_node.deploy.form.volcengine_live_domain.label": "火山引擎视频直播流域名(支持泛域名)",
+ "workflow_node.deploy.form.volcengine_live_domain.placeholder": "请输入火山引擎视频直播流域名",
+ "workflow_node.deploy.form.volcengine_live_domain.tooltip": "这是什么?请参阅 https://console.volcengine.com/live ",
+ "workflow_node.deploy.form.webhook_data.label": "Webhook 回调数据(JSON 格式)",
+ "workflow_node.deploy.form.webhook_data.placeholder": "请输入 Webhook 回调数据",
+
+ "workflow_node.notify.form.subject.label": "通知主题",
+ "workflow_node.notify.form.subject.placeholder": "请输入通知主题",
+ "workflow_node.notify.form.message.label": "通知内容",
+ "workflow_node.notify.form.message.placeholder": "请输入通知内容",
+ "workflow_node.notify.form.channel.label": "通知渠道",
+ "workflow_node.notify.form.channel.placeholder": "请选择通知渠道",
+ "workflow_node.notify.form.channel.button": "去配置"
+}
diff --git a/ui/src/i18n/locales/zh/nls.workflow.runs.json b/ui/src/i18n/locales/zh/nls.workflow.runs.json
new file mode 100644
index 00000000..ccd1df0b
--- /dev/null
+++ b/ui/src/i18n/locales/zh/nls.workflow.runs.json
@@ -0,0 +1,9 @@
+{
+ "workflow_run.props.id": "ID",
+ "workflow_run.props.status": "状态",
+ "workflow_run.props.status.succeeded": "成功",
+ "workflow_run.props.status.failed": "失败",
+ "workflow_run.props.trigger": "触发方式",
+ "workflow_run.props.started_at": "开始时间",
+ "workflow_run.props.completed_at": "完成时间"
+}
diff --git a/ui/src/pages/accesses/AccessList.tsx b/ui/src/pages/accesses/AccessList.tsx
index 5de49c06..a7c63991 100644
--- a/ui/src/pages/accesses/AccessList.tsx
+++ b/ui/src/pages/accesses/AccessList.tsx
@@ -13,7 +13,8 @@ import dayjs from "dayjs";
import { ClientResponseError } from "pocketbase";
import AccessEditModal from "@/components/access/AccessEditModal";
-import { accessProvidersMap, type AccessModel } from "@/domain/access";
+import { type AccessModel } from "@/domain/access";
+import { accessProvidersMap } from "@/domain/provider";
import { useAccessStore } from "@/stores/access";
import { getErrMsg } from "@/utils/error";
@@ -89,7 +90,7 @@ const AccessList = () => {
data={{ ...record, id: undefined, name: `${record.name}-copy` }}
preset="add"
trigger={
-
+
} variant="text" />
}
diff --git a/ui/src/utils/validators.ts b/ui/src/utils/validators.ts
index 75d57767..a31c3ebc 100644
--- a/ui/src/utils/validators.ts
+++ b/ui/src/utils/validators.ts
@@ -34,3 +34,7 @@ export const validHttpOrHttpsUrl = (value: string) => {
return false;
}
};
+
+export const validPortNumber = (value: string | number) => {
+ return parseInt(value + "") === +value && +value >= 1 && +value <= 65535;
+};