mirror of
https://github.com/usual2970/certimate.git
synced 2025-07-25 19:38:35 +00:00
feat: support configuring independent ca in workflows
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
import { forwardRef, memo, useEffect, useImperativeHandle, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FormOutlined as FormOutlinedIcon, PlusOutlined as PlusOutlinedIcon, QuestionCircleOutlined as QuestionCircleOutlinedIcon } from "@ant-design/icons";
|
||||
import { Link } from "react-router";
|
||||
import {
|
||||
FormOutlined as FormOutlinedIcon,
|
||||
PlusOutlined as PlusOutlinedIcon,
|
||||
QuestionCircleOutlined as QuestionCircleOutlinedIcon,
|
||||
RightOutlined as RightOutlinedIcon,
|
||||
} from "@ant-design/icons";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import {
|
||||
AutoComplete,
|
||||
@@ -25,8 +31,9 @@ import AccessEditModal from "@/components/access/AccessEditModal";
|
||||
import AccessSelect from "@/components/access/AccessSelect";
|
||||
import ModalForm from "@/components/ModalForm";
|
||||
import MultipleInput from "@/components/MultipleInput";
|
||||
import ApplyDNSProviderSelect from "@/components/provider/ApplyDNSProviderSelect";
|
||||
import { ACCESS_USAGES, APPLY_DNS_PROVIDERS, accessProvidersMap, applyDNSProvidersMap } from "@/domain/provider";
|
||||
import CAProviderSelect from "@/components/provider/CAProviderSelect";
|
||||
import DNSProviderSelect from "@/components/provider/DNSProviderSelect";
|
||||
import { ACCESS_USAGES, APPLY_DNS_PROVIDERS, accessProvidersMap, applyCAProvidersMap, applyDNSProvidersMap } from "@/domain/provider";
|
||||
import { type WorkflowNodeConfigForApply } from "@/domain/workflow";
|
||||
import { useAntdForm, useAntdFormName, useZustandShallowSelector } from "@/hooks";
|
||||
import { useAccessesStore } from "@/stores/access";
|
||||
@@ -60,7 +67,7 @@ const initFormModel = (): ApplyNodeConfigFormFieldValues => {
|
||||
return {
|
||||
challengeType: "dns-01",
|
||||
keyAlgorithm: "RSA2048",
|
||||
skipBeforeExpiryDays: 20,
|
||||
skipBeforeExpiryDays: 30,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -83,7 +90,16 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
providerAccessId: z
|
||||
.string({ message: t("workflow_node.apply.form.provider_access.placeholder") })
|
||||
.min(1, t("workflow_node.apply.form.provider_access.placeholder")),
|
||||
providerConfig: z.any(),
|
||||
providerConfig: z.any().nullish(),
|
||||
caProvider: z.string({ message: t("workflow_node.apply.form.ca_provider.placeholder") }).nullish(),
|
||||
caProviderAccessId: z
|
||||
.string({ message: t("workflow_node.apply.form.ca_provider_access.placeholder") })
|
||||
.nullish()
|
||||
.refine((v) => {
|
||||
if (!fieldCAProvider) return true;
|
||||
return !!v;
|
||||
}, t("workflow_node.apply.form.ca_provider_access.placeholder")),
|
||||
caProviderConfig: z.any().nullish(),
|
||||
keyAlgorithm: z
|
||||
.string({ message: t("workflow_node.apply.form.key_algorithm.placeholder") })
|
||||
.nonempty(t("workflow_node.apply.form.key_algorithm.placeholder")),
|
||||
@@ -121,9 +137,10 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
initialValues: initialValues ?? initFormModel(),
|
||||
});
|
||||
|
||||
const fieldDomains = Form.useWatch<string>("domains", formInst);
|
||||
const fieldProvider = Form.useWatch<string>("provider", { form: formInst, preserve: true });
|
||||
const fieldProviderAccessId = Form.useWatch<string>("providerAccessId", formInst);
|
||||
const fieldDomains = Form.useWatch<string>("domains", formInst);
|
||||
const fieldCAProvider = Form.useWatch<string>("caProvider", formInst);
|
||||
const fieldNameservers = Form.useWatch<string>("nameservers", formInst);
|
||||
|
||||
const [showProvider, setShowProvider] = useState(false);
|
||||
@@ -139,6 +156,15 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
}
|
||||
}, [accesses, fieldProviderAccessId]);
|
||||
|
||||
const [showCAProviderAccess, setShowCAProviderAccess] = useState(false);
|
||||
useEffect(() => {
|
||||
if (fieldCAProvider) {
|
||||
setShowCAProviderAccess(true);
|
||||
} else {
|
||||
setShowCAProviderAccess(false);
|
||||
}
|
||||
}, [fieldCAProvider]);
|
||||
|
||||
const [nestedFormInst] = Form.useForm();
|
||||
const nestedFormName = useAntdFormName({ form: nestedFormInst, name: "workflowNodeApplyConfigFormProviderConfigForm" });
|
||||
const nestedFormEl = useMemo(() => {
|
||||
@@ -195,6 +221,27 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
}
|
||||
};
|
||||
|
||||
const handleCAProviderSelect = (value?: string | undefined) => {
|
||||
if (fieldCAProvider === value) return;
|
||||
|
||||
// 切换 CA 提供商时联动授权信息
|
||||
if (value === "") {
|
||||
setTimeout(() => {
|
||||
formInst.setFieldValue("caProvider", undefined);
|
||||
formInst.setFieldValue("caProviderAccessId", undefined);
|
||||
onValuesChange?.(formInst.getFieldsValue(true));
|
||||
}, 1);
|
||||
} else if (initialValues?.caProvider === value) {
|
||||
formInst.setFieldValue("caProviderAccessId", initialValues?.caProviderAccessId);
|
||||
onValuesChange?.(formInst.getFieldsValue(true));
|
||||
} else {
|
||||
if (applyCAProvidersMap.get(fieldCAProvider)?.provider !== applyCAProvidersMap.get(value!)?.provider) {
|
||||
formInst.setFieldValue("caProviderAccessId", undefined);
|
||||
onValuesChange?.(formInst.getFieldsValue(true));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleFormProviderChange = (name: string) => {
|
||||
if (name === nestedFormName) {
|
||||
formInst.setFieldValue("providerConfig", nestedFormInst.getFieldsValue());
|
||||
@@ -273,7 +320,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="provider" label={t("workflow_node.apply.form.provider.label")} hidden={!showProvider} rules={[formRule]}>
|
||||
<ApplyDNSProviderSelect
|
||||
<DNSProviderSelect
|
||||
disabled={!showProvider}
|
||||
filter={(record) => {
|
||||
if (fieldProviderAccessId) {
|
||||
@@ -304,13 +351,13 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
preset="add"
|
||||
trigger={
|
||||
<Button size="small" type="link">
|
||||
<PlusOutlinedIcon />
|
||||
{t("workflow_node.apply.form.provider_access.button")}
|
||||
<PlusOutlinedIcon className="text-xs" />
|
||||
</Button>
|
||||
}
|
||||
afterSubmit={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.APPLY)) {
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.DNS)) {
|
||||
formInst.setFieldValue("providerAccessId", record.id);
|
||||
}
|
||||
}}
|
||||
@@ -322,7 +369,7 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
<AccessSelect
|
||||
filter={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.APPLY);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.DNS);
|
||||
}}
|
||||
placeholder={t("workflow_node.apply.form.provider_access.placeholder")}
|
||||
onChange={handleProviderAccessSelect}
|
||||
@@ -340,6 +387,71 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
</Divider>
|
||||
|
||||
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
|
||||
<Form.Item className="mb-0">
|
||||
<label className="mb-1 block">
|
||||
<div className="flex w-full items-center justify-between gap-4">
|
||||
<div className="max-w-full grow truncate">{t("workflow_node.apply.form.ca_provider.label")}</div>
|
||||
<div className="text-right">
|
||||
<Link className="ant-typography" to="/settings/ssl-provider" target="_blank">
|
||||
<Button size="small" type="link">
|
||||
{t("workflow_node.apply.form.ca_provider.button")}
|
||||
<RightOutlinedIcon className="text-xs" />
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<Form.Item name="caProvider" rules={[formRule]}>
|
||||
<CAProviderSelect
|
||||
allowClear
|
||||
placeholder={t("workflow_node.apply.form.ca_provider.placeholder")}
|
||||
showSearch
|
||||
onSelect={handleCAProviderSelect}
|
||||
onClear={handleCAProviderSelect}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item className="mb-0" hidden={!showCAProviderAccess}>
|
||||
<label className="mb-1 block">
|
||||
<div className="flex w-full items-center justify-between gap-4">
|
||||
<div className="max-w-full grow truncate">
|
||||
<span>{t("workflow_node.apply.form.ca_provider_access.label")}</span>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<AccessEditModal
|
||||
preset="add"
|
||||
trigger={
|
||||
<Button size="small" type="link">
|
||||
{t("workflow_node.apply.form.ca_provider_access.button")}
|
||||
<PlusOutlinedIcon className="text-xs" />
|
||||
</Button>
|
||||
}
|
||||
afterSubmit={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.CA)) {
|
||||
formInst.setFieldValue("caProviderAccessId", record.id);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<Form.Item name="caProviderAccessId" rules={[formRule]}>
|
||||
<AccessSelect
|
||||
filter={(record) => {
|
||||
if (fieldCAProvider) {
|
||||
return applyCAProvidersMap.get(fieldCAProvider)?.provider === record.provider;
|
||||
}
|
||||
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.CA);
|
||||
}}
|
||||
placeholder={t("workflow_node.apply.form.ca_provider_access.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="keyAlgorithm" label={t("workflow_node.apply.form.key_algorithm.label")} rules={[formRule]}>
|
||||
<Select
|
||||
options={["RSA2048", "RSA3072", "RSA4096", "RSA8192", "EC256", "EC384"].map((e) => ({
|
||||
@@ -364,6 +476,9 @@ const ApplyNodeConfigForm = forwardRef<ApplyNodeConfigFormInstance, ApplyNodeCon
|
||||
onChange={(e) => {
|
||||
formInst.setFieldValue("nameservers", e.target.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
formInst.setFieldValue("nameservers", undefined);
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<NameserversModalInput
|
||||
|
@@ -7,8 +7,8 @@ import { z } from "zod";
|
||||
|
||||
import AccessEditModal from "@/components/access/AccessEditModal";
|
||||
import AccessSelect from "@/components/access/AccessSelect";
|
||||
import DeployProviderPicker from "@/components/provider/DeployProviderPicker";
|
||||
import DeployProviderSelect from "@/components/provider/DeployProviderSelect";
|
||||
import HostingProviderPicker from "@/components/provider/HostingProviderPicker.tsx";
|
||||
import HostingProviderSelect from "@/components/provider/HostingProviderSelect.tsx";
|
||||
import Show from "@/components/Show";
|
||||
import { ACCESS_USAGES, DEPLOY_PROVIDERS, accessProvidersMap, deployProvidersMap } from "@/domain/provider";
|
||||
import { type WorkflowNode, type WorkflowNodeConfigForDeploy } from "@/domain/workflow";
|
||||
@@ -292,7 +292,7 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
onValuesChange?.(formInst.getFieldsValue(true));
|
||||
};
|
||||
|
||||
const handleProviderSelect = (value: string) => {
|
||||
const handleProviderSelect = (value?: string | undefined) => {
|
||||
if (fieldProvider === value) return;
|
||||
|
||||
// 切换部署目标时重置表单,避免其他部署目标的配置字段影响当前部署目标
|
||||
@@ -310,7 +310,7 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
}
|
||||
formInst.setFieldsValue(newValues);
|
||||
|
||||
if (deployProvidersMap.get(fieldProvider)?.provider !== deployProvidersMap.get(value)?.provider) {
|
||||
if (deployProvidersMap.get(fieldProvider)?.provider !== deployProvidersMap.get(value!)?.provider) {
|
||||
formInst.setFieldValue("providerAccessId", undefined);
|
||||
onValuesChange?.(formInst.getFieldsValue(true));
|
||||
}
|
||||
@@ -355,15 +355,16 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
|
||||
<Show
|
||||
when={!!fieldProvider}
|
||||
fallback={<DeployProviderPicker autoFocus placeholder={t("workflow_node.deploy.search.provider.placeholder")} onSelect={handleProviderPick} />}
|
||||
fallback={<HostingProviderPicker autoFocus placeholder={t("workflow_node.deploy.search.provider.placeholder")} onSelect={handleProviderPick} />}
|
||||
>
|
||||
<Form.Item name="provider" label={t("workflow_node.deploy.form.provider.label")} rules={[formRule]}>
|
||||
<DeployProviderSelect
|
||||
<HostingProviderSelect
|
||||
allowClear
|
||||
disabled={!!initialValues?.provider}
|
||||
placeholder={t("workflow_node.deploy.form.provider.placeholder")}
|
||||
showSearch
|
||||
onSelect={handleProviderSelect}
|
||||
onClear={handleProviderSelect}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -384,13 +385,13 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
preset="add"
|
||||
trigger={
|
||||
<Button size="small" type="link">
|
||||
<PlusOutlinedIcon />
|
||||
{t("workflow_node.deploy.form.provider_access.button")}
|
||||
<PlusOutlinedIcon className="text-xs" />
|
||||
</Button>
|
||||
}
|
||||
afterSubmit={(record) => {
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.DEPLOY)) {
|
||||
if (provider?.usages?.includes(ACCESS_USAGES.HOSTING)) {
|
||||
formInst.setFieldValue("providerAccessId", record.id);
|
||||
}
|
||||
}}
|
||||
@@ -406,7 +407,7 @@ const DeployNodeConfigForm = forwardRef<DeployNodeConfigFormInstance, DeployNode
|
||||
}
|
||||
|
||||
const provider = accessProvidersMap.get(record.provider);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.DEPLOY);
|
||||
return !!provider?.usages?.includes(ACCESS_USAGES.HOSTING);
|
||||
}}
|
||||
placeholder={t("workflow_node.deploy.form.provider_access.placeholder")}
|
||||
/>
|
||||
|
@@ -100,6 +100,9 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({
|
||||
onChange={(e) => {
|
||||
formInst.setFieldValue("resourceIds", e.target.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
formInst.setFieldValue("resourceIds", "");
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<ResourceIdsModalInput
|
||||
@@ -130,6 +133,9 @@ const DeployNodeConfigFormAliyunCASDeployConfig = ({
|
||||
onChange={(e) => {
|
||||
formInst.setFieldValue("contactIds", e.target.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
formInst.setFieldValue("contactIds", "");
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<ContactIdsModalInput
|
||||
|
@@ -123,6 +123,9 @@ const DeployNodeConfigFormBaotaPanelSiteConfig = ({
|
||||
onChange={(e) => {
|
||||
formInst.setFieldValue("siteNames", e.target.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
formInst.setFieldValue("siteNames", "");
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<SiteNamesModalInput
|
||||
|
@@ -107,6 +107,9 @@ const DeployNodeConfigFormTencentCloudSSLDeployConfig = ({
|
||||
onChange={(e) => {
|
||||
formInst.setFieldValue("resourceIds", e.target.value);
|
||||
}}
|
||||
onClear={() => {
|
||||
formInst.setFieldValue("resourceIds", "");
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
<ResourceIdsModalInput
|
||||
|
Reference in New Issue
Block a user