mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-08 13:39:53 +00:00
feat(ui): new AccessEditForm using antd
This commit is contained in:
parent
047b3bc079
commit
c27818b3b0
@ -2,8 +2,8 @@
|
||||
|
||||
> [!WARNING]
|
||||
> 当前分支为 `next`,是 v0.3.x 的开发分支,目前还没有稳定,请勿在生产环境中使用。
|
||||
>
|
||||
> 如需访问 v0.2.x 源码,请切换至 `main` 分支。
|
||||
>
|
||||
> 如需访问之前的版本,请切换至 `main` 分支。
|
||||
|
||||
# 🔒Certimate
|
||||
|
||||
@ -84,11 +84,11 @@ make local.run
|
||||
| 华为云 | √ | √ | 可签发在华为云注册的域名;可部署到华为云 CDN、ELB |
|
||||
| 七牛云 | | √ | 可部署到七牛云 CDN |
|
||||
| 多吉云 | | √ | 可部署到多吉云 CDN |
|
||||
| 火山引擎 | √ | √ | 可签发在火山引擎注册的域名;可部署到火山引擎 Live、CDN |
|
||||
| 火山引擎 | √ | √ | 可签发在火山引擎注册的域名;可部署到火山引擎 Live、CDN |
|
||||
| AWS | √ | | 可签发在 AWS Route53 托管的域名 |
|
||||
| CloudFlare | √ | | 可签发在 CloudFlare 注册的域名;CloudFlare 服务自带 SSL 证书 |
|
||||
| GoDaddy | √ | | 可签发在 GoDaddy 注册的域名 |
|
||||
| Namesilo | √ | | 可签发在 Namesilo 注册的域名 |
|
||||
| NameSilo | √ | | 可签发在 NameSilo 注册的域名 |
|
||||
| PowerDNS | √ | | 可签发在 PowerDNS 托管的域名 |
|
||||
| HTTP 请求 | √ | | 可签发允许通过 HTTP 请求修改 DNS 的域名 |
|
||||
| 本地部署 | | √ | 可部署到本地服务器 |
|
||||
@ -194,4 +194,3 @@ Certimate 是一个免费且开源的项目,采用 [MIT 开源协议](LICENSE.
|
||||
## 十、Star 趋势图
|
||||
|
||||
[](https://starchart.cc/usual2970/certimate)
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
> [!WARNING]
|
||||
> The current branch is `next`, which is the development branch for v0.3.x. It is currently unstable and should not be used in production environments.
|
||||
>
|
||||
>
|
||||
> To access the previous versions, please switch to the `main` branch.
|
||||
|
||||
# 🔒Certimate
|
||||
@ -76,7 +76,7 @@ password:1234567890
|
||||
## List of Supported Providers
|
||||
|
||||
| Provider | Registration | Deployment | Remarks |
|
||||
| :-----------: | :----------: | :--------: |-------------------------------------------------------------------------------------------------------------|
|
||||
| :-----------: | :----------: | :--------: | ----------------------------------------------------------------------------------------------------------- |
|
||||
| Alibaba Cloud | √ | √ | Supports domains registered on Alibaba Cloud; supports deployment to Alibaba Cloud OSS, CDN,SLB |
|
||||
| Tencent Cloud | √ | √ | Supports domains registered on Tencent Cloud; supports deployment to Tencent Cloud COS, CDN, ECDN, CLB, TEO |
|
||||
| Baidu Cloud | | √ | Supports deployment to Baidu Cloud CDN |
|
||||
@ -87,7 +87,7 @@ password:1234567890
|
||||
| AWS | √ | | Supports domains managed on AWS Route53 |
|
||||
| CloudFlare | √ | | Supports domains registered on CloudFlare; CloudFlare services come with SSL certificates |
|
||||
| GoDaddy | √ | | Supports domains registered on GoDaddy |
|
||||
| Namesilo | √ | | Supports domains registered on Namesilo |
|
||||
| NameSilo | √ | | Supports domains registered on NameSilo |
|
||||
| PowerDNS | √ | | Supports domains managed on PowerDNS |
|
||||
| HTTP Request | √ | | Supports domains which allow managing DNS by HTTP request |
|
||||
| Local Deploy | | √ | Supports deployment to local servers |
|
||||
|
@ -39,7 +39,7 @@ const (
|
||||
configTypeCloudflare = "cloudflare"
|
||||
configTypeGoDaddy = "godaddy"
|
||||
configTypeHuaweiCloud = "huaweicloud"
|
||||
configTypeNamesilo = "namesilo"
|
||||
configTypeNameSilo = "namesilo"
|
||||
configTypePowerDNS = "powerdns"
|
||||
configTypeTencentCloud = "tencentcloud"
|
||||
configTypeVolcEngine = "volcengine"
|
||||
@ -219,7 +219,7 @@ func GetWithTypeOption(t string, option *ApplyOption) (Applicant, error) {
|
||||
return NewAws(option), nil
|
||||
case configTypeCloudflare:
|
||||
return NewCloudflare(option), nil
|
||||
case configTypeNamesilo:
|
||||
case configTypeNameSilo:
|
||||
return NewNamesilo(option), nil
|
||||
case configTypeGoDaddy:
|
||||
return NewGodaddy(option), nil
|
||||
|
@ -22,7 +22,7 @@ type HuaweiCloudCDNDeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云地域。
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
// 加速域名(不支持泛域名)。
|
||||
Domain string `json:"domain"`
|
||||
|
@ -27,7 +27,7 @@ type HuaweiCloudELBDeployerConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云地域。
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
// 部署资源类型。
|
||||
ResourceType DeployResourceType `json:"resourceType"`
|
||||
|
@ -26,7 +26,7 @@ type HuaweiCloudELBUploaderConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云地域。
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ type HuaweiCloudSCMUploaderConfig struct {
|
||||
AccessKeyId string `json:"accessKeyId"`
|
||||
// 华为云 SecretAccessKey。
|
||||
SecretAccessKey string `json:"secretAccessKey"`
|
||||
// 华为云地域。
|
||||
// 华为云区域。
|
||||
Region string `json:"region"`
|
||||
}
|
||||
|
||||
|
193
ui/src/components/access/AccessEditForm.tsx
Normal file
193
ui/src/components/access/AccessEditForm.tsx
Normal file
@ -0,0 +1,193 @@
|
||||
import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import {
|
||||
ACCESS_PROVIDER_TYPES,
|
||||
type AccessModel,
|
||||
type ACMEHttpReqAccessConfig,
|
||||
type AliyunAccessConfig,
|
||||
type AWSAccessConfig,
|
||||
type BaiduCloudAccessConfig,
|
||||
type BytePlusAccessConfig,
|
||||
type CloudflareAccessConfig,
|
||||
type DogeCloudAccessConfig,
|
||||
type GoDaddyAccessConfig,
|
||||
type HuaweiCloudAccessConfig,
|
||||
type KubernetesAccessConfig,
|
||||
type LocalAccessConfig,
|
||||
type NameSiloAccessConfig,
|
||||
type PowerDNSAccessConfig,
|
||||
type QiniuAccessConfig,
|
||||
type SSHAccessConfig,
|
||||
type TencentCloudAccessConfig,
|
||||
type VolcEngineAccessConfig,
|
||||
type WebhookAccessConfig,
|
||||
} from "@/domain/access";
|
||||
import AccessTypeSelect from "./AccessTypeSelect";
|
||||
import AccessEditFormACMEHttpReqConfig from "./AccessEditFormACMEHttpReqConfig";
|
||||
import AccessEditFormAliyunConfig from "./AccessEditFormAliyunConfig";
|
||||
import AccessEditFormAWSConfig from "./AccessEditFormAWSConfig";
|
||||
import AccessEditFormBaiduCloudConfig from "./AccessEditFormBaiduCloudConfig";
|
||||
import AccessEditFormBytePlusConfig from "./AccessEditFormBytePlusConfig";
|
||||
import AccessEditFormCloudflareConfig from "./AccessEditFormCloudflareConfig";
|
||||
import AccessEditFormDogeCloudConfig from "./AccessEditFormDogeCloudConfig";
|
||||
import AccessEditFormGoDaddyConfig from "./AccessEditFormGoDaddyConfig";
|
||||
import AccessEditFormHuaweiCloudConfig from "./AccessEditFormHuaweiCloudConfig";
|
||||
import AccessEditFormKubernetesConfig from "./AccessEditFormKubernetesConfig";
|
||||
import AccessEditFormLocalConfig from "./AccessEditFormLocalConfig";
|
||||
import AccessEditFormNameSiloConfig from "./AccessEditFormNameSiloConfig";
|
||||
import AccessEditFormPowerDNSConfig from "./AccessEditFormPowerDNSConfig";
|
||||
import AccessEditFormQiniuConfig from "./AccessEditFormQiniuConfig";
|
||||
import AccessEditFormSSHConfig from "./AccessEditFormSSHConfig";
|
||||
import AccessEditFormTencentCloudConfig from "./AccessEditFormTencentCloudConfig";
|
||||
import AccessEditFormVolcEngineConfig from "./AccessEditFormVolcEngineConfig";
|
||||
import AccessEditFormWebhookConfig from "./AccessEditFormWebhookConfig";
|
||||
|
||||
type AccessEditFormModelType = Partial<Omit<AccessModel, "id" | "created" | "updated" | "deleted">>;
|
||||
|
||||
export type AccessEditFormProps = {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
mode: "add" | "edit";
|
||||
model?: AccessEditFormModelType;
|
||||
onModelChange?: (model: AccessEditFormModelType) => void;
|
||||
};
|
||||
|
||||
export type AccessEditFormInstance = {
|
||||
getFieldsValue: () => AccessEditFormModelType;
|
||||
resetFields: () => void;
|
||||
validateFields: () => Promise<AccessEditFormModelType>;
|
||||
};
|
||||
|
||||
const AccessEditForm = forwardRef<AccessEditFormInstance, AccessEditFormProps>(({ className, style, disabled, loading, mode, model, onModelChange }, ref) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.name.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
configType: z.nativeEnum(ACCESS_PROVIDER_TYPES, { message: t("access.form.type.placeholder") }),
|
||||
config: z.any(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const [form] = Form.useForm<z.infer<typeof formSchema>>();
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? {});
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? {});
|
||||
}, [model]);
|
||||
|
||||
const [configType, setConfigType] = useState(model?.configType);
|
||||
useEffect(() => {
|
||||
setConfigType(model?.configType);
|
||||
}, [model?.configType]);
|
||||
|
||||
const [configFormInst] = Form.useForm();
|
||||
const configForm = useMemo(() => {
|
||||
/*
|
||||
注意:如果追加新的子组件,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new child component, please keep ASCII order.
|
||||
*/
|
||||
switch (configType) {
|
||||
case ACCESS_PROVIDER_TYPES.ACMEHTTPREQ:
|
||||
return <AccessEditFormACMEHttpReqConfig form={configFormInst} model={model?.config as ACMEHttpReqAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.ALIYUN:
|
||||
return <AccessEditFormAliyunConfig form={configFormInst} model={model?.config as AliyunAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.AWS:
|
||||
return <AccessEditFormAWSConfig form={configFormInst} model={model?.config as AWSAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.BAIDUCLOUD:
|
||||
return <AccessEditFormBaiduCloudConfig form={configFormInst} model={model?.config as BaiduCloudAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.BYTEPLUS:
|
||||
return <AccessEditFormBytePlusConfig form={configFormInst} model={model?.config as BytePlusAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.CLOUDFLARE:
|
||||
return <AccessEditFormCloudflareConfig form={configFormInst} model={model?.config as CloudflareAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.DOGECLOUD:
|
||||
return <AccessEditFormDogeCloudConfig form={configFormInst} model={model?.config as DogeCloudAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.GODADDY:
|
||||
return <AccessEditFormGoDaddyConfig form={configFormInst} model={model?.config as GoDaddyAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.HUAWEICLOUD:
|
||||
return <AccessEditFormHuaweiCloudConfig form={configFormInst} model={model?.config as HuaweiCloudAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.KUBERNETES:
|
||||
return <AccessEditFormKubernetesConfig form={configFormInst} model={model?.config as KubernetesAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.LOCAL:
|
||||
return <AccessEditFormLocalConfig form={configFormInst} model={model?.config as LocalAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.NAMESILO:
|
||||
return <AccessEditFormNameSiloConfig form={configFormInst} model={model?.config as NameSiloAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.POWERDNS:
|
||||
return <AccessEditFormPowerDNSConfig form={configFormInst} model={model?.config as PowerDNSAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.QINIU:
|
||||
return <AccessEditFormQiniuConfig form={configFormInst} model={model?.config as QiniuAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.SSH:
|
||||
return <AccessEditFormSSHConfig form={configFormInst} model={model?.config as SSHAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.TENCENTCLOUD:
|
||||
return <AccessEditFormTencentCloudConfig form={configFormInst} model={model?.config as TencentCloudAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.VOLCENGINE:
|
||||
return <AccessEditFormVolcEngineConfig form={configFormInst} model={model?.config as VolcEngineAccessConfig} />;
|
||||
case ACCESS_PROVIDER_TYPES.WEBHOOK:
|
||||
return <AccessEditFormWebhookConfig form={configFormInst} model={model?.config as WebhookAccessConfig} />;
|
||||
}
|
||||
}, [model, configType, configFormInst]);
|
||||
|
||||
const handleFormProviderChange = (name: string) => {
|
||||
if (name === "configForm") {
|
||||
form.setFieldValue("config", configFormInst.getFieldsValue());
|
||||
onModelChange?.(form.getFieldsValue());
|
||||
}
|
||||
};
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormModelType) => {
|
||||
if (fields.configType !== configType) {
|
||||
setConfigType(fields.configType);
|
||||
}
|
||||
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
getFieldsValue: () => {
|
||||
return form.getFieldsValue();
|
||||
},
|
||||
resetFields: () => {
|
||||
return form.resetFields();
|
||||
},
|
||||
validateFields: () => {
|
||||
const t1 = form.validateFields();
|
||||
const t2 = configFormInst.validateFields();
|
||||
return Promise.all([t1, t2]).then(() => t1);
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<Form.Provider onFormChange={handleFormProviderChange}>
|
||||
<div className={className} style={style}>
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" onValuesChange={handleFormChange}>
|
||||
<Form.Item name="name" label={t("access.form.name.label")} rules={[formRule]}>
|
||||
<Input placeholder={t("access.form.name.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="configType"
|
||||
label={t("access.form.type.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.type.tooltip") }}></span>}
|
||||
>
|
||||
<AccessTypeSelect disabled={mode === "edit"} placeholder={t("access.form.type.placeholder")} showSearch={!disabled} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="config" hidden />
|
||||
</Form>
|
||||
|
||||
{configForm}
|
||||
</div>
|
||||
</Form.Provider>
|
||||
);
|
||||
});
|
||||
|
||||
export default AccessEditForm;
|
103
ui/src/components/access/AccessEditFormACMEHttpReqConfig.tsx
Normal file
103
ui/src/components/access/AccessEditFormACMEHttpReqConfig.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, Select, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type ACMEHttpReqAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormACMEHttpReqConfigModelType = Partial<ACMEHttpReqAccessConfig>;
|
||||
|
||||
export type AccessEditFormACMEHttpReqConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormACMEHttpReqConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormACMEHttpReqConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {
|
||||
endpoint: "https://example.com/api/",
|
||||
mode: "",
|
||||
} as AccessEditFormACMEHttpReqConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormACMEHttpReqConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormACMEHttpReqConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
endpoint: z.string().url(t("common.errmsg.url_invalid")),
|
||||
mode: z.string().min(0, t("access.form.acmehttpreq_mode.placeholder")).nullish(),
|
||||
username: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.acmehttpreq_username.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.nullish(),
|
||||
password: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.acmehttpreq_password.placeholder"))
|
||||
.max(256, t("common.errmsg.string_max", { max: 256 }))
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormACMEHttpReqConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="endpoint"
|
||||
label={t("access.form.acmehttpreq_endpoint.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.acmehttpreq_endpoint.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.acmehttpreq_endpoint.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="mode"
|
||||
label={t("access.form.acmehttpreq_mode.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.acmehttpreq_mode.tooltip") }}></span>}
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{ value: "", label: "(default)" },
|
||||
{ value: "RAW", label: "RAW" },
|
||||
]}
|
||||
placeholder={t("access.form.acmehttpreq_mode.placeholder")}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
label={t("access.form.acmehttpreq_username.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.acmehttpreq_username.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.acmehttpreq_username.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="password"
|
||||
label={t("access.form.acmehttpreq_password.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.acmehttpreq_password.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.acmehttpreq_password.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormACMEHttpReqConfig;
|
106
ui/src/components/access/AccessEditFormAWSConfig.tsx
Normal file
106
ui/src/components/access/AccessEditFormAWSConfig.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type AWSAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormAWSConfigModelType = Partial<AWSAccessConfig>;
|
||||
|
||||
export type AccessEditFormAWSConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormAWSConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormAWSConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {
|
||||
region: "us-east-1",
|
||||
} as AccessEditFormAWSConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormAWSConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormAWSConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aws_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aws_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
// TODO: 该字段仅用于申请证书,后续迁移到工作流表单中
|
||||
region: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.aws_region.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.nullish(),
|
||||
// TODO: 该字段仅用于申请证书,后续迁移到工作流表单中
|
||||
hostedZoneId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.aws_hosted_zone_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormAWSConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKeyId"
|
||||
label={t("access.form.aws_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.aws_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.aws_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretAccessKey"
|
||||
label={t("access.form.aws_secret_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.aws_secret_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.aws_secret_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="region"
|
||||
label={t("access.form.aws_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.aws_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.aws_region.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="hostedZoneId"
|
||||
label={t("access.form.aws_hosted_zone_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.aws_hosted_zone_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.aws_hosted_zone_id.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormAWSConfig;
|
72
ui/src/components/access/AccessEditFormAliyunConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormAliyunConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type AliyunAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormAliyunConfigModelType = Partial<AliyunAccessConfig>;
|
||||
|
||||
export type AccessEditFormAliyunConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormAliyunConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormAliyunConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormAliyunConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormAliyunConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormAliyunConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aliyun_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
accessKeySecret: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.aliyun_access_key_secret.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormAliyunConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKeyId"
|
||||
label={t("access.form.aliyun_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.aliyun_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.aliyun_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="accessKeySecret"
|
||||
label={t("access.form.aliyun_access_key_secret.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.aliyun_access_key_secret.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.aliyun_access_key_secret.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormAliyunConfig;
|
72
ui/src/components/access/AccessEditFormBaiduCloudConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormBaiduCloudConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type BaiduCloudAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormBaiduCloudConfigModelType = Partial<BaiduCloudAccessConfig>;
|
||||
|
||||
export type AccessEditFormBaiduCloudConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormBaiduCloudConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormBaiduCloudConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormBaiduCloudConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormBaiduCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormBaiduCloudConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.baiducloud_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.baiducloud_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormBaiduCloudConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKeyId"
|
||||
label={t("access.form.baiducloud_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.baiducloud_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.baiducloud_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretAccessKey"
|
||||
label={t("access.form.baiducloud_secret_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.baiducloud_secret_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.baiducloud_secret_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormBaiduCloudConfig;
|
72
ui/src/components/access/AccessEditFormBytePlusConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormBytePlusConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type BytePlusAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormBytePlusConfigModelType = Partial<BytePlusAccessConfig>;
|
||||
|
||||
export type AccessEditFormBytePlusConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormBytePlusConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormBytePlusConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormBytePlusConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormBytePlusConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormBytePlusConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.byteplus_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.byteplus_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormBytePlusConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKey"
|
||||
label={t("access.form.byteplus_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.byteplus_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.byteplus_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretKey"
|
||||
label={t("access.form.byteplus_secret_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.byteplus_secret_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.byteplus_secret_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormBytePlusConfig;
|
58
ui/src/components/access/AccessEditFormCloudflareConfig.tsx
Normal file
58
ui/src/components/access/AccessEditFormCloudflareConfig.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type CloudflareAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormCloudflareConfigModelType = Partial<CloudflareAccessConfig>;
|
||||
|
||||
export type AccessEditFormCloudflareConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormCloudflareConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormCloudflareConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormCloudflareConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormCloudflareConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormCloudflareConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
dnsApiToken: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.cloudflare_dns_api_token.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormCloudflareConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="dnsApiToken"
|
||||
label={t("access.form.cloudflare_dns_api_token.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.cloudflare_dns_api_token.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.cloudflare_dns_api_token.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormCloudflareConfig;
|
72
ui/src/components/access/AccessEditFormDogeCloudConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormDogeCloudConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type DogeCloudAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormDogeCloudConfigModelType = Partial<DogeCloudAccessConfig>;
|
||||
|
||||
export type AccessEditFormDogeCloudConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormDogeCloudConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormDogeCloudConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormDogeCloudConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormDogeCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormDogeCloudConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.dogecloud_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.dogecloud_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormDogeCloudConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKey"
|
||||
label={t("access.form.dogecloud_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.dogecloud_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.dogecloud_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretKey"
|
||||
label={t("access.form.dogecloud_secret_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.dogecloud_secret_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.dogecloud_secret_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormDogeCloudConfig;
|
72
ui/src/components/access/AccessEditFormGoDaddyConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormGoDaddyConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type GoDaddyAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormGoDaddyConfigModelType = Partial<GoDaddyAccessConfig>;
|
||||
|
||||
export type AccessEditFormGoDaddyConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormGoDaddyConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormGoDaddyConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormGoDaddyConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormGoDaddyConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormGoDaddyConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
apiKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.godaddy_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
apiSecret: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.godaddy_api_secret.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormGoDaddyConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="apiKey"
|
||||
label={t("access.form.godaddy_api_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.godaddy_api_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.godaddy_api_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="apiSecret"
|
||||
label={t("access.form.godaddy_api_secret.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.godaddy_api_secret.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.godaddy_api_secret.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormGoDaddyConfig;
|
90
ui/src/components/access/AccessEditFormHuaweiCloudConfig.tsx
Normal file
90
ui/src/components/access/AccessEditFormHuaweiCloudConfig.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type HuaweiCloudAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormHuaweiCloudConfigModelType = Partial<HuaweiCloudAccessConfig>;
|
||||
|
||||
export type AccessEditFormHuaweiCloudConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormHuaweiCloudConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormHuaweiCloudConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {
|
||||
region: "cn-north-1",
|
||||
} as AccessEditFormHuaweiCloudConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormHuaweiCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormHuaweiCloudConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.huaweicloud_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.huaweicloud_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
// TODO: 该字段仅用于申请证书,后续迁移到工作流表单中
|
||||
region: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.huaweicloud_region.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormHuaweiCloudConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKeyId"
|
||||
label={t("access.form.huaweicloud_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.huaweicloud_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.huaweicloud_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretAccessKey"
|
||||
label={t("access.form.huaweicloud_secret_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.huaweicloud_secret_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.huaweicloud_secret_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="region"
|
||||
label={t("access.form.huaweicloud_region.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.huaweicloud_region.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.huaweicloud_region.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormHuaweiCloudConfig;
|
79
ui/src/components/access/AccessEditFormKubernetesConfig.tsx
Normal file
79
ui/src/components/access/AccessEditFormKubernetesConfig.tsx
Normal file
@ -0,0 +1,79 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { flushSync } from "react-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, Form, Input, Upload, type FormInstance, type UploadFile, type UploadProps } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
import { Upload as UploadIcon } from "lucide-react";
|
||||
|
||||
import { type KubernetesAccessConfig } from "@/domain/access";
|
||||
import { readFileContent } from "@/utils/file";
|
||||
|
||||
type AccessEditFormKubernetesConfigModelType = Partial<KubernetesAccessConfig>;
|
||||
|
||||
export type AccessEditFormKubernetesConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormKubernetesConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormKubernetesConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormKubernetesConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormKubernetesConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormKubernetesConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
kubeConfig: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(0, t("access.form.k8s_kubeconfig.placeholder"))
|
||||
.max(20480, t("common.errmsg.string_max", { max: 20480 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
setKubeFileList(model?.kubeConfig?.trim() ? [{ uid: "-1", name: "kubeconfig", status: "done" }] : []);
|
||||
}, [model]);
|
||||
|
||||
const [kubeFileList, setKubeFileList] = useState<UploadFile[]>([]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormKubernetesConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
const handleUploadChange: UploadProps["onChange"] = async ({ file }) => {
|
||||
if (file && file.status !== "removed") {
|
||||
form.setFieldValue("kubeConfig", (await readFileContent(file.originFileObj ?? (file as unknown as File))).trim());
|
||||
setKubeFileList([file]);
|
||||
} else {
|
||||
form.setFieldValue("kubeConfig", "");
|
||||
setKubeFileList([]);
|
||||
}
|
||||
|
||||
flushSync(() => onModelChange?.(form.getFieldsValue()));
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="kubeConfig"
|
||||
label={t("access.form.k8s_kubeconfig.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.k8s_kubeconfig.tooltip") }}></span>}
|
||||
>
|
||||
<Input.TextArea hidden placeholder={t("access.form.k8s_kubeconfig.placeholder")} value={form.getFieldValue("kubeConfig")} />
|
||||
<Upload beforeUpload={() => false} fileList={kubeFileList} maxCount={1} onChange={handleUploadChange}>
|
||||
<Button icon={<UploadIcon size={16} />}>{t("access.form.k8s_kubeconfig.upload")}</Button>
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormKubernetesConfig;
|
29
ui/src/components/access/AccessEditFormLocalConfig.tsx
Normal file
29
ui/src/components/access/AccessEditFormLocalConfig.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Form, type FormInstance } from "antd";
|
||||
|
||||
import { type LocalAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormLocalConfigModelType = Partial<LocalAccessConfig>;
|
||||
|
||||
export type AccessEditFormLocalConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormLocalConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormLocalConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormLocalConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormLocalConfig = ({ form, disabled, loading, model }: AccessEditFormLocalConfigProps) => {
|
||||
const [initialValues, setInitialValues] = useState(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
return <Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm"></Form>;
|
||||
};
|
||||
|
||||
export default AccessEditFormLocalConfig;
|
58
ui/src/components/access/AccessEditFormNameSiloConfig.tsx
Normal file
58
ui/src/components/access/AccessEditFormNameSiloConfig.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type NameSiloAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormNameSiloConfigModelType = Partial<NameSiloAccessConfig>;
|
||||
|
||||
export type AccessEditFormNameSiloConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormNameSiloConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormNameSiloConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormNameSiloConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormNameSiloConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormNameSiloConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
apiKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.namesilo_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormNameSiloConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="apiKey"
|
||||
label={t("access.form.namesilo_api_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.namesilo_api_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.namesilo_api_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormNameSiloConfig;
|
68
ui/src/components/access/AccessEditFormPowerDNSConfig.tsx
Normal file
68
ui/src/components/access/AccessEditFormPowerDNSConfig.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type PowerDNSAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormPowerDNSConfigModelType = Partial<PowerDNSAccessConfig>;
|
||||
|
||||
export type AccessEditFormPowerDNSConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormPowerDNSConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormPowerDNSConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormPowerDNSConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormPowerDNSConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormPowerDNSConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
apiUrl: z.string().url(t("common.errmsg.url_invalid")),
|
||||
apiKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.powerdns_api_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormPowerDNSConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="apiUrl"
|
||||
label={t("access.form.powerdns_api_url.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.powerdns_api_url.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.powerdns_api_url.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="apiKey"
|
||||
label={t("access.form.powerdns_api_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.powerdns_api_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.powerdns_api_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormPowerDNSConfig;
|
72
ui/src/components/access/AccessEditFormQiniuConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormQiniuConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type QiniuAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormQiniuConfigModelType = Partial<QiniuAccessConfig>;
|
||||
|
||||
export type AccessEditFormQiniuConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormQiniuConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormQiniuConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormQiniuConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormQiniuConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormQiniuConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.qiniu_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.qiniu_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormQiniuConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKey"
|
||||
label={t("access.form.qiniu_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.qiniu_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.qiniu_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretKey"
|
||||
label={t("access.form.qiniu_secret_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.qiniu_secret_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.qiniu_secret_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormQiniuConfig;
|
162
ui/src/components/access/AccessEditFormSSHConfig.tsx
Normal file
162
ui/src/components/access/AccessEditFormSSHConfig.tsx
Normal file
@ -0,0 +1,162 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { flushSync } from "react-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, Form, Input, InputNumber, Upload, type FormInstance, type UploadFile, type UploadProps } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
import { Upload as UploadIcon } from "lucide-react";
|
||||
|
||||
import { type SSHAccessConfig } from "@/domain/access";
|
||||
import { readFileContent } from "@/utils/file";
|
||||
|
||||
type AccessEditFormSSHConfigModelType = Partial<SSHAccessConfig>;
|
||||
|
||||
export type AccessEditFormSSHConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormSSHConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormSSHConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {
|
||||
host: "127.0.0.1",
|
||||
port: 22,
|
||||
username: "root",
|
||||
} as AccessEditFormSSHConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormSSHConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormSSHConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
host: z.string().refine(
|
||||
(str) => {
|
||||
const reIpv4 =
|
||||
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
const reIpv6 =
|
||||
/^([\da-fA-F]{1,4}:){6}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)|::([\da−fA−F]1,4:)0,4((25[0−5]|2[0−4]\d|[01]?\d\d?)\.)3(25[0−5]|2[0−4]\d|[01]?\d\d?)|::([\da−fA−F]1,4:)0,4((25[0−5]|2[0−4]\d|[01]?\d\d?)\.)3(25[0−5]|2[0−4]\d|[01]?\d\d?)|^([\da-fA-F]{1,4}:):([\da-fA-F]{1,4}:){0,3}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)|([\da−fA−F]1,4:)2:([\da−fA−F]1,4:)0,2((25[0−5]|2[0−4]\d|[01]?\d\d?)\.)3(25[0−5]|2[0−4]\d|[01]?\d\d?)|([\da−fA−F]1,4:)2:([\da−fA−F]1,4:)0,2((25[0−5]|2[0−4]\d|[01]?\d\d?)\.)3(25[0−5]|2[0−4]\d|[01]?\d\d?)|^([\da-fA-F]{1,4}:){3}:([\da-fA-F]{1,4}:){0,1}((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)|([\da−fA−F]1,4:)4:((25[0−5]|2[0−4]\d|[01]?\d\d?)\.)3(25[0−5]|2[0−4]\d|[01]?\d\d?)|([\da−fA−F]1,4:)4:((25[0−5]|2[0−4]\d|[01]?\d\d?)\.)3(25[0−5]|2[0−4]\d|[01]?\d\d?)|^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}|:((:[\da−fA−F]1,4)1,6|:)|:((:[\da−fA−F]1,4)1,6|:)|^[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,5}|:)|([\da−fA−F]1,4:)2((:[\da−fA−F]1,4)1,4|:)|([\da−fA−F]1,4:)2((:[\da−fA−F]1,4)1,4|:)|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]{1,4}){1,3}|:)|([\da−fA−F]1,4:)4((:[\da−fA−F]1,4)1,2|:)|([\da−fA−F]1,4:)4((:[\da−fA−F]1,4)1,2|:)|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?|([\da−fA−F]1,4:)6:|([\da−fA−F]1,4:)6:/;
|
||||
const reDomain = /^(?:\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$/;
|
||||
return reIpv4.test(str) || reIpv6.test(str) || reDomain.test(str);
|
||||
},
|
||||
{ message: t("common.errmsg.host_invalid") }
|
||||
),
|
||||
port: z
|
||||
.number()
|
||||
.int()
|
||||
.gte(1, t("common.errmsg.port_invalid"))
|
||||
.lte(65535, t("common.errmsg.port_invalid"))
|
||||
.transform((v) => +v),
|
||||
username: z
|
||||
.string()
|
||||
.min(1, "access.form.ssh_username.placeholder")
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
password: z
|
||||
.string()
|
||||
.min(0, "access.form.ssh_password.placeholder")
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 }))
|
||||
.nullish(),
|
||||
key: z
|
||||
.string()
|
||||
.min(0, "access.form.ssh_key.placeholder")
|
||||
.max(20480, t("common.errmsg.string_max", { max: 20480 }))
|
||||
.nullish(),
|
||||
keyPassphrase: z
|
||||
.string()
|
||||
.min(0, "access.form.ssh_key_passphrase.placeholder")
|
||||
.max(20480, t("common.errmsg.string_max", { max: 20480 }))
|
||||
.nullish(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
setKeyFileList(model?.key?.trim() ? [{ uid: "-1", name: "sshkey", status: "done" }] : []);
|
||||
}, [model]);
|
||||
|
||||
const [keyFileList, setKeyFileList] = useState<UploadFile[]>([]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormSSHConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
const handleUploadChange: UploadProps["onChange"] = async ({ file }) => {
|
||||
if (file && file.status !== "removed") {
|
||||
form.setFieldValue("kubeConfig", (await readFileContent(file.originFileObj ?? (file as unknown as File))).trim());
|
||||
setKeyFileList([file]);
|
||||
} else {
|
||||
form.setFieldValue("kubeConfig", "");
|
||||
setKeyFileList([]);
|
||||
}
|
||||
|
||||
flushSync(() => onModelChange?.(form.getFieldsValue()));
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<div className="flex space-x-2">
|
||||
<div className="w-2/3">
|
||||
<Form.Item name="host" label={t("access.form.ssh_host.label")} rules={[formRule]}>
|
||||
<Input placeholder={t("access.form.ssh_host.placeholder")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<div className="w-1/3">
|
||||
<Form.Item name="port" label={t("access.form.ssh_port.label")} rules={[formRule]}>
|
||||
<InputNumber className="w-full" placeholder={t("access.form.ssh_port.placeholder")} min={1} max={65535} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-2">
|
||||
<div className="w-1/2">
|
||||
<Form.Item name="username" label={t("access.form.ssh_username.label")} rules={[formRule]}>
|
||||
<Input placeholder={t("access.form.ssh_username.placeholder")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<div className="w-1/2">
|
||||
<Form.Item
|
||||
name="password"
|
||||
label={t("access.form.ssh_password.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ssh_password.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.ssh_password.placeholder")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-2">
|
||||
<div className="w-1/2">
|
||||
<Form.Item
|
||||
name="key"
|
||||
label={t("access.form.ssh_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ssh_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.TextArea hidden placeholder={t("access.form.ssh_key.placeholder")} value={form.getFieldValue("key")} />
|
||||
<Upload beforeUpload={() => false} fileList={keyFileList} maxCount={1} onChange={handleUploadChange}>
|
||||
<Button icon={<UploadIcon size={16} />}>{t("access.form.ssh_key.upload")}</Button>
|
||||
</Upload>
|
||||
</Form.Item>
|
||||
</div>
|
||||
|
||||
<div className="w-1/2">
|
||||
<Form.Item
|
||||
name="keyPassphrase"
|
||||
label={t("access.form.ssh_key_passphrase.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.ssh_key_passphrase.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.ssh_key_passphrase.placeholder")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormSSHConfig;
|
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type TencentCloudAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormTencentCloudConfigModelType = Partial<TencentCloudAccessConfig>;
|
||||
|
||||
export type AccessEditFormTencentCloudConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormTencentCloudConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormTencentCloudConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormTencentCloudConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormTencentCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormTencentCloudConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
secretId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.tencentcloud_secret_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.tencentcloud_secret_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormTencentCloudConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="secretId"
|
||||
label={t("access.form.tencentcloud_secret_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.tencentcloud_secret_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.tencentcloud_secret_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretKey"
|
||||
label={t("access.form.tencentcloud_secret_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.tencentcloud_secret_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.tencentcloud_secret_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormTencentCloudConfig;
|
72
ui/src/components/access/AccessEditFormVolcEngineConfig.tsx
Normal file
72
ui/src/components/access/AccessEditFormVolcEngineConfig.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type VolcEngineAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormVolcEngineConfigModelType = Partial<VolcEngineAccessConfig>;
|
||||
|
||||
export type AccessEditFormVolcEngineConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormVolcEngineConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormVolcEngineConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormVolcEngineConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormVolcEngineConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormVolcEngineConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
accessKeyId: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.volcengine_access_key_id.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
secretAccessKey: z
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, t("access.form.volcengine_secret_access_key.placeholder"))
|
||||
.max(64, t("common.errmsg.string_max", { max: 64 })),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormVolcEngineConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item
|
||||
name="accessKeyId"
|
||||
label={t("access.form.volcengine_access_key_id.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.volcengine_access_key_id.tooltip") }}></span>}
|
||||
>
|
||||
<Input placeholder={t("access.form.volcengine_access_key_id.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="secretAccessKey"
|
||||
label={t("access.form.volcengine_secret_access_key.label")}
|
||||
rules={[formRule]}
|
||||
tooltip={<span dangerouslySetInnerHTML={{ __html: t("access.form.volcengine_secret_access_key.tooltip") }}></span>}
|
||||
>
|
||||
<Input.Password placeholder={t("access.form.volcengine_secret_access_key.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormVolcEngineConfig;
|
49
ui/src/components/access/AccessEditFormWebhookConfig.tsx
Normal file
49
ui/src/components/access/AccessEditFormWebhookConfig.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Form, Input, type FormInstance } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { type WebhookAccessConfig } from "@/domain/access";
|
||||
|
||||
type AccessEditFormWebhookConfigModelType = Partial<WebhookAccessConfig>;
|
||||
|
||||
export type AccessEditFormWebhookConfigProps = {
|
||||
form: FormInstance;
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
model?: AccessEditFormWebhookConfigModelType;
|
||||
onModelChange?: (model: AccessEditFormWebhookConfigModelType) => void;
|
||||
};
|
||||
|
||||
const initModel = () => {
|
||||
return {} as AccessEditFormWebhookConfigModelType;
|
||||
};
|
||||
|
||||
const AccessEditFormWebhookConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormWebhookConfigProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
url: z.string().url(t("common.errmsg.url_invalid")),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
|
||||
const [initialValues, setInitialValues] = useState<Partial<z.infer<typeof formSchema>>>(model ?? initModel());
|
||||
useEffect(() => {
|
||||
setInitialValues(model ?? initModel());
|
||||
}, [model]);
|
||||
|
||||
const handleFormChange = (_: unknown, fields: AccessEditFormWebhookConfigModelType) => {
|
||||
onModelChange?.(fields);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
|
||||
<Form.Item name="url" label={t("access.form.webhook_url.label")} rules={[formRule]}>
|
||||
<Input placeholder={t("access.form.webhook_url.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditFormWebhookConfig;
|
108
ui/src/components/access/AccessEditModal.tsx
Normal file
108
ui/src/components/access/AccessEditModal.tsx
Normal file
@ -0,0 +1,108 @@
|
||||
import { cloneElement, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Modal, notification } from "antd";
|
||||
|
||||
import { type AccessModel } from "@/domain/access";
|
||||
import { useAccessStore } from "@/stores/access";
|
||||
import AccessEditForm, { type AccessEditFormInstance } from "./AccessEditForm";
|
||||
|
||||
export type AccessEditModalProps = {
|
||||
data?: Partial<AccessModel>;
|
||||
loading?: boolean;
|
||||
mode: "add" | "edit" | "copy";
|
||||
open?: boolean;
|
||||
trigger?: React.ReactElement;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
};
|
||||
|
||||
const AccessEditModal = ({ data, loading, mode, trigger, ...props }: AccessEditModalProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||
|
||||
const { createAccess, updateAccess } = useAccessStore();
|
||||
|
||||
const [open, setOpen] = useControllableValue<boolean>(props, {
|
||||
valuePropName: "open",
|
||||
defaultValuePropName: "defaultOpen",
|
||||
trigger: "onOpenChange",
|
||||
});
|
||||
|
||||
const triggerEl = useMemo(() => {
|
||||
if (!trigger) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cloneElement(trigger, {
|
||||
...trigger.props,
|
||||
onClick: () => {
|
||||
setOpen(true);
|
||||
trigger.props?.onClick?.();
|
||||
},
|
||||
});
|
||||
}, [trigger, setOpen]);
|
||||
|
||||
const formRef = useRef<AccessEditFormInstance>(null);
|
||||
const [formPending, setFormPending] = useState(false);
|
||||
|
||||
const handleClickOk = async () => {
|
||||
setFormPending(true);
|
||||
try {
|
||||
await formRef.current!.validateFields();
|
||||
} catch (err) {
|
||||
setFormPending(false);
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
try {
|
||||
if (mode === "add") {
|
||||
await createAccess(formRef.current!.getFieldsValue() as AccessModel);
|
||||
} else {
|
||||
await updateAccess({ ...data, ...formRef.current!.getFieldsValue() } as AccessModel);
|
||||
}
|
||||
|
||||
setOpen(false);
|
||||
} catch (err) {
|
||||
notificationApi.error({ message: t("common.text.request_error"), description: <>{String(err)}</> });
|
||||
|
||||
throw err;
|
||||
} finally {
|
||||
setFormPending(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClickCancel = () => {
|
||||
if (formPending) return Promise.reject();
|
||||
|
||||
setOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{NotificationContextHolder}
|
||||
|
||||
{triggerEl}
|
||||
|
||||
<Modal
|
||||
afterClose={() => setOpen(false)}
|
||||
cancelButtonProps={{ disabled: formPending }}
|
||||
closable
|
||||
confirmLoading={formPending}
|
||||
destroyOnClose
|
||||
loading={loading}
|
||||
okText={mode === "edit" ? t("common.button.save") : t("common.button.submit")}
|
||||
open={open}
|
||||
title={t(`access.action.${mode}`)}
|
||||
onOk={handleClickOk}
|
||||
onCancel={handleClickCancel}
|
||||
>
|
||||
<div className="pt-4 pb-2">
|
||||
<AccessEditForm ref={formRef} mode={mode === "add" ? "add" : "edit"} model={data} />
|
||||
</div>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccessEditModal;
|
@ -15,17 +15,44 @@ const AccessTypeSelect = memo((props: AccessTypeSelectProps) => {
|
||||
label: t(item.name),
|
||||
}));
|
||||
|
||||
const renderOption = (key: string) => {
|
||||
const provider = accessProvidersMap.get(key);
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-4 max-w-full overflow-hidden">
|
||||
<Space className="flex-grow max-w-full truncate" size={4}>
|
||||
<Avatar src={provider?.icon} size="small" />
|
||||
<Typography.Text className="leading-loose" ellipsis>
|
||||
{t(provider?.name ?? "")}
|
||||
</Typography.Text>
|
||||
</Space>
|
||||
<div>
|
||||
{provider?.usage === "apply" && (
|
||||
<>
|
||||
<Tag color="orange">{t("access.props.provider.usage.dns")}</Tag>
|
||||
</>
|
||||
)}
|
||||
{provider?.usage === "deploy" && (
|
||||
<>
|
||||
<Tag color="blue">{t("access.props.provider.usage.host")}</Tag>
|
||||
</>
|
||||
)}
|
||||
{provider?.usage === "all" && (
|
||||
<>
|
||||
<Tag color="orange">{t("access.props.provider.usage.dns")}</Tag>
|
||||
<Tag color="blue">{t("access.props.provider.usage.host")}</Tag>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Select
|
||||
{...props}
|
||||
labelRender={({ label, value }) => {
|
||||
if (label) {
|
||||
return (
|
||||
<Space className="max-w-full truncate" size={4}>
|
||||
<Avatar src={accessProvidersMap.get(String(value))?.icon} size="small" />
|
||||
{label}
|
||||
</Space>
|
||||
);
|
||||
return renderOption(value as string);
|
||||
}
|
||||
|
||||
return <Typography.Text type="secondary">{props.placeholder}</Typography.Text>;
|
||||
@ -33,32 +60,7 @@ const AccessTypeSelect = memo((props: AccessTypeSelectProps) => {
|
||||
options={options}
|
||||
optionFilterProp={undefined}
|
||||
optionLabelProp={undefined}
|
||||
optionRender={(option) => (
|
||||
<div className="flex items-center justify-between gap-4 max-w-full overflow-hidden">
|
||||
<Space className="flex-grow max-w-full truncate" size={4}>
|
||||
<Avatar src={accessProvidersMap.get(option.data.value)?.icon} size="small" />
|
||||
<Typography.Text ellipsis>{t(accessProvidersMap.get(option.data.value)?.name ?? "")}</Typography.Text>
|
||||
</Space>
|
||||
<div>
|
||||
{accessProvidersMap.get(option.data.value)?.usage === "apply" && (
|
||||
<>
|
||||
<Tag color="orange">{t("access.props.provider.usage.dns")}</Tag>
|
||||
</>
|
||||
)}
|
||||
{accessProvidersMap.get(option.data.value)?.usage === "deploy" && (
|
||||
<>
|
||||
<Tag color="blue">{t("access.props.provider.usage.host")}</Tag>
|
||||
</>
|
||||
)}
|
||||
{accessProvidersMap.get(option.data.value)?.usage === "all" && (
|
||||
<>
|
||||
<Tag color="orange">{t("access.props.provider.usage.dns")}</Tag>
|
||||
<Tag color="blue">{t("access.props.provider.usage.host")}</Tag>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
optionRender={(option) => renderOption(option.data.value)}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ import dayjs from "dayjs";
|
||||
import { type CertificateModel } from "@/domain/certificate";
|
||||
import { saveFiles2Zip } from "@/utils/file";
|
||||
|
||||
type CertificateDetailProps = {
|
||||
export type CertificateDetailProps = {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
data: CertificateModel;
|
||||
|
@ -1,30 +1,26 @@
|
||||
import { cloneElement, useEffect, useMemo, useState } from "react";
|
||||
import { cloneElement, useMemo } from "react";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Drawer } from "antd";
|
||||
|
||||
import { type CertificateModel } from "@/domain/certificate";
|
||||
import CertificateDetail from "./CertificateDetail";
|
||||
|
||||
type CertificateDetailDrawerProps = {
|
||||
export type CertificateDetailDrawerProps = {
|
||||
data?: CertificateModel;
|
||||
loading?: boolean;
|
||||
open?: boolean;
|
||||
trigger?: React.ReactElement;
|
||||
onOpenChange?: (open: boolean) => void;
|
||||
};
|
||||
|
||||
const CertificateDetailDrawer = ({ data, trigger, ...props }: CertificateDetailDrawerProps) => {
|
||||
const CertificateDetailDrawer = ({ data, loading, trigger, ...props }: CertificateDetailDrawerProps) => {
|
||||
const [open, setOpen] = useControllableValue<boolean>(props, {
|
||||
valuePropName: "open",
|
||||
defaultValuePropName: "defaultOpen",
|
||||
trigger: "onOpenChange",
|
||||
});
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
setLoading(data == null);
|
||||
}, [data]);
|
||||
|
||||
const triggerDom = useMemo(() => {
|
||||
const triggerEl = useMemo(() => {
|
||||
if (!trigger) {
|
||||
return null;
|
||||
}
|
||||
@ -40,7 +36,7 @@ const CertificateDetailDrawer = ({ data, trigger, ...props }: CertificateDetailD
|
||||
|
||||
return (
|
||||
<>
|
||||
{triggerDom}
|
||||
{triggerEl}
|
||||
|
||||
<Drawer closable destroyOnClose open={open} loading={loading} placement="right" width={480} onClose={() => setOpen(false)}>
|
||||
{data ? <CertificateDetail data={data} /> : <></>}
|
||||
|
@ -10,7 +10,7 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/component
|
||||
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||
import AccessEditDialog from "@/components/certimate/AccessEditDialog";
|
||||
import AccessEditModal from "@/components/access/AccessEditModal";
|
||||
import EmailsEdit from "@/components/certimate/EmailsEdit";
|
||||
import StringList from "@/components/certimate/StringList";
|
||||
|
||||
@ -165,14 +165,14 @@ const ApplyForm = ({ data }: ApplyFormProps) => {
|
||||
<FormItem>
|
||||
<FormLabel className="flex justify-between w-full">
|
||||
<div>{t("domain.application.form.access.label")}</div>
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="flex items-center font-normal cursor-pointer text-primary hover:underline">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -15,7 +15,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -106,15 +106,15 @@ const DeployToAliyunALB = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="aliyun"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -86,15 +86,15 @@ const DeployToAliyunCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="aliyun"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -15,7 +15,7 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -106,15 +106,15 @@ const DeployToAliyunCLB = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="aliyun"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -17,7 +17,7 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectVa
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -97,15 +97,15 @@ const DeployToAliyunOSS = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "aliyun" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="aliyun"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -86,15 +86,15 @@ const DeployToBaiduCloudCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "baiducloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="baiducloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -86,15 +86,15 @@ const DeployToByteplusCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "byteplus" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="byteplus"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -17,7 +17,7 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectVa
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import { Plus } from "lucide-react";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
updateNode: state.updateNode,
|
||||
@ -87,15 +87,15 @@ const DeployToDogeCloudCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "dogecloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="dogecloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -17,7 +17,7 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectVa
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -92,15 +92,15 @@ const DeployToHuaweiCloudCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "huaweicloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="huaweicloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -15,7 +15,7 @@ import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
|
||||
@ -114,15 +114,15 @@ const DeployToHuaweiCloudELB = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "huaweicloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="huaweicloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -15,7 +15,7 @@ import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
|
||||
@ -101,15 +101,15 @@ const DeployToKubernetesSecret = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "k8s" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="k8s"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { WorkflowNode } from "@/domain/workflow";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -211,15 +211,15 @@ Remove-Item -Path "$pfxPath" -Force
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "local" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="local"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -87,15 +87,15 @@ const DeployToQiniuCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "qiniu" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="qiniu"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -15,7 +15,7 @@ import i18n from "@/i18n";
|
||||
import { WorkflowNode } from "@/domain/workflow";
|
||||
import { Textarea } from "../ui/textarea";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -129,15 +129,15 @@ const DeployToSSH = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "ssh" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="ssh"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -86,15 +86,15 @@ const DeployToTencentCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="tencentcloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
type TencentResourceType = "ssl-deploy" | "loadbalancer" | "listener" | "ruledomain";
|
||||
@ -126,15 +126,15 @@ const DeployToTencentCLB = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="tencentcloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -15,7 +15,7 @@ import { Button } from "../ui/button";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
@ -92,15 +92,15 @@ const DeployToTencentCOS = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="tencentcloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -89,15 +89,15 @@ const DeployToTencentTEO = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "tencentcloud" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="tencentcloud"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -86,15 +86,15 @@ const DeployToVolcengineCDN = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "volcengine" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="volcengine"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -86,15 +86,15 @@ const DeployToVolcengineLive = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "volcengine" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="volcengine"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -16,7 +16,7 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectVa
|
||||
import { SelectLabel } from "@radix-ui/react-select";
|
||||
import KVList from "../certimate/KVList";
|
||||
import AccessSelect from "./AccessSelect";
|
||||
import AccessEditDialog from "../certimate/AccessEditDialog";
|
||||
import AccessEditModal from "../access/AccessEditModal";
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
const selectState = (state: WorkflowState) => ({
|
||||
@ -90,15 +90,15 @@ const DeployToWebhook = ({ data }: DeployFormProps) => {
|
||||
<FormLabel className="flex justify-between">
|
||||
<div>{t("domain.deployment.form.access.label")}</div>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ configType: "webhook" }}
|
||||
mode="add"
|
||||
trigger={
|
||||
<div className="font-normal text-primary hover:underline cursor-pointer flex items-center">
|
||||
<Plus size={14} />
|
||||
{t("common.button.add")}
|
||||
</div>
|
||||
}
|
||||
op="add"
|
||||
outConfigType="webhook"
|
||||
/>
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
|
@ -65,7 +65,7 @@ export interface AccessModel extends Omit<BaseModel, "created" | "updated"> {
|
||||
| HuaweiCloudAccessConfig
|
||||
| KubernetesAccessConfig
|
||||
| LocalAccessConfig
|
||||
| NamesiloAccessConfig
|
||||
| NameSiloAccessConfig
|
||||
| PowerDNSAccessConfig
|
||||
| QiniuAccessConfig
|
||||
| SSHAccessConfig
|
||||
@ -119,18 +119,18 @@ export type GoDaddyAccessConfig = {
|
||||
};
|
||||
|
||||
export type HuaweiCloudAccessConfig = {
|
||||
region: string;
|
||||
accessKeyId: string;
|
||||
secretAccessKey: string;
|
||||
region?: string;
|
||||
};
|
||||
|
||||
export type KubernetesAccessConfig = {
|
||||
kubeConfig: string;
|
||||
kubeConfig?: string;
|
||||
};
|
||||
|
||||
export type LocalAccessConfig = never;
|
||||
|
||||
export type NamesiloAccessConfig = {
|
||||
export type NameSiloAccessConfig = {
|
||||
apiKey: string;
|
||||
};
|
||||
|
||||
@ -146,11 +146,10 @@ export type QiniuAccessConfig = {
|
||||
|
||||
export type SSHAccessConfig = {
|
||||
host: string;
|
||||
port: string;
|
||||
port: number;
|
||||
username: string;
|
||||
password?: string;
|
||||
key?: string;
|
||||
keyFile?: string;
|
||||
keyPassphrase?: string;
|
||||
};
|
||||
|
||||
@ -168,12 +167,10 @@ export type WebhookAccessConfig = {
|
||||
url: string;
|
||||
};
|
||||
|
||||
type AccessTypes = (typeof ACCESS_PROVIDER_TYPES)[keyof typeof ACCESS_PROVIDER_TYPES];
|
||||
|
||||
type AccessUsages = "apply" | "deploy" | "all";
|
||||
|
||||
type AccessProvider = {
|
||||
type: AccessTypes;
|
||||
type: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
usage: AccessUsages;
|
||||
@ -203,7 +200,7 @@ export const accessProvidersMap: Map<AccessProvider["type"], AccessProvider> = n
|
||||
[ACCESS_PROVIDER_TYPE_WEBHOOK, "common.provider.webhook", "/imgs/providers/webhook.svg", "deploy"],
|
||||
[ACCESS_PROVIDER_TYPE_KUBERNETES, "common.provider.kubernetes", "/imgs/providers/kubernetes.svg", "deploy"],
|
||||
[ACCESS_PROVIDER_TYPE_ACMEHTTPREQ, "common.provider.acmehttpreq", "/imgs/providers/acmehttpreq.svg", "apply"],
|
||||
].map(([type, name, icon, usage]) => [type as AccessTypes, { type: type as AccessTypes, name, icon, usage: usage as AccessUsages }])
|
||||
].map(([type, name, icon, usage]) => [type, { type, name, icon, usage: usage as AccessUsages }])
|
||||
);
|
||||
|
||||
export const accessTypeFormSchema = z.union(
|
||||
|
@ -20,6 +20,122 @@
|
||||
"access.form.name.placeholder": "Please enter authorization name",
|
||||
"access.form.type.label": "Provider",
|
||||
"access.form.type.placeholder": "Please select a provider",
|
||||
"access.form.type.tooltip": "DNS Provider: The provider that hosts your domain names and manages your DNS records.<br>Host Provider: The provider that hosts your servers or cloud services for deploying certificates.<br><br><i>Cannot be edited after saving.</i>",
|
||||
"access.form.acmehttpreq_endpoint.label": "Endpoint",
|
||||
"access.form.acmehttpreq_endpoint.placeholder": "Please enter Endpoint",
|
||||
"access.form.acmehttpreq_endpoint.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.acmehttpreq_mode.label": "Mode",
|
||||
"access.form.acmehttpreq_mode.placeholder": "Please select mode",
|
||||
"access.form.acmehttpreq_mode.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.acmehttpreq_username.label": "HTTP Basic Auth Username",
|
||||
"access.form.acmehttpreq_username.placeholder": "Please enter HTTP basic auth username",
|
||||
"access.form.acmehttpreq_username.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.acmehttpreq_password.label": "HTTP Basic Auth Password",
|
||||
"access.form.acmehttpreq_password.placeholder": "Please enter HTTP basic auth password",
|
||||
"access.form.acmehttpreq_password.tooltip": "For more information, see <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.aliyun_access_key_id.label": "Aliyun Access Key ID",
|
||||
"access.form.aliyun_access_key_id.placeholder": "Please enter Aliyun Access Key ID",
|
||||
"access.form.aliyun_access_key_id.tooltip": "For more information, see <a href=\"https://www.alibabacloud.com/help/en/acr/create-and-obtain-an-accesskey-pair\" target=\"_blank\">https://www.alibabacloud.com/help/en/acr/create-and-obtain-an-accesskey-pair</a>",
|
||||
"access.form.aliyun_access_key_secret.label": "Aliyun Access Key Secret",
|
||||
"access.form.aliyun_access_key_secret.placeholder": "Please enter Aliyun Access Key Secret",
|
||||
"access.form.aliyun_access_key_secret.tooltip": "For more information, see <a href=\"https://www.alibabacloud.com/help/en/acr/create-and-obtain-an-accesskey-pair\" target=\"_blank\">https://www.alibabacloud.com/help/en/acr/create-and-obtain-an-accesskey-pair</a>",
|
||||
"access.form.aws_access_key_id.label": "AWS Access Key ID",
|
||||
"access.form.aws_access_key_id.placeholder": "Please enter AWS Access Key ID",
|
||||
"access.form.aws_access_key_id.tooltip": "For more information, see <a href=\"https://docs.aws.amazon.com/en_us/IAM/latest/UserGuide/id_credentials_access-keys.html\" target=\"_blank\">https://docs.aws.amazon.com/en_us/IAM/latest/UserGuide/id_credentials_access-keys.html</a>",
|
||||
"access.form.aws_secret_access_key.label": "AWS Secret Access Key",
|
||||
"access.form.aws_secret_access_key.placeholder": "Please enter AWS Secret Access Key",
|
||||
"access.form.aws_secret_access_key.tooltip": "For more information, see <a href=\"https://docs.aws.amazon.com/en_us/IAM/latest/UserGuide/id_credentials_access-keys.html\" target=\"_blank\">https://docs.aws.amazon.com/en_us/IAM/latest/UserGuide/id_credentials_access-keys.html</a>",
|
||||
"access.form.aws_region.label": "AWS Region",
|
||||
"access.form.aws_region.placeholder": "Please enter AWS Region (example: us-east-1)",
|
||||
"access.form.aws_region.tooltip": "For more information, see <a href=\"https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/en_us/general/latest/gr/rande.html#regional-endpoints</a>",
|
||||
"access.form.aws_hosted_zone_id.label": "AWS Hosted Zone ID",
|
||||
"access.form.aws_hosted_zone_id.placeholder": "Please enter AWS Hosted Zone ID",
|
||||
"access.form.aws_hosted_zone_id.tooltip": "For more information, see <a href=\"https://docs.aws.amazon.com/en_us/Route53/latest/DeveloperGuide/hosted-zones-working-with.html\" target=\"_blank\">https://docs.aws.amazon.com/en_us/Route53/latest/DeveloperGuide/hosted-zones-working-with.html</a>",
|
||||
"access.form.baiducloud_access_key_id.label": "Baidu Cloud Access Key ID",
|
||||
"access.form.baiducloud_access_key_id.placeholder": "Please enter Baidu Cloud Access Key ID",
|
||||
"access.form.baiducloud_access_key_id.tooltip": "For more information, see <a href=\"https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en\" target=\"_blank\">https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en</a>",
|
||||
"access.form.baiducloud_secret_access_key.label": "Baidu Cloud Secret Access Key",
|
||||
"access.form.baiducloud_secret_access_key.placeholder": "Please enter Baidu Cloud Secret Access Key",
|
||||
"access.form.baiducloud_secret_access_key.tooltip": "For more information, see <a href=\"https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en\" target=\"_blank\">https://intl.cloud.baidu.com/doc/Reference/s/jjwvz2e3p-en</a>",
|
||||
"access.form.byteplus_access_key.label": "BytePlus Access Key",
|
||||
"access.form.byteplus_access_key.placeholder": "Please enter BytePlus Access Key",
|
||||
"access.form.byteplus_access_key.tooltip": "For more information, see <a href=\"https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys</a>",
|
||||
"access.form.byteplus_secret_key.label": "BytePlus Secret Key",
|
||||
"access.form.byteplus_secret_key.placeholder": "Please enter BytePlus Secret Key",
|
||||
"access.form.byteplus_secret_key.tooltip": "For more information, see <a href=\"https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/en/docs/byteplus-platform/docs-managing-keys</a>",
|
||||
"access.form.cloudflare_dns_api_token.label": "Cloudflare API Token",
|
||||
"access.form.cloudflare_dns_api_token.placeholder": "Please enter Cloudflare API Token",
|
||||
"access.form.cloudflare_dns_api_token.tooltip": "For more information, see <a href=\"https://developers.cloudflare.com/fundamentals/api/get-started/create-token/\" target=\"_blank\">https://developers.cloudflare.com/fundamentals/api/get-started/create-token/</a>",
|
||||
"access.form.dogecloud_access_key.label": "Doge Cloud Access Key",
|
||||
"access.form.dogecloud_access_key.placeholder": "Please enter Doge Cloud Access Key",
|
||||
"access.form.dogecloud_access_key.tooltip": "For more information, see <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"access.form.dogecloud_secret_key.label": "Doge Cloud Secret Key",
|
||||
"access.form.dogecloud_secret_key.placeholder": "Please enter Doge Cloud Secret Key",
|
||||
"access.form.dogecloud_secret_key.tooltip": "For more information, see <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"access.form.godaddy_api_key.label": "GoDaddy API Key",
|
||||
"access.form.godaddy_api_key.placeholder": "Please enter GoDaddy API Key",
|
||||
"access.form.godaddy_api_key.tooltip": "For more information, see <a href=\"https://developer.godaddy.com/\" target=\"_blank\">https://developer.godaddy.com/</a>",
|
||||
"access.form.godaddy_api_secret.label": "GoDaddy API Secret",
|
||||
"access.form.godaddy_api_secret.placeholder": "Please enter GoDaddy API Secret",
|
||||
"access.form.godaddy_api_secret.tooltip": "For more information, see <a href=\"https://developer.godaddy.com/\" target=\"_blank\">https://developer.godaddy.com/</a>",
|
||||
"access.form.huaweicloud_access_key_id.label": "Huawei Cloud Access Key ID",
|
||||
"access.form.huaweicloud_access_key_id.placeholder": "Please enter Huawei Cloud Access Key ID",
|
||||
"access.form.huaweicloud_access_key_id.tooltip": "For more information, see <a href=\"https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html</a>",
|
||||
"access.form.huaweicloud_secret_access_key.label": "Huawei Cloud Secret Access Key",
|
||||
"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 <a href=\"https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/intl/en-us/usermanual-ca/ca_01_0003.html</a>",
|
||||
"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.tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/apiexplorer/#/endpoint?locale=en-us\" target=\"_blank\">https://console-intl.huaweicloud.com/apiexplorer/#/endpoint</a>",
|
||||
"access.form.k8s_kubeconfig.label": "KubeConfig",
|
||||
"access.form.k8s_kubeconfig.placeholder": "Please enter KubeConfig file",
|
||||
"access.form.k8s_kubeconfig.upload": "Choose File ...",
|
||||
"access.form.k8s_kubeconfig.tooltip": "For more information, see <a href=\"https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/\" target=\"_blank\">https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/</a><br><br>If empty, the Pod's ServiceAccount will be used.",
|
||||
"access.form.namesilo_api_key.label": "NameSilo API Key",
|
||||
"access.form.namesilo_api_key.placeholder": "Please enter NameSilo API Key",
|
||||
"access.form.namesilo_api_key.tooltip": "For more information, see <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>",
|
||||
"access.form.powerdns_api_url.label": "PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.placeholder": "Please enter PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.tooltip": "For more information, see <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api</a>",
|
||||
"access.form.powerdns_api_key.label": "PowerDNS API Key",
|
||||
"access.form.powerdns_api_key.placeholder": "Please enter PowerDNS API Key",
|
||||
"access.form.powerdns_api_key.tooltip": "For more information, see <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api</a>",
|
||||
"access.form.qiniu_access_key.label": "Qiniu Access Key",
|
||||
"access.form.qiniu_access_key.placeholder": "Please enter Qiniu Access Key",
|
||||
"access.form.qiniu_access_key.tooltip": "For more information, see <a href=\"https://portal.qiniu.com/\" target=\"_blank\">https://portal.qiniu.com/</a>",
|
||||
"access.form.qiniu_secret_key.label": "Qiniu Secret Key",
|
||||
"access.form.qiniu_secret_key.placeholder": "Please enter Qiniu Secret Key",
|
||||
"access.form.qiniu_secret_key.tooltip": "For more information, see <a href=\"https://portal.qiniu.com/\" target=\"_blank\">https://portal.qiniu.com/</a>",
|
||||
"access.form.tencentcloud_secret_id.label": "Tencent Cloud SecretId",
|
||||
"access.form.tencentcloud_secret_id.placeholder": "Please enter Tencent Cloud SecretId",
|
||||
"access.form.tencentcloud_secret_id.tooltip": "For more information, see <a href=\"https://cloud.tencent.com/document/product/598/40488?lang=en\" target=\"_blank\">https://cloud.tencent.com/document/product/598/40488?lang=en</a>",
|
||||
"access.form.tencentcloud_secret_key.label": "Tencent Cloud SecretKey",
|
||||
"access.form.tencentcloud_secret_key.placeholder": "Please enter Tencent Cloud SecretKey",
|
||||
"access.form.tencentcloud_secret_key.tooltip": "For more information, see <a href=\"https://cloud.tencent.com/document/product/598/40488?lang=en\" target=\"_blank\">https://cloud.tencent.com/document/product/598/40488?lang=en</a>",
|
||||
"access.form.volcengine_access_key_id.label": "VolcEngine Access Key ID",
|
||||
"access.form.volcengine_access_key_id.placeholder": "Please enter VolcEngine Access Key ID",
|
||||
"access.form.volcengine_access_key_id.tooltip": "For more information, see <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
|
||||
"access.form.volcengine_secret_access_key.label": "VolcEngine Secret Access Key",
|
||||
"access.form.volcengine_secret_access_key.placeholder": "Please enter VolcEngine Secret Access Key",
|
||||
"access.form.volcengine_secret_access_key.tooltip": "For more information, see <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
|
||||
"access.form.webhook_url.label": "Webhook URL",
|
||||
"access.form.webhook_url.placeholder": "Please enter Webhook URL",
|
||||
"access.form.ssh_host.label": "Server Host",
|
||||
"access.form.ssh_host.placeholder": "Please enter server host",
|
||||
"access.form.ssh_port.label": "Server Port",
|
||||
"access.form.ssh_port.placeholder": "Please enter server port",
|
||||
"access.form.ssh_username.label": "Username",
|
||||
"access.form.ssh_username.placeholder": "Please enter username",
|
||||
"access.form.ssh_password.label": "Password",
|
||||
"access.form.ssh_password.placeholder": "Please enter password",
|
||||
"access.form.ssh_password.tooltip": "Required when using password to connect to SSH.",
|
||||
"access.form.ssh_key.label": "SSH Key",
|
||||
"access.form.ssh_key.placeholder": "Please enter SSH Key",
|
||||
"access.form.ssh_key.upload": "Choose File ...",
|
||||
"access.form.ssh_key.tooltip": "Required when using key to connect to SSH.",
|
||||
"access.form.ssh_key_passphrase.label": "SSH Key Passphrase",
|
||||
"access.form.ssh_key_passphrase.placeholder": "Please enter SSH Key passphrase",
|
||||
"access.form.ssh_key_passphrase.tooltip": "Optional when using key to connect to SSH.",
|
||||
"access.form.region.label": "Region",
|
||||
"access.form.region.placeholder": "Please enter Region",
|
||||
"access.form.access_key_id.label": "AccessKeyId",
|
||||
@ -36,12 +152,6 @@
|
||||
"access.form.secret_access_key.placeholder": "Please enter SecretAccessKey",
|
||||
"access.form.cloud_dns_api_token.label": "CLOUD_DNS_API_TOKEN",
|
||||
"access.form.cloud_dns_api_token.placeholder": "Please enter CLOUD_DNS_API_TOKEN",
|
||||
"access.form.godaddy_api_key.label": "GO_DADDY_API_KEY",
|
||||
"access.form.godaddy_api_key.placeholder": "Please enter GO_DADDY_API_KEY",
|
||||
"access.form.godaddy_api_secret.label": "GO_DADDY_API_SECRET",
|
||||
"access.form.godaddy_api_secret.placeholder": "Please enter GO_DADDY_API_SECRET",
|
||||
"access.form.namesilo_api_key.label": "NAMESILO_API_KEY",
|
||||
"access.form.namesilo_api_key.placeholder": "Please enter NAMESILO_API_KEY",
|
||||
"access.form.pdns_api_url.label": "PDNS_API_URL",
|
||||
"access.form.pdns_api_url.placeholder": "Please enter PDNS_API_URL",
|
||||
"access.form.pdns_api_key.label": "PDNS_API_KEY",
|
||||
@ -53,25 +163,5 @@
|
||||
"access.form.username.label": "Username",
|
||||
"access.form.username.placeholder": "Please enter username",
|
||||
"access.form.password.label": "Password",
|
||||
"access.form.password.placeholder": "Please enter password",
|
||||
"access.form.access_group.placeholder": "Please select a group",
|
||||
"access.form.ssh_group.label": "Authorization Configuration Group (used to deploy a single domain certificate to multiple SSH hosts)",
|
||||
"access.form.ssh_host.label": "Server Host",
|
||||
"access.form.ssh_host.placeholder": "Please enter Host",
|
||||
"access.form.ssh_port.label": "SSH Port",
|
||||
"access.form.ssh_port.placeholder": "Please enter Port",
|
||||
"access.form.ssh_username.label": "Username",
|
||||
"access.form.ssh_username.placeholder": "Please enter username",
|
||||
"access.form.ssh_password.label": "Password (Log-in using password)",
|
||||
"access.form.ssh_password.placeholder": "Please enter password",
|
||||
"access.form.ssh_key.label": "Key (Log-in using private key)",
|
||||
"access.form.ssh_key.placeholder": "Please enter Key",
|
||||
"access.form.ssh_key_file.placeholder": "Please select file",
|
||||
"access.form.ssh_key_passphrase.label": "Key Passphrase (Log-in using private key)",
|
||||
"access.form.ssh_key_passphrase.placeholder": "Please enter Key Passphrase",
|
||||
"access.form.webhook_url.label": "Webhook URL",
|
||||
"access.form.webhook_url.placeholder": "Please enter Webhook URL",
|
||||
"access.form.k8s_kubeconfig.label": "KubeConfig (Null will use pod's ServiceAccount)",
|
||||
"access.form.k8s_kubeconfig.placeholder": "Please enter KubeConfig",
|
||||
"access.form.k8s_kubeconfig_file.placeholder": "Please select file (Null will use pod's ServiceAccount)"
|
||||
"access.form.password.placeholder": "Please enter password"
|
||||
}
|
||||
|
@ -40,8 +40,9 @@
|
||||
"common.errmsg.email_empty": "Please enter email",
|
||||
"common.errmsg.email_duplicate": "Email already exists",
|
||||
"common.errmsg.domain_invalid": "Please enter domain",
|
||||
"common.errmsg.host_invalid": "Please enter the correct domain name or IP",
|
||||
"common.errmsg.ip_invalid": "Please enter IP",
|
||||
"common.errmsg.host_invalid": "Please enter a valid domain name or IP",
|
||||
"common.errmsg.port_invalid": "Please enter a valid port",
|
||||
"common.errmsg.ip_invalid": "Please enter a valid IP",
|
||||
"common.errmsg.url_invalid": "Please enter a valid URL",
|
||||
|
||||
"common.provider.aliyun": "Alibaba Cloud",
|
||||
@ -68,7 +69,7 @@
|
||||
"common.provider.dogecloud.cdn": "Doge Cloud - CDN",
|
||||
"common.provider.aws": "AWS",
|
||||
"common.provider.cloudflare": "Cloudflare",
|
||||
"common.provider.namesilo": "Namesilo",
|
||||
"common.provider.namesilo": "NameSilo",
|
||||
"common.provider.godaddy": "GoDaddy",
|
||||
"common.provider.powerdns": "PowerDNS",
|
||||
"common.provider.acmehttpreq": "Http Request (ACME Proxy)",
|
||||
|
@ -20,6 +20,122 @@
|
||||
"access.form.name.placeholder": "请输入授权名称",
|
||||
"access.form.type.label": "提供商",
|
||||
"access.form.type.placeholder": "请选择提供商",
|
||||
"access.form.type.tooltip": "提供商分为两种类型:<br>【DNS 提供商】您的域名托管方,用于管理您的域名解析记录。<br>【主机提供商】您的服务器或云服务的托管方,用于部署申请后的证书。<br><br>该字段保存后不可修改。",
|
||||
"access.form.acmehttpreq_endpoint.label": "服务端点",
|
||||
"access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点",
|
||||
"access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.acmehttpreq_mode.label": "模式",
|
||||
"access.form.acmehttpreq_mode.placeholder": "请选择模式",
|
||||
"access.form.acmehttpreq_mode.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.acmehttpreq_username.label": "HTTP 基本认证用户名",
|
||||
"access.form.acmehttpreq_username.placeholder": "请输入 HTTP 基本认证用户名",
|
||||
"access.form.acmehttpreq_username.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.acmehttpreq_password.label": "HTTP 基本认证密码",
|
||||
"access.form.acmehttpreq_password.placeholder": "请输入 HTTP 基本认证密码",
|
||||
"access.form.acmehttpreq_password.tooltip": "这是什么?请参阅 <a href=\"https://go-acme.github.io/lego/dns/httpreq/\" target=\"_blank\">https://go-acme.github.io/lego/dns/httpreq/</a>",
|
||||
"access.form.aliyun_access_key_id.label": "阿里云 Access Key ID",
|
||||
"access.form.aliyun_access_key_id.placeholder": "请输入阿里云 Access Key ID",
|
||||
"access.form.aliyun_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair\" target=\"_blank\">https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair</a>",
|
||||
"access.form.aliyun_access_key_secret.label": "阿里云 Access Key Secret",
|
||||
"access.form.aliyun_access_key_secret.placeholder": "请输入阿里云 Access Key Secret",
|
||||
"access.form.aliyun_access_key_secret.tooltip": "这是什么?请参阅 <a href=\"https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair\" target=\"_blank\">https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair</a>",
|
||||
"access.form.aws_access_key_id.label": "AWS Access Key ID",
|
||||
"access.form.aws_access_key_id.placeholder": "请输入 AWS Access Key ID",
|
||||
"access.form.aws_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html</a>",
|
||||
"access.form.aws_secret_access_key.label": "AWS Secret Access Key",
|
||||
"access.form.aws_secret_access_key.placeholder": "请输入 AWS Secret Access Key",
|
||||
"access.form.aws_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_access-keys.html</a>",
|
||||
"access.form.aws_region.label": "AWS 区域",
|
||||
"access.form.aws_region.placeholder": "请输入 AWS 区域(例如:us-east-1)",
|
||||
"access.form.aws_region.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/general/latest/gr/rande.html#regional-endpoints</a>",
|
||||
"access.form.aws_hosted_zone_id.label": "AWS 托管区域 ID",
|
||||
"access.form.aws_hosted_zone_id.placeholder": "请输入 AWS 托管区域 ID",
|
||||
"access.form.aws_hosted_zone_id.tooltip": "这是什么?请参阅 <a href=\"https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html\" target=\"_blank\">https://docs.aws.amazon.com/zh_cn/Route53/latest/DeveloperGuide/hosted-zones-working-with.html</a>",
|
||||
"access.form.baiducloud_access_key_id.label": "百度智能云 Access Key ID",
|
||||
"access.form.baiducloud_access_key_id.placeholder": "请输入百度智能云 Access Key ID",
|
||||
"access.form.baiducloud_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p\" target=\"_blank\">https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p</a>",
|
||||
"access.form.baiducloud_secret_access_key.label": "百度智能云 Secret Access Key",
|
||||
"access.form.baiducloud_secret_access_key.placeholder": "请输入百度智能云 Secret Access Key",
|
||||
"access.form.baiducloud_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p\" target=\"_blank\">https://cloud.baidu.com/doc/Reference/s/jjwvz2e3p</a>",
|
||||
"access.form.byteplus_access_key.label": "BytePlus Access Key",
|
||||
"access.form.byteplus_access_key.placeholder": "请输入 BytePlus Access Key",
|
||||
"access.form.byteplus_access_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys</a>",
|
||||
"access.form.byteplus_secret_key.label": "BytePlus Secret Key",
|
||||
"access.form.byteplus_secret_key.placeholder": "请输入 BytePlus Secret Key",
|
||||
"access.form.byteplus_secret_key.tooltip": "这是什么?请参阅 <a href=\"https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys\" target=\"_blank\">https://docs.byteplus.com/zh-CN/docs/byteplus-platform/docs-managing-keys</a>",
|
||||
"access.form.cloudflare_dns_api_token.label": "Cloudflare API Token",
|
||||
"access.form.cloudflare_dns_api_token.placeholder": "请输入 Cloudflare API Token",
|
||||
"access.form.cloudflare_dns_api_token.tooltip": "这是什么?请参阅 <a href=\"https://developers.cloudflare.com/fundamentals/api/get-started/create-token/\" target=\"_blank\">https://developers.cloudflare.com/fundamentals/api/get-started/create-token/</a>",
|
||||
"access.form.dogecloud_access_key.label": "多吉云 Access Key",
|
||||
"access.form.dogecloud_access_key.placeholder": "请输入多吉云 Access Key",
|
||||
"access.form.dogecloud_access_key.tooltip": "这是什么?请参阅 <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"access.form.dogecloud_secret_key.label": "多吉云 Secret Key",
|
||||
"access.form.dogecloud_secret_key.placeholder": "请输入多吉云 Secret Key",
|
||||
"access.form.dogecloud_secret_key.tooltip": "这是什么?请参阅 <a href=\"https://console.dogecloud.com/\" target=\"_blank\">https://console.dogecloud.com/</a>",
|
||||
"access.form.godaddy_api_key.label": "GoDaddy API Key",
|
||||
"access.form.godaddy_api_key.placeholder": "请输入 GoDaddy API Key",
|
||||
"access.form.godaddy_api_key.tooltip": "这是什么?请参阅 <a href=\"https://developer.godaddy.com/\" target=\"_blank\">https://developer.godaddy.com/</a>",
|
||||
"access.form.godaddy_api_secret.label": "GoDaddy API Secret",
|
||||
"access.form.godaddy_api_secret.placeholder": "请输入 GoDaddy API Secret",
|
||||
"access.form.godaddy_api_secret.tooltip": "这是什么?请参阅 <a href=\"https://developer.godaddy.com/\" target=\"_blank\">https://developer.godaddy.com/</a>",
|
||||
"access.form.huaweicloud_access_key_id.label": "华为云 Access Key ID",
|
||||
"access.form.huaweicloud_access_key_id.placeholder": "请输入华为云 Access Key ID",
|
||||
"access.form.huaweicloud_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html</a>",
|
||||
"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": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html\" target=\"_blank\">https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html</a>",
|
||||
"access.form.huaweicloud_region.label": "华为云 DNS 产品区域",
|
||||
"access.form.huaweicloud_region.placeholder": "请输入华为云区域(例如:cn-north-1)",
|
||||
"access.form.huaweicloud_region.tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/apiexplorer/#/endpoint\" target=\"_blank\">https://console.huaweicloud.com/apiexplorer/#/endpoint</a>",
|
||||
"access.form.k8s_kubeconfig.label": "KubeConfig",
|
||||
"access.form.k8s_kubeconfig.placeholder": "请选择 KubeConfig 文件",
|
||||
"access.form.k8s_kubeconfig.upload": "选择文件",
|
||||
"access.form.k8s_kubeconfig.tooltip": "这是什么?请参阅 <a href=\"https://kubernetes.io/zh-cn/docs/concepts/configuration/organize-cluster-access-kubeconfig/\" target=\"_blank\">https://kubernetes.io/zh-cn/docs/concepts/configuration/organize-cluster-access-kubeconfig/</a><br><br>为空时,将使用 Pod 的 ServiceAccount 作为凭证。",
|
||||
"access.form.namesilo_api_key.label": "NameSilo API Key",
|
||||
"access.form.namesilo_api_key.placeholder": "请输入 NameSilo API Key",
|
||||
"access.form.namesilo_api_key.tooltip": "这是什么?请参阅 <a href=\"https://www.namesilo.com/support/v2/articles/account-options/api-manager\" target=\"_blank\">https://www.namesilo.com/support/v2/articles/account-options/api-manager</a>",
|
||||
"access.form.powerdns_api_url.label": "PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.placeholder": "请输入 PowerDNS API URL",
|
||||
"access.form.powerdns_api_url.tooltip": "这是什么?请参阅 <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#endpoints-and-objects-in-the-api</a>",
|
||||
"access.form.powerdns_api_key.label": "PowerDNS API Key",
|
||||
"access.form.powerdns_api_key.placeholder": "请输入 PowerDNS API Key",
|
||||
"access.form.powerdns_api_key.tooltip": "这是什么?请参阅 <a href=\"https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api\" target=\"_blank\">https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api</a>",
|
||||
"access.form.qiniu_access_key.label": "七牛云 Access Key",
|
||||
"access.form.qiniu_access_key.placeholder": "请输入七牛云 Access Key",
|
||||
"access.form.qiniu_access_key.tooltip": "这是什么?请参阅 <a href=\"https://portal.qiniu.com/\" target=\"_blank\">https://portal.qiniu.com/</a>",
|
||||
"access.form.qiniu_secret_key.label": "七牛云 Secret Key",
|
||||
"access.form.qiniu_secret_key.placeholder": "请输入七牛云 Secret Key",
|
||||
"access.form.qiniu_secret_key.tooltip": "这是什么?请参阅 <a href=\"https://portal.qiniu.com/\" target=\"_blank\">https://portal.qiniu.com/</a>",
|
||||
"access.form.tencentcloud_secret_id.label": "腾讯云 SecretId",
|
||||
"access.form.tencentcloud_secret_id.placeholder": "请输入腾讯云 SecretId",
|
||||
"access.form.tencentcloud_secret_id.tooltip": "这是什么?请参阅 <a href=\"https://cloud.tencent.com/document/product/598/40488\" target=\"_blank\">https://cloud.tencent.com/document/product/598/40488</a>",
|
||||
"access.form.tencentcloud_secret_key.label": "腾讯云 SecretKey",
|
||||
"access.form.tencentcloud_secret_key.placeholder": "请输入腾讯云 SecretKey",
|
||||
"access.form.tencentcloud_secret_key.tooltip": "这是什么?请参阅 <a href=\"https://cloud.tencent.com/document/product/598/40488\" target=\"_blank\">https://cloud.tencent.com/document/product/598/40488</a>",
|
||||
"access.form.volcengine_access_key_id.label": "火山引擎 Access Key ID",
|
||||
"access.form.volcengine_access_key_id.placeholder": "请输入火山引擎 Access Key ID",
|
||||
"access.form.volcengine_access_key_id.tooltip": "这是什么?请参阅 <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
|
||||
"access.form.volcengine_secret_access_key.label": "火山引擎 Secret Access Key",
|
||||
"access.form.volcengine_secret_access_key.placeholder": "请输入火山引擎 Secret Access Key",
|
||||
"access.form.volcengine_secret_access_key.tooltip": "这是什么?请参阅 <a href=\"https://www.volcengine.com/docs/6291/216571\" target=\"_blank\">https://www.volcengine.com/docs/6291/216571</a>",
|
||||
"access.form.webhook_url.label": "Webhook URL",
|
||||
"access.form.webhook_url.placeholder": "请输入 Webhook URL",
|
||||
"access.form.ssh_host.label": "服务器地址",
|
||||
"access.form.ssh_host.placeholder": "请输入服务器地址",
|
||||
"access.form.ssh_port.label": "服务器端口",
|
||||
"access.form.ssh_port.placeholder": "请输入服务器端口",
|
||||
"access.form.ssh_username.label": "用户名",
|
||||
"access.form.ssh_username.placeholder": "请输入用户名",
|
||||
"access.form.ssh_password.label": "密码",
|
||||
"access.form.ssh_password.placeholder": "请输入密码",
|
||||
"access.form.ssh_password.tooltip": "使用密码连接到 SSH 时必填。",
|
||||
"access.form.ssh_key.label": "SSH 密钥",
|
||||
"access.form.ssh_key.placeholder": "请输入 SSH 密钥文件",
|
||||
"access.form.ssh_key.upload": "选择文件",
|
||||
"access.form.ssh_key.tooltip": "使用 SSH 密钥连接到 SSH 时必填。",
|
||||
"access.form.ssh_key_passphrase.label": "SSH 密钥口令",
|
||||
"access.form.ssh_key_passphrase.placeholder": "请输入 SSH 密钥口令",
|
||||
"access.form.ssh_key_passphrase.tooltip": "使用 SSH 密钥连接到 SSH 时选填。",
|
||||
"access.form.region.label": "Region",
|
||||
"access.form.region.placeholder": "请输入区域",
|
||||
"access.form.access_key_id.label": "AccessKeyId",
|
||||
@ -36,12 +152,6 @@
|
||||
"access.form.secret_access_key.placeholder": "请输入 SecretAccessKey",
|
||||
"access.form.cloud_dns_api_token.label": "CLOUD_DNS_API_TOKEN",
|
||||
"access.form.cloud_dns_api_token.placeholder": "请输入 CLOUD_DNS_API_TOKEN",
|
||||
"access.form.godaddy_api_key.label": "GO_DADDY_API_KEY",
|
||||
"access.form.godaddy_api_key.placeholder": "请输入 GO_DADDY_API_KEY",
|
||||
"access.form.godaddy_api_secret.label": "GO_DADDY_API_SECRET",
|
||||
"access.form.godaddy_api_secret.placeholder": "请输入 GO_DADDY_API_SECRET",
|
||||
"access.form.namesilo_api_key.label": "NAMESILO_API_KEY",
|
||||
"access.form.namesilo_api_key.placeholder": "请输入 NAMESILO_API_KEY",
|
||||
"access.form.pdns_api_url.label": "PDNS_API_URL",
|
||||
"access.form.pdns_api_url.placeholder": "请输入 PDNS_API_URL",
|
||||
"access.form.pdns_api_key.label": "PDNS_API_KEY",
|
||||
@ -53,25 +163,5 @@
|
||||
"access.form.username.label": "用户名",
|
||||
"access.form.username.placeholder": "请输入用户名",
|
||||
"access.form.password.label": "密码",
|
||||
"access.form.password.placeholder": "请输入密码",
|
||||
"access.form.access_group.placeholder": "请选择分组",
|
||||
"access.form.ssh_group.label": "授权配置组(用于将一个域名证书部署到多个 SSH 主机)",
|
||||
"access.form.ssh_host.label": "服务器 Host",
|
||||
"access.form.ssh_host.placeholder": "请输入 Host",
|
||||
"access.form.ssh_port.label": "SSH 端口",
|
||||
"access.form.ssh_port.placeholder": "请输入 Port",
|
||||
"access.form.ssh_username.label": "用户名",
|
||||
"access.form.ssh_username.placeholder": "请输入用户名",
|
||||
"access.form.ssh_password.label": "密码(使用密码登录)",
|
||||
"access.form.ssh_password.placeholder": "请输入密码",
|
||||
"access.form.ssh_key.label": "Key(使用私钥登录)",
|
||||
"access.form.ssh_key.placeholder": "请输入 Key",
|
||||
"access.form.ssh_key_file.placeholder": "请选择文件",
|
||||
"access.form.ssh_key_passphrase.label": "Key 口令(使用私钥登录)",
|
||||
"access.form.ssh_key_passphrase.placeholder": "请输入 Key 口令",
|
||||
"access.form.webhook_url.label": "Webhook URL",
|
||||
"access.form.webhook_url.placeholder": "请输入 Webhook URL",
|
||||
"access.form.k8s_kubeconfig.label": "KubeConfig(不选将使用Pod的ServiceAccount)",
|
||||
"access.form.k8s_kubeconfig.placeholder": "请输入 KubeConfig",
|
||||
"access.form.k8s_kubeconfig_file.placeholder": "请选择文件"
|
||||
"access.form.password.placeholder": "请输入密码"
|
||||
}
|
||||
|
@ -41,6 +41,7 @@
|
||||
"common.errmsg.email_duplicate": "邮箱已存在",
|
||||
"common.errmsg.domain_invalid": "请输入正确的域名",
|
||||
"common.errmsg.host_invalid": "请输入正确的域名或 IP 地址",
|
||||
"common.errmsg.port_invalid": "请输入正确的端口号",
|
||||
"common.errmsg.ip_invalid": "请输入正确的 IP 地址",
|
||||
"common.errmsg.url_invalid": "请输入正确的 URL",
|
||||
|
||||
@ -68,7 +69,7 @@
|
||||
"common.provider.dogecloud.cdn": "多吉云 - 内容分发网络 CDN",
|
||||
"common.provider.aws": "AWS",
|
||||
"common.provider.cloudflare": "Cloudflare",
|
||||
"common.provider.namesilo": "Namesilo",
|
||||
"common.provider.namesilo": "NameSilo",
|
||||
"common.provider.godaddy": "GoDaddy",
|
||||
"common.provider.powerdns": "PowerDNS",
|
||||
"common.provider.acmehttpreq": "Http Request (ACME Proxy)",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Navigate, Outlet } from "react-router-dom";
|
||||
|
||||
import Version from "@/components/certimate/Version";
|
||||
import Version from "@/components/Version";
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
const AuthLayout = () => {
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
Workflow as WorkflowIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
import Version from "@/components/certimate/Version";
|
||||
import Version from "@/components/Version";
|
||||
import { useTheme } from "@/hooks";
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
|
@ -6,7 +6,7 @@ import { Copy as CopyIcon, Pencil as PencilIcon, Plus as PlusIcon, Trash2 as Tra
|
||||
import dayjs from "dayjs";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
|
||||
import AccessEditDialog from "@/components/certimate/AccessEditDialog";
|
||||
import AccessEditModal from "@/components/access/AccessEditModal";
|
||||
import { accessProvidersMap, type AccessModel } from "@/domain/access";
|
||||
import { useAccessStore } from "@/stores/access";
|
||||
|
||||
@ -71,24 +71,24 @@ const AccessList = () => {
|
||||
render: (_, record) => (
|
||||
<>
|
||||
<Space size={0}>
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={record}
|
||||
mode="edit"
|
||||
trigger={
|
||||
<Tooltip title={t("access.action.edit")}>
|
||||
<Button type="link" icon={<PencilIcon size={16} />} />
|
||||
</Tooltip>
|
||||
}
|
||||
op="edit"
|
||||
data={record}
|
||||
/>
|
||||
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
data={{ ...record, id: undefined, name: `${record.name}-copy` }}
|
||||
mode="copy"
|
||||
trigger={
|
||||
<Tooltip title={t("access.action.copy")}>
|
||||
<Button type="link" icon={<CopyIcon size={16} />} />
|
||||
</Tooltip>
|
||||
}
|
||||
op="copy"
|
||||
data={record}
|
||||
/>
|
||||
|
||||
<Tooltip title={t("access.action.delete")}>
|
||||
@ -113,7 +113,14 @@ const AccessList = () => {
|
||||
const [pageSize, setPageSize] = useState<number>(10);
|
||||
|
||||
useEffect(() => {
|
||||
fetchAccesses();
|
||||
fetchAccesses().catch((err) => {
|
||||
if (err instanceof ClientResponseError && err.isAbort) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(err);
|
||||
notificationApi.error({ message: t("common.text.request_error"), description: <>{String(err)}</> });
|
||||
});
|
||||
}, []);
|
||||
|
||||
const fetchTableData = useCallback(async () => {
|
||||
@ -167,14 +174,14 @@ const AccessList = () => {
|
||||
<PageHeader
|
||||
title={t("access.page.title")}
|
||||
extra={[
|
||||
<AccessEditDialog
|
||||
<AccessEditModal
|
||||
key="create"
|
||||
mode="add"
|
||||
trigger={
|
||||
<Button key="create" type="primary" icon={<PlusIcon size={16} />}>
|
||||
<Button type="primary" icon={<PlusIcon size={16} />}>
|
||||
{t("access.action.add")}
|
||||
</Button>
|
||||
}
|
||||
op="add"
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
@ -190,6 +197,7 @@ const AccessList = () => {
|
||||
current: page,
|
||||
pageSize: pageSize,
|
||||
total: tableTotal,
|
||||
showSizeChanger: true,
|
||||
onChange: (page: number, pageSize: number) => {
|
||||
setPage(page);
|
||||
setPageSize(pageSize);
|
||||
|
@ -222,6 +222,7 @@ const CertificateList = () => {
|
||||
current: page,
|
||||
pageSize: pageSize,
|
||||
total: tableTotal,
|
||||
showSizeChanger: true,
|
||||
onChange: (page: number, pageSize: number) => {
|
||||
setPage(page);
|
||||
setPageSize(pageSize);
|
||||
|
@ -20,19 +20,18 @@ const Login = () => {
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const [form] = Form.useForm<z.infer<typeof formSchema>>();
|
||||
const [formPending, setFormPending] = useState(false);
|
||||
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
|
||||
const onSubmit = async (values: z.infer<typeof formSchema>) => {
|
||||
setIsPending(true);
|
||||
const handleFormFinish = async (fields: z.infer<typeof formSchema>) => {
|
||||
setFormPending(true);
|
||||
|
||||
try {
|
||||
await getPocketBase().admins.authWithPassword(values.username, values.password);
|
||||
await getPocketBase().admins.authWithPassword(fields.username, fields.password);
|
||||
navigage("/");
|
||||
} catch (err) {
|
||||
notificationApi.error({ message: t("common.text.request_error"), description: <>{String(err)}</> });
|
||||
} finally {
|
||||
setIsPending(false);
|
||||
setFormPending(false);
|
||||
}
|
||||
};
|
||||
|
||||
@ -45,7 +44,7 @@ const Login = () => {
|
||||
<img src="/logo.svg" className="w-16" />
|
||||
</div>
|
||||
|
||||
<Form form={form} disabled={isPending} layout="vertical" onFinish={onSubmit}>
|
||||
<Form form={form} disabled={formPending} layout="vertical" onFinish={handleFormFinish}>
|
||||
<Form.Item name="username" label={t("login.username.label")} rules={[formRule]}>
|
||||
<Input placeholder={t("login.username.placeholder")} />
|
||||
</Form.Item>
|
||||
@ -55,7 +54,7 @@ const Login = () => {
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit" block loading={isPending}>
|
||||
<Button type="primary" htmlType="submit" block loading={formPending}>
|
||||
{t("login.submit")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
|
@ -313,6 +313,7 @@ const WorkflowList = () => {
|
||||
current: page,
|
||||
pageSize: pageSize,
|
||||
total: tableTotal,
|
||||
showSizeChanger: true,
|
||||
onChange: (page: number, pageSize: number) => {
|
||||
setPage(page);
|
||||
setPageSize(pageSize);
|
||||
|
@ -12,7 +12,7 @@ export const list = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const save = async (record: AccessModel) => {
|
||||
export const save = async (record: Partial<AccessModel>) => {
|
||||
if (record.id) {
|
||||
return await getPocketBase().collection(COLLECTION_NAME).update<AccessModel>(record.id, record);
|
||||
}
|
||||
@ -20,7 +20,7 @@ export const save = async (record: AccessModel) => {
|
||||
return await getPocketBase().collection(COLLECTION_NAME).create<AccessModel>(record);
|
||||
};
|
||||
|
||||
export const remove = async (record: AccessModel) => {
|
||||
export const remove = async (record: Partial<AccessModel>) => {
|
||||
record = { ...record, deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") };
|
||||
await getPocketBase().collection(COLLECTION_NAME).update<AccessModel>(record.id, record);
|
||||
};
|
||||
|
@ -6,7 +6,7 @@ import { list as listAccess, save as saveAccess, remove as removeAccess } from "
|
||||
|
||||
export interface AccessState {
|
||||
accesses: AccessModel[];
|
||||
createAccess: (access: AccessModel) => void;
|
||||
createAccess: (access: Omit<AccessModel, "id" | "created" | "udpated" | "deleted">) => void;
|
||||
updateAccess: (access: AccessModel) => void;
|
||||
deleteAccess: (access: AccessModel) => void;
|
||||
fetchAccesses: () => Promise<void>;
|
||||
@ -17,22 +17,24 @@ export const useAccessStore = create<AccessState>((set) => {
|
||||
accesses: [],
|
||||
|
||||
createAccess: async (access) => {
|
||||
access = await saveAccess(access);
|
||||
const record = await saveAccess(access);
|
||||
|
||||
set(
|
||||
produce((state: AccessState) => {
|
||||
state.accesses.unshift(access);
|
||||
state.accesses.unshift(record);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
updateAccess: async (access) => {
|
||||
access = await saveAccess(access);
|
||||
const record = await saveAccess(access);
|
||||
|
||||
set(
|
||||
produce((state: AccessState) => {
|
||||
const index = state.accesses.findIndex((e) => e.id === access.id);
|
||||
state.accesses[index] = access;
|
||||
const index = state.accesses.findIndex((e) => e.id === record.id);
|
||||
if (index !== -1) {
|
||||
state.accesses[index] = record;
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
|
@ -14,7 +14,7 @@ export function readFileContent(file: File): Promise<string> {
|
||||
|
||||
reader.onerror = () => reject(reader.error);
|
||||
|
||||
reader.readAsText(file);
|
||||
reader.readAsText(file, "utf-8");
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user