diff --git a/internal/applicant/applicant.go b/internal/applicant/applicant.go index 319443f9..56c3baeb 100644 --- a/internal/applicant/applicant.go +++ b/internal/applicant/applicant.go @@ -18,7 +18,6 @@ import ( "github.com/go-acme/lego/v4/challenge/dns01" "github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/registration" - "github.com/pocketbase/pocketbase/models" "github.com/usual2970/certimate/internal/app" "github.com/usual2970/certimate/internal/domain" @@ -57,12 +56,12 @@ type Certificate struct { } type ApplyOption struct { - Email string `json:"email"` SubjectAltNames string `json:"subjectAltNames"` + Email string `json:"email"` AccessConfig string `json:"accessConfig"` KeyAlgorithm string `json:"keyAlgorithm"` Nameservers string `json:"nameservers"` - PropagationTimeout int64 `json:"propagationTimeout"` + PropagationTimeout int32 `json:"propagationTimeout"` DisableFollowCNAME bool `json:"disableFollowCNAME"` } @@ -125,41 +124,11 @@ type Applicant interface { Apply() (*Certificate, error) } -func Get(record *models.Record) (Applicant, error) { - if record.GetString("applyConfig") == "" { - return nil, errors.New("applyConfig is empty") - } - - applyConfig := &domain.ApplyConfig{} - record.UnmarshalJSONField("applyConfig", applyConfig) - - access, err := app.GetApp().Dao().FindRecordById("access", applyConfig.Access) - if err != nil { - return nil, fmt.Errorf("access record not found: %w", err) - } - - if applyConfig.Email == "" { - applyConfig.Email = defaultEmail - } - - option := &ApplyOption{ - Email: applyConfig.Email, - SubjectAltNames: record.GetString("domain"), - AccessConfig: access.GetString("config"), - KeyAlgorithm: applyConfig.KeyAlgorithm, - Nameservers: applyConfig.Nameservers, - PropagationTimeout: applyConfig.PropagationTimeout, - DisableFollowCNAME: applyConfig.DisableFollowCNAME, - } - - return GetWithTypeOption(domain.AccessProviderType(access.GetString("provider")), option) -} - func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) { // 获取授权配置 accessRepo := repository.NewAccessRepository() - access, err := accessRepo.GetById(context.Background(), node.GetConfigString("access")) + access, err := accessRepo.GetById(context.Background(), node.GetConfigString("providerAccessId")) if err != nil { return nil, fmt.Errorf("access record not found: %w", err) } @@ -170,7 +139,7 @@ func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) { AccessConfig: access.Config, KeyAlgorithm: node.GetConfigString("keyAlgorithm"), Nameservers: node.GetConfigString("nameservers"), - PropagationTimeout: node.GetConfigInt64("propagationTimeout"), + PropagationTimeout: node.GetConfigInt32("propagationTimeout"), DisableFollowCNAME: node.GetConfigBool("disableFollowCNAME"), } diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index 30e454f4..a90dc1b8 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -49,7 +49,7 @@ const ( type DeployerOption struct { DomainId string `json:"domainId"` Domain string `json:"domain"` - Access string `json:"access"` + AccessConfig string `json:"accessConfig"` AccessRecord *domain.Access `json:"-"` DeployConfig domain.DeployConfig `json:"deployConfig"` Certificate applicant.Certificate `json:"certificate"` @@ -97,7 +97,7 @@ func GetWithTypeAndOption(deployType string, option *DeployerOption) (Deployer, func newWithDeployConfig(record *models.Record, cert *applicant.Certificate, deployConfig domain.DeployConfig) (Deployer, error) { accessRepo := repository.NewAccessRepository() - access, err := accessRepo.GetById(context.Background(), deployConfig.Access) + access, err := accessRepo.GetById(context.Background(), deployConfig.ProviderAccessId) if err != nil { return nil, fmt.Errorf("获取access失败:%w", err) } @@ -105,7 +105,7 @@ func newWithDeployConfig(record *models.Record, cert *applicant.Certificate, dep option := &DeployerOption{ DomainId: record.Id, Domain: record.GetString("domain"), - Access: access.Config, + AccessConfig: access.Config, AccessRecord: access, DeployConfig: deployConfig, } @@ -118,11 +118,11 @@ func newWithDeployConfig(record *models.Record, cert *applicant.Certificate, dep } } - return newWithTypeAndOption(deployConfig.Type, option) + return newWithTypeAndOption(deployConfig.Provider, option) } func newWithTypeAndOption(deployType string, option *DeployerOption) (Deployer, error) { - deployer, logger, err := createDeployer(deployType, option.AccessRecord.Config, option.DeployConfig.Config) + deployer, logger, err := createDeployer(deployType, option.AccessRecord.Config, option.DeployConfig.NodeConfig) if err != nil { return nil, err } diff --git a/internal/domain/domains.go b/internal/domain/domains.go index 287046ed..6ca5cbd3 100644 --- a/internal/domain/domains.go +++ b/internal/domain/domains.go @@ -3,17 +3,17 @@ package domain // Deprecated: TODO: 即将废弃 type ApplyConfig struct { Email string `json:"email"` - Access string `json:"access"` + ProviderAccessId string `json:"providerAccessId"` KeyAlgorithm string `json:"keyAlgorithm"` Nameservers string `json:"nameservers"` - PropagationTimeout int64 `json:"propagationTimeout"` + PropagationTimeout int32 `json:"propagationTimeout"` DisableFollowCNAME bool `json:"disableFollowCNAME"` } // Deprecated: TODO: 即将废弃 type DeployConfig struct { - Id string `json:"id"` - Access string `json:"access"` - Type string `json:"type"` - Config map[string]any `json:"config"` + NodeId string `json:"nodeId"` + NodeConfig map[string]any `json:"nodeConfig"` + Provider string `json:"provider"` + ProviderAccessId string `json:"providerAccessId"` } diff --git a/internal/domain/workflow.go b/internal/domain/workflow.go index 8d342fe2..51c203bf 100644 --- a/internal/domain/workflow.go +++ b/internal/domain/workflow.go @@ -1,8 +1,7 @@ package domain import ( - "fmt" - "strconv" + "github.com/usual2970/certimate/internal/pkg/utils/maps" ) const ( @@ -47,33 +46,19 @@ type WorkflowNode struct { } func (n *WorkflowNode) GetConfigString(key string) string { - if v, ok := n.Config[key]; ok { - if s, ok := v.(string); ok { - return s - } - } - return "" + return maps.GetValueAsString(n.Config, key) } func (n *WorkflowNode) GetConfigBool(key string) bool { - if v, ok := n.Config[key]; ok { - if b, ok := v.(bool); ok { - return b - } - } - return false + return maps.GetValueAsBool(n.Config, key) +} + +func (n *WorkflowNode) GetConfigInt32(key string) int32 { + return maps.GetValueAsInt32(n.Config, key) } func (n *WorkflowNode) GetConfigInt64(key string) int64 { - // 先转成字符串,再转成 int64 - if v, ok := n.Config[key]; ok { - temp := fmt.Sprintf("%v", v) - if i, err := strconv.ParseInt(temp, 10, 64); err == nil { - return i - } - } - - return 0 + return maps.GetValueAsInt64(n.Config, key) } type WorkflowNodeIO struct { diff --git a/internal/pkg/core/deployer/providers/webhook/webhook.go b/internal/pkg/core/deployer/providers/webhook/webhook.go index e9ed6f11..d81da684 100644 --- a/internal/pkg/core/deployer/providers/webhook/webhook.go +++ b/internal/pkg/core/deployer/providers/webhook/webhook.go @@ -54,13 +54,6 @@ func NewWithLogger(config *WebhookDeployerConfig, logger logger.Logger) (*Webhoo }, nil } -type webhookData struct { - SubjectAltNames string `json:"subjectAltNames"` - Certificate string `json:"certificate"` - PrivateKey string `json:"privateKey"` - Variables map[string]string `json:"variables"` -} - func (d *WebhookDeployer) Deploy(ctx context.Context, certPem string, privkeyPem string) (*deployer.DeployResult, error) { certX509, err := x509.ParseCertificateFromPEM(certPem) if err != nil { diff --git a/internal/pkg/utils/maps/maps.go b/internal/pkg/utils/maps/maps.go index 0c80e3a3..a7c11592 100644 --- a/internal/pkg/utils/maps/maps.go +++ b/internal/pkg/utils/maps/maps.go @@ -118,6 +118,12 @@ func GetValueOrDefaultAsInt64(dict map[string]any, key string, defaultValue int6 } } + if result, ok := value.(int32); ok { + if result != 0 { + return int64(result) + } + } + // 兼容字符串类型的值 if str, ok := value.(string); ok { if result, err := strconv.ParseInt(str, 10, 64); err == nil { diff --git a/internal/workflow/node-processor/deploy_node.go b/internal/workflow/node-processor/deploy_node.go index fc717de5..ff20eb3b 100644 --- a/internal/workflow/node-processor/deploy_node.go +++ b/internal/workflow/node-processor/deploy_node.go @@ -59,15 +59,16 @@ func (d *deployNode) Run(ctx context.Context) error { } accessRepo := repository.NewAccessRepository() - access, err := accessRepo.GetById(context.Background(), d.node.GetConfigString("access")) + access, err := accessRepo.GetById(context.Background(), d.node.GetConfigString("providerAccessId")) if err != nil { d.AddOutput(ctx, d.node.Name, "获取授权配置失败", err.Error()) return err } + option := &deployer.DeployerOption{ DomainId: d.node.Id, Domain: cert.SAN, - Access: access.Config, + AccessConfig: access.Config, AccessRecord: access, Certificate: applicant.Certificate{ CertUrl: cert.CertUrl, @@ -77,10 +78,10 @@ func (d *deployNode) Run(ctx context.Context) error { IssuerCertificate: cert.IssuerCertificate, }, DeployConfig: domain.DeployConfig{ - Id: d.node.Id, - Access: access.Id, - Type: d.node.GetConfigString("provider"), - Config: d.node.Config, + NodeId: d.node.Id, + NodeConfig: d.node.Config, + Provider: d.node.GetConfigString("provider"), + ProviderAccessId: access.Id, }, } diff --git a/ui/src/components/access/AccessEditForm.tsx b/ui/src/components/access/AccessEditForm.tsx index 1e68d226..6809da4d 100644 --- a/ui/src/components/access/AccessEditForm.tsx +++ b/ui/src/components/access/AccessEditForm.tsx @@ -7,7 +7,7 @@ import { z } from "zod"; import AccessProviderSelect from "@/components/provider/AccessProviderSelect"; import { type AccessModel } from "@/domain/access"; -import { ACCESS_PROVIDERS, accessProvidersMap } from "@/domain/provider"; +import { ACCESS_PROVIDERS } from "@/domain/provider"; import { useAntdForm } from "@/hooks"; import AccessEditFormACMEHttpReqConfig from "./AccessEditFormACMEHttpReqConfig"; diff --git a/ui/src/components/workflow/WorkflowRunDetailDrawer.tsx b/ui/src/components/workflow/WorkflowRunDetailDrawer.tsx index ec7295e0..ae48231f 100644 --- a/ui/src/components/workflow/WorkflowRunDetailDrawer.tsx +++ b/ui/src/components/workflow/WorkflowRunDetailDrawer.tsx @@ -50,7 +50,7 @@ const WorkflowRunDetailDrawer = ({ data, loading, trigger, ...props }: WorkflowR {item.outputs.map((output, j) => { return (
-
[{dayjs(output.time).format("YYYY-MM-DD HH:mm:ss")}]
+
[{dayjs(output.time).format("YYYY-MM-DD HH:mm:ss")}]
{output.error ?
{output.error}
:
{output.content}
}
); diff --git a/ui/src/components/workflow/node/ApplyNodeForm.tsx b/ui/src/components/workflow/node/ApplyNodeForm.tsx index abc59880..d01b7386 100644 --- a/ui/src/components/workflow/node/ApplyNodeForm.tsx +++ b/ui/src/components/workflow/node/ApplyNodeForm.tsx @@ -12,8 +12,9 @@ import MultipleInput from "@/components/MultipleInput"; import AccessEditModal from "@/components/access/AccessEditModal"; import AccessSelect from "@/components/access/AccessSelect"; import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider"; -import { type WorkflowNode } from "@/domain/workflow"; +import { type WorkflowApplyNodeConfig, type WorkflowNode } from "@/domain/workflow"; import { useAntdForm, useZustandShallowSelector } from "@/hooks"; +import { useAccessesStore } from "@/stores/access"; import { useContactEmailsStore } from "@/stores/contact"; import { useWorkflowStore } from "@/stores/workflow"; import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators"; @@ -25,12 +26,10 @@ export type ApplyNodeFormProps = { const MULTIPLE_INPUT_DELIMITER = ";"; -const initFormModel = () => { +const initFormModel = (): Partial => { return { - domain: "", keyAlgorithm: "RSA2048", - nameservers: "", - propagationTimeout: 60, + propagationTimeout: 120, disableFollowCNAME: true, }; }; @@ -38,6 +37,7 @@ const initFormModel = () => { const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => { const { t } = useTranslation(); + const { accesses } = useAccessesStore(useZustandShallowSelector("accesses")); const { addEmail } = useContactEmailsStore(useZustandShallowSelector("addEmail")); const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"])); const { hidePanel } = usePanel(); @@ -49,7 +49,9 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => { .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")), + providerAccessId: z + .string({ message: t("workflow_node.apply.form.provider_access.placeholder") }) + .min(1, t("workflow_node.apply.form.provider_access.placeholder")), keyAlgorithm: z.string().nullish(), nameservers: z .string() @@ -74,13 +76,16 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => { formPending, formProps, } = useAntdForm>({ - initialValues: node?.config ?? initFormModel(), + initialValues: (node?.config as WorkflowApplyNodeConfig) ?? initFormModel(), onSubmit: async (values) => { await formInst.validateFields(); await addEmail(values.email); await updateNode( produce(node, (draft) => { - draft.config = { ...values }; + draft.config = { + provider: accesses.find((e) => e.id === values.providerAccessId)?.provider, + ...values, + } as WorkflowApplyNodeConfig; draft.validated = true; }) ); @@ -146,8 +151,8 @@ const ApplyNodeForm = ({ node }: ApplyNodeFormProps) => { - + { const provider = accessProvidersMap.get(record.provider); return ACCESS_USAGES.ALL === provider?.usage || ACCESS_USAGES.APPLY === provider?.usage; diff --git a/ui/src/components/workflow/node/DeployNodeForm.tsx b/ui/src/components/workflow/node/DeployNodeForm.tsx index d376ad73..0363aaa4 100644 --- a/ui/src/components/workflow/node/DeployNodeForm.tsx +++ b/ui/src/components/workflow/node/DeployNodeForm.tsx @@ -12,7 +12,7 @@ import AccessSelect from "@/components/access/AccessSelect"; import DeployProviderPicker from "@/components/provider/DeployProviderPicker"; import DeployProviderSelect from "@/components/provider/DeployProviderSelect"; import { ACCESS_USAGES, DEPLOY_PROVIDERS, accessProvidersMap, deployProvidersMap } from "@/domain/provider"; -import { type WorkflowNode } from "@/domain/workflow"; +import { type WorkflowDeployNodeConfig, type WorkflowNode } from "@/domain/workflow"; import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useWorkflowStore } from "@/stores/workflow"; import { usePanel } from "../PanelProvider"; @@ -44,7 +44,7 @@ export type DeployFormProps = { node: WorkflowNode; }; -const initFormModel = () => { +const initFormModel = (): Partial => { return {}; }; @@ -56,7 +56,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => { const formSchema = z.object({ provider: z.string({ message: t("workflow_node.deploy.form.provider.placeholder") }).nonempty(t("workflow_node.deploy.form.provider.placeholder")), - access: z + providerAccessId: 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")), @@ -67,7 +67,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => { formPending, formProps, } = useAntdForm>({ - initialValues: node?.config ?? initFormModel(), + initialValues: (node?.config as WorkflowDeployNodeConfig) ?? initFormModel(), onSubmit: async (values) => { await formInst.validateFields(); await updateNode( @@ -160,7 +160,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => { const oldValues = formInst.getFieldsValue(); const newValues: Record = {}; for (const key in oldValues) { - if (key === "provider" || key === "access" || key === "certificate") { + if (key === "provider" || key === "providerAccessId" || key === "certificate") { newValues[key] = oldValues[key]; } else { newValues[key] = undefined; @@ -169,7 +169,7 @@ const DeployNodeForm = ({ node }: DeployFormProps) => { formInst.setFieldsValue(newValues); if (deployProvidersMap.get(fieldProvider)?.provider !== deployProvidersMap.get(value)?.provider) { - formInst.setFieldValue("access", undefined); + formInst.setFieldValue("providerAccessId", undefined); } } }; @@ -205,14 +205,14 @@ const DeployNodeForm = ({ node }: DeployFormProps) => { onSubmit={(record) => { const provider = accessProvidersMap.get(record.provider); if (ACCESS_USAGES.ALL === provider?.usage || ACCESS_USAGES.DEPLOY === provider?.usage) { - formInst.setFieldValue("access", record.id); + formInst.setFieldValue("providerAccessId", record.id); } }} /> - + { diff --git a/ui/src/components/workflow/node/NotifyNodeForm.tsx b/ui/src/components/workflow/node/NotifyNodeForm.tsx index 9e2ef76c..eacecda3 100644 --- a/ui/src/components/workflow/node/NotifyNodeForm.tsx +++ b/ui/src/components/workflow/node/NotifyNodeForm.tsx @@ -8,7 +8,7 @@ import { produce } from "immer"; import { z } from "zod"; import { notifyChannelsMap } from "@/domain/settings"; -import { type WorkflowNode } from "@/domain/workflow"; +import { type WorkflowNode, type WorkflowNotifyNodeConfig } from "@/domain/workflow"; import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useNotifyChannelsStore } from "@/stores/notify"; import { useWorkflowStore } from "@/stores/workflow"; @@ -18,7 +18,7 @@ export type NotifyNodeFormProps = { node: WorkflowNode; }; -const initFormModel = () => { +const initFormModel = (): Partial => { return { subject: "Completed!", message: "Your workflow has been completed on Certimate.", @@ -57,7 +57,7 @@ const NotifyNodeForm = ({ node }: NotifyNodeFormProps) => { formPending, formProps, } = useAntdForm>({ - initialValues: node?.config ?? initFormModel(), + initialValues: (node?.config as WorkflowNotifyNodeConfig) ?? initFormModel(), onSubmit: async (values) => { await formInst.validateFields(); await updateNode( diff --git a/ui/src/components/workflow/node/StartNodeForm.tsx b/ui/src/components/workflow/node/StartNodeForm.tsx index 9611e91d..22664ac3 100644 --- a/ui/src/components/workflow/node/StartNodeForm.tsx +++ b/ui/src/components/workflow/node/StartNodeForm.tsx @@ -7,7 +7,7 @@ import { produce } from "immer"; import { z } from "zod"; import Show from "@/components/Show"; -import { type WorkflowNode } from "@/domain/workflow"; +import { type WorkflowNode, type WorkflowStartNodeConfig } from "@/domain/workflow"; import { useAntdForm, useZustandShallowSelector } from "@/hooks"; import { useWorkflowStore } from "@/stores/workflow"; import { getNextCronExecutions, validCronExpression } from "@/utils/cron"; @@ -17,7 +17,7 @@ export type StartNodeFormProps = { node: WorkflowNode; }; -const initFormModel = () => { +const initFormModel = (): WorkflowStartNodeConfig => { return { executionMethod: "auto", crontab: "0 0 * * *", @@ -54,7 +54,7 @@ const StartNodeForm = ({ node }: StartNodeFormProps) => { formPending, formProps, } = useAntdForm>({ - initialValues: node?.config ?? initFormModel(), + initialValues: (node?.config as WorkflowStartNodeConfig) ?? initFormModel(), onSubmit: async (values) => { await formInst.validateFields(); await updateNode( diff --git a/ui/src/domain/workflow.ts b/ui/src/domain/workflow.ts index 124d5f3a..773f5941 100644 --- a/ui/src/domain/workflow.ts +++ b/ui/src/domain/workflow.ts @@ -85,6 +85,39 @@ export type WorkflowNode = { validated?: boolean; }; +export type WorkflowStartNodeConfig = { + executionMethod: string; + crontab?: string; +}; + +export type WorkflowApplyNodeConfig = { + domain: string; + email: string; + provider: string; + providerAccessId: string; + keyAlgorithm: string; + nameservers?: string; + propagationTimeout?: number; + disableFollowCNAME?: boolean; +}; + +export type WorkflowDeployNodeConfig = { + provider: string; + providerAccessId: string; + certificate: string; + [key: string]: unknown; +}; + +export type WorkflowNotifyNodeConfig = { + channel: string; + subject: string; + message: string; +}; + +export type WorkflowBranchNodeConfig = never; + +export type WorkflowEndNodeConfig = never; + export type WorkflowNodeIO = { name: string; type: string; @@ -150,7 +183,7 @@ export const newNode = (nodeType: WorkflowNodeType, options: NewNodeOptions = {} case WorkflowNodeType.Apply: case WorkflowNodeType.Deploy: { - node.config = {}; + node.config = {} as Record; node.input = workflowNodeTypeDefaultInputs.get(nodeType); node.output = workflowNodeTypeDefaultOutputs.get(nodeType); } diff --git a/ui/src/i18n/locales/en/nls.workflow.nodes.json b/ui/src/i18n/locales/en/nls.workflow.nodes.json index f95dc295..9390da12 100644 --- a/ui/src/i18n/locales/en/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/en/nls.workflow.nodes.json @@ -27,10 +27,10 @@ "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.provider_access.label": "DNS provider authorization", + "workflow_node.apply.form.provider_access.placeholder": "Please select an authorization of DNS provider", + "workflow_node.apply.form.provider_access.tooltip": "Used to manage DNS records during ACME DNS-01 authentication.", + "workflow_node.apply.form.provider_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", diff --git a/ui/src/i18n/locales/zh/nls.workflow.nodes.json b/ui/src/i18n/locales/zh/nls.workflow.nodes.json index 1b5133cf..5966fa2d 100644 --- a/ui/src/i18n/locales/zh/nls.workflow.nodes.json +++ b/ui/src/i18n/locales/zh/nls.workflow.nodes.json @@ -27,10 +27,10 @@ "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.provider_access.label": "DNS 提供商授权", + "workflow_node.apply.form.provider_access.placeholder": "请选择 DNS 提供商授权", + "workflow_node.apply.form.provider_access.tooltip": "用于 ACME DNS-01 认证时操作域名解析记录,注意与部署阶段所需的主机提供商相区分。", + "workflow_node.apply.form.provider_access.button": "新建", "workflow_node.apply.form.advanced_config.label": "高级设置", "workflow_node.apply.form.key_algorithm.label": "数字证书算法", "workflow_node.apply.form.key_algorithm.placeholder": "请选择数字证书算法",