fix(ui): duplicate form names

This commit is contained in:
Fu Diwei 2024-12-20 12:06:30 +08:00
parent d143df3f9f
commit cae33cfc4f
27 changed files with 116 additions and 98 deletions

View File

@ -1,32 +1,11 @@
import { forwardRef, useEffect, useImperativeHandle, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { useDeepCompareEffect } from "ahooks";
import { useCreation, useDeepCompareEffect } from "ahooks";
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 { ACCESS_PROVIDER_TYPES, type AccessModel } from "@/domain/access";
import AccessTypeSelect from "./AccessTypeSelect";
import AccessEditFormACMEHttpReqConfig from "./AccessEditFormACMEHttpReqConfig";
import AccessEditFormAliyunConfig from "./AccessEditFormAliyunConfig";
@ -48,13 +27,14 @@ import AccessEditFormVolcEngineConfig from "./AccessEditFormVolcEngineConfig";
import AccessEditFormWebhookConfig from "./AccessEditFormWebhookConfig";
type AccessEditFormModelType = Partial<MaybeModelRecord<AccessModel>>;
type AccessEditFormModes = "add" | "edit";
export type AccessEditFormProps = {
className?: string;
style?: React.CSSProperties;
disabled?: boolean;
loading?: boolean;
mode: "add" | "edit";
mode: AccessEditFormModes;
model?: AccessEditFormModelType;
onModelChange?: (model: AccessEditFormModelType) => void;
};
@ -91,53 +71,55 @@ const AccessEditForm = forwardRef<AccessEditFormInstance, AccessEditFormProps>((
}, [model?.configType]);
const [configFormInst] = Form.useForm();
const configFormName = useCreation(() => `accessEditForm_config${Math.random().toString(36).substring(2, 10)}${new Date().getTime()}`, []);
const configFormComponent = useMemo(() => {
/*
ASCII
NOTICE: If you add new child component, please keep ASCII order.
*/
const configFormProps = { form: configFormInst, formName: configFormName, disabled: disabled, loading: loading, model: model?.config };
switch (configType) {
case ACCESS_PROVIDER_TYPES.ACMEHTTPREQ:
return <AccessEditFormACMEHttpReqConfig form={configFormInst} model={model?.config as ACMEHttpReqAccessConfig} />;
return <AccessEditFormACMEHttpReqConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.ALIYUN:
return <AccessEditFormAliyunConfig form={configFormInst} model={model?.config as AliyunAccessConfig} />;
return <AccessEditFormAliyunConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.AWS:
return <AccessEditFormAWSConfig form={configFormInst} model={model?.config as AWSAccessConfig} />;
return <AccessEditFormAWSConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.BAIDUCLOUD:
return <AccessEditFormBaiduCloudConfig form={configFormInst} model={model?.config as BaiduCloudAccessConfig} />;
return <AccessEditFormBaiduCloudConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.BYTEPLUS:
return <AccessEditFormBytePlusConfig form={configFormInst} model={model?.config as BytePlusAccessConfig} />;
return <AccessEditFormBytePlusConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.CLOUDFLARE:
return <AccessEditFormCloudflareConfig form={configFormInst} model={model?.config as CloudflareAccessConfig} />;
return <AccessEditFormCloudflareConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.DOGECLOUD:
return <AccessEditFormDogeCloudConfig form={configFormInst} model={model?.config as DogeCloudAccessConfig} />;
return <AccessEditFormDogeCloudConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.GODADDY:
return <AccessEditFormGoDaddyConfig form={configFormInst} model={model?.config as GoDaddyAccessConfig} />;
return <AccessEditFormGoDaddyConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.HUAWEICLOUD:
return <AccessEditFormHuaweiCloudConfig form={configFormInst} model={model?.config as HuaweiCloudAccessConfig} />;
return <AccessEditFormHuaweiCloudConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.KUBERNETES:
return <AccessEditFormKubernetesConfig form={configFormInst} model={model?.config as KubernetesAccessConfig} />;
return <AccessEditFormKubernetesConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.LOCAL:
return <AccessEditFormLocalConfig form={configFormInst} model={model?.config as LocalAccessConfig} />;
return <AccessEditFormLocalConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.NAMESILO:
return <AccessEditFormNameSiloConfig form={configFormInst} model={model?.config as NameSiloAccessConfig} />;
return <AccessEditFormNameSiloConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.POWERDNS:
return <AccessEditFormPowerDNSConfig form={configFormInst} model={model?.config as PowerDNSAccessConfig} />;
return <AccessEditFormPowerDNSConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.QINIU:
return <AccessEditFormQiniuConfig form={configFormInst} model={model?.config as QiniuAccessConfig} />;
return <AccessEditFormQiniuConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.SSH:
return <AccessEditFormSSHConfig form={configFormInst} model={model?.config as SSHAccessConfig} />;
return <AccessEditFormSSHConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.TENCENTCLOUD:
return <AccessEditFormTencentCloudConfig form={configFormInst} model={model?.config as TencentCloudAccessConfig} />;
return <AccessEditFormTencentCloudConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.VOLCENGINE:
return <AccessEditFormVolcEngineConfig form={configFormInst} model={model?.config as VolcEngineAccessConfig} />;
return <AccessEditFormVolcEngineConfig {...configFormProps} />;
case ACCESS_PROVIDER_TYPES.WEBHOOK:
return <AccessEditFormWebhookConfig form={configFormInst} model={model?.config as WebhookAccessConfig} />;
return <AccessEditFormWebhookConfig {...configFormProps} />;
}
}, [model, configType, configFormInst]);
const handleFormProviderChange = (name: string) => {
if (name === "configForm") {
if (name === configFormName) {
form.setFieldValue("config", configFormInst.getFieldsValue());
onModelChange?.(form.getFieldsValue(true));
}

View File

@ -11,6 +11,7 @@ type AccessEditFormACMEHttpReqConfigModelType = Partial<ACMEHttpReqAccessConfig>
export type AccessEditFormACMEHttpReqConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormACMEHttpReqConfigModelType;
@ -24,7 +25,7 @@ const initModel = () => {
} as AccessEditFormACMEHttpReqConfigModelType;
};
const AccessEditFormACMEHttpReqConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormACMEHttpReqConfigProps) => {
const AccessEditFormACMEHttpReqConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormACMEHttpReqConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -55,7 +56,7 @@ const AccessEditFormACMEHttpReqConfig = ({ form, disabled, loading, model, onMod
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="endpoint"
label={t("access.form.acmehttpreq_endpoint.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormAWSConfigModelType = Partial<AWSAccessConfig>;
export type AccessEditFormAWSConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormAWSConfigModelType;
@ -23,7 +24,7 @@ const initModel = () => {
} as AccessEditFormAWSConfigModelType;
};
const AccessEditFormAWSConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormAWSConfigProps) => {
const AccessEditFormAWSConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormAWSConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -64,7 +65,7 @@ const AccessEditFormAWSConfig = ({ form, disabled, loading, model, onModelChange
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKeyId"
label={t("access.form.aws_access_key_id.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormAliyunConfigModelType = Partial<AliyunAccessConfig>;
export type AccessEditFormAliyunConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormAliyunConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormAliyunConfigModelType;
};
const AccessEditFormAliyunConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormAliyunConfigProps) => {
const AccessEditFormAliyunConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormAliyunConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormAliyunConfig = ({ form, disabled, loading, model, onModelCha
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKeyId"
label={t("access.form.aliyun_access_key_id.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormBaiduCloudConfigModelType = Partial<BaiduCloudAccessConfig>;
export type AccessEditFormBaiduCloudConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormBaiduCloudConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormBaiduCloudConfigModelType;
};
const AccessEditFormBaiduCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormBaiduCloudConfigProps) => {
const AccessEditFormBaiduCloudConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormBaiduCloudConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormBaiduCloudConfig = ({ form, disabled, loading, model, onMode
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKeyId"
label={t("access.form.baiducloud_access_key_id.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormBytePlusConfigModelType = Partial<BytePlusAccessConfig>;
export type AccessEditFormBytePlusConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormBytePlusConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormBytePlusConfigModelType;
};
const AccessEditFormBytePlusConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormBytePlusConfigProps) => {
const AccessEditFormBytePlusConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormBytePlusConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormBytePlusConfig = ({ form, disabled, loading, model, onModelC
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKey"
label={t("access.form.byteplus_access_key.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormCloudflareConfigModelType = Partial<CloudflareAccessConfig>;
export type AccessEditFormCloudflareConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormCloudflareConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormCloudflareConfigModelType;
};
const AccessEditFormCloudflareConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormCloudflareConfigProps) => {
const AccessEditFormCloudflareConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormCloudflareConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -43,7 +44,7 @@ const AccessEditFormCloudflareConfig = ({ form, disabled, loading, model, onMode
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="dnsApiToken"
label={t("access.form.cloudflare_dns_api_token.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormDogeCloudConfigModelType = Partial<DogeCloudAccessConfig>;
export type AccessEditFormDogeCloudConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormDogeCloudConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormDogeCloudConfigModelType;
};
const AccessEditFormDogeCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormDogeCloudConfigProps) => {
const AccessEditFormDogeCloudConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormDogeCloudConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormDogeCloudConfig = ({ form, disabled, loading, model, onModel
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKey"
label={t("access.form.dogecloud_access_key.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormGoDaddyConfigModelType = Partial<GoDaddyAccessConfig>;
export type AccessEditFormGoDaddyConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormGoDaddyConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormGoDaddyConfigModelType;
};
const AccessEditFormGoDaddyConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormGoDaddyConfigProps) => {
const AccessEditFormGoDaddyConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormGoDaddyConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormGoDaddyConfig = ({ form, disabled, loading, model, onModelCh
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="apiKey"
label={t("access.form.godaddy_api_key.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormHuaweiCloudConfigModelType = Partial<HuaweiCloudAccessConfig>
export type AccessEditFormHuaweiCloudConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormHuaweiCloudConfigModelType;
@ -23,7 +24,7 @@ const initModel = () => {
} as AccessEditFormHuaweiCloudConfigModelType;
};
const AccessEditFormHuaweiCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormHuaweiCloudConfigProps) => {
const AccessEditFormHuaweiCloudConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormHuaweiCloudConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -57,7 +58,7 @@ const AccessEditFormHuaweiCloudConfig = ({ form, disabled, loading, model, onMod
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKeyId"
label={t("access.form.huaweicloud_access_key_id.label")}

View File

@ -14,6 +14,7 @@ type AccessEditFormKubernetesConfigModelType = Partial<KubernetesAccessConfig>;
export type AccessEditFormKubernetesConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormKubernetesConfigModelType;
@ -24,7 +25,7 @@ const initModel = () => {
return {} as AccessEditFormKubernetesConfigModelType;
};
const AccessEditFormKubernetesConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormKubernetesConfigProps) => {
const AccessEditFormKubernetesConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormKubernetesConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -32,7 +33,8 @@ const AccessEditFormKubernetesConfig = ({ form, disabled, loading, model, onMode
.string()
.trim()
.min(0, t("access.form.k8s_kubeconfig.placeholder"))
.max(20480, t("common.errmsg.string_max", { max: 20480 })),
.max(20480, t("common.errmsg.string_max", { max: 20480 }))
.nullish(),
});
const formRule = createSchemaFieldRule(formSchema);
@ -61,7 +63,7 @@ const AccessEditFormKubernetesConfig = ({ form, disabled, loading, model, onMode
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="kubeConfig"
label={t("access.form.k8s_kubeconfig.label")}

View File

@ -8,6 +8,7 @@ type AccessEditFormLocalConfigModelType = Partial<LocalAccessConfig>;
export type AccessEditFormLocalConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormLocalConfigModelType;
@ -18,13 +19,13 @@ const initModel = () => {
return {} as AccessEditFormLocalConfigModelType;
};
const AccessEditFormLocalConfig = ({ form, disabled, loading, model }: AccessEditFormLocalConfigProps) => {
const AccessEditFormLocalConfig = ({ form, formName, disabled, loading, model }: AccessEditFormLocalConfigProps) => {
const [initialValues, setInitialValues] = useState(model ?? initModel());
useDeepCompareEffect(() => {
setInitialValues(model ?? initModel());
}, [model]);
return <Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm"></Form>;
return <Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName}></Form>;
};
export default AccessEditFormLocalConfig;

View File

@ -11,6 +11,7 @@ type AccessEditFormNameSiloConfigModelType = Partial<NameSiloAccessConfig>;
export type AccessEditFormNameSiloConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormNameSiloConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormNameSiloConfigModelType;
};
const AccessEditFormNameSiloConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormNameSiloConfigProps) => {
const AccessEditFormNameSiloConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormNameSiloConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -43,7 +44,7 @@ const AccessEditFormNameSiloConfig = ({ form, disabled, loading, model, onModelC
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="apiKey"
label={t("access.form.namesilo_api_key.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormPowerDNSConfigModelType = Partial<PowerDNSAccessConfig>;
export type AccessEditFormPowerDNSConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormPowerDNSConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormPowerDNSConfigModelType;
};
const AccessEditFormPowerDNSConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormPowerDNSConfigProps) => {
const AccessEditFormPowerDNSConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormPowerDNSConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -44,7 +45,7 @@ const AccessEditFormPowerDNSConfig = ({ form, disabled, loading, model, onModelC
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="apiUrl"
label={t("access.form.powerdns_api_url.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormQiniuConfigModelType = Partial<QiniuAccessConfig>;
export type AccessEditFormQiniuConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormQiniuConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormQiniuConfigModelType;
};
const AccessEditFormQiniuConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormQiniuConfigProps) => {
const AccessEditFormQiniuConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormQiniuConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormQiniuConfig = ({ form, disabled, loading, model, onModelChan
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKey"
label={t("access.form.qiniu_access_key.label")}

View File

@ -14,6 +14,7 @@ type AccessEditFormSSHConfigModelType = Partial<SSHAccessConfig>;
export type AccessEditFormSSHConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormSSHConfigModelType;
@ -28,7 +29,7 @@ const initModel = () => {
} as AccessEditFormSSHConfigModelType;
};
const AccessEditFormSSHConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormSSHConfigProps) => {
const AccessEditFormSSHConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormSSHConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -97,7 +98,7 @@ const AccessEditFormSSHConfig = ({ form, disabled, loading, model, onModelChange
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} 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]}>

View File

@ -11,6 +11,7 @@ type AccessEditFormTencentCloudConfigModelType = Partial<TencentCloudAccessConfi
export type AccessEditFormTencentCloudConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormTencentCloudConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormTencentCloudConfigModelType;
};
const AccessEditFormTencentCloudConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormTencentCloudConfigProps) => {
const AccessEditFormTencentCloudConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormTencentCloudConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormTencentCloudConfig = ({ form, disabled, loading, model, onMo
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="secretId"
label={t("access.form.tencentcloud_secret_id.label")}

View File

@ -11,6 +11,7 @@ type AccessEditFormVolcEngineConfigModelType = Partial<VolcEngineAccessConfig>;
export type AccessEditFormVolcEngineConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormVolcEngineConfigModelType;
@ -21,7 +22,7 @@ const initModel = () => {
return {} as AccessEditFormVolcEngineConfigModelType;
};
const AccessEditFormVolcEngineConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormVolcEngineConfigProps) => {
const AccessEditFormVolcEngineConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormVolcEngineConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -48,7 +49,7 @@ const AccessEditFormVolcEngineConfig = ({ form, disabled, loading, model, onMode
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} onValuesChange={handleFormChange}>
<Form.Item
name="accessKeyId"
label={t("access.form.volcengine_access_key_id.label")}

View File

@ -10,6 +10,7 @@ type AccessEditFormWebhookConfigModelType = Partial<WebhookAccessConfig>;
export type AccessEditFormWebhookConfigProps = {
form: FormInstance;
formName: string;
disabled?: boolean;
loading?: boolean;
model?: AccessEditFormWebhookConfigModelType;
@ -20,7 +21,7 @@ const initModel = () => {
return {} as AccessEditFormWebhookConfigModelType;
};
const AccessEditFormWebhookConfig = ({ form, disabled, loading, model, onModelChange }: AccessEditFormWebhookConfigProps) => {
const AccessEditFormWebhookConfig = ({ form, formName, disabled, loading, model, onModelChange }: AccessEditFormWebhookConfigProps) => {
const { t } = useTranslation();
const formSchema = z.object({
@ -41,7 +42,7 @@ const AccessEditFormWebhookConfig = ({ form, disabled, loading, model, onModelCh
};
return (
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name="configForm" onValuesChange={handleFormChange}>
<Form form={form} disabled={loading || disabled} initialValues={initialValues} layout="vertical" name={formName} 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>

View File

@ -6,13 +6,13 @@ import { useAccessStore } from "@/stores/access";
export type AccessTypeSelectProps = Omit<
SelectProps,
"filterOption" | "filterSort" | "labelRender" | "options" | "optionFilterProp" | "optionLabelProp" | "optionRender"
"filterOption" | "filterSort" | "labelRender" | "loading" | "options" | "optionFilterProp" | "optionLabelProp" | "optionRender"
> & {
filter?: (record: AccessModel) => boolean;
};
const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
const { accesses, fetchAccesses } = useAccessStore();
const { initialized, accesses, fetchAccesses } = useAccessStore();
useEffect(() => {
fetchAccesses();
}, [fetchAccesses]);
@ -64,6 +64,7 @@ const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
return <Typography.Text type="secondary">{props.placeholder}</Typography.Text>;
}}
loading={!initialized}
options={options}
optionFilterProp="label"
optionLabelProp={undefined}

View File

@ -90,7 +90,7 @@
"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.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>Leave blank to use the Pod's ServiceAccount.",
"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>",

View File

@ -20,7 +20,7 @@
"access.form.name.placeholder": "请输入授权名称",
"access.form.type.label": "提供商",
"access.form.type.placeholder": "请选择提供商",
"access.form.type.tooltip": "提供商分为两种类型:<br>【DNS 提供商】您的域名 DNS 托管方,用于在申请证书时管理您的域名解析记录。<br>【主机提供商】您的服务器或云服务的托管方,用于部署签发的证书。<br><br>该字段保存后不可修改。",
"access.form.type.tooltip": "提供商分为两种类型:<br>【DNS 提供商】您的 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>",

View File

@ -43,7 +43,7 @@
"common.errmsg.host_invalid": "请输入正确的域名或 IP 地址",
"common.errmsg.port_invalid": "请输入正确的端口号",
"common.errmsg.ip_invalid": "请输入正确的 IP 地址",
"common.errmsg.url_invalid": "请输入正确的 URL",
"common.errmsg.url_invalid": "请输入正确的 URL 地址",
"common.provider.acmehttpreq": "Http Request (ACME Proxy)",
"common.provider.aliyun": "阿里云",

View File

@ -7,8 +7,9 @@ const COLLECTION_NAME = "access";
export const list = async () => {
return await getPocketBase().collection(COLLECTION_NAME).getFullList<AccessModel>({
sort: "-created",
filter: "deleted=null",
sort: "-created",
requestKey: null,
});
};

View File

@ -21,6 +21,7 @@ export const list = async (req: CertificateListReq) => {
const options: RecordListOptions = {
sort: "-created",
expand: "workflow",
requestKey: null,
};
if (req.state === "expireSoon") {

View File

@ -5,6 +5,7 @@ import { type AccessModel } from "@/domain/access";
import { list as listAccess, save as saveAccess, remove as removeAccess } from "@/repository/access";
export interface AccessState {
initialized: boolean;
accesses: AccessModel[];
createAccess: (access: MaybeModelRecord<AccessModel>) => void;
updateAccess: (access: MaybeModelRecordWithId<AccessModel>) => void;
@ -13,7 +14,10 @@ export interface AccessState {
}
export const useAccessStore = create<AccessState>((set) => {
let fetcher: Promise<AccessModel[]> | null = null; // 防止多次重复请求
return {
initialized: false,
accesses: [],
createAccess: async (access) => {
@ -50,11 +54,14 @@ export const useAccessStore = create<AccessState>((set) => {
},
fetchAccesses: async () => {
const accesses = await listAccess();
fetcher ??= listAccess();
set({
accesses: accesses ?? [],
});
try {
const accesses = await fetcher;
set({ accesses: accesses ?? [], initialized: true });
} finally {
fetcher = null;
}
},
};
});

View File

@ -1,23 +1,26 @@
import { create } from "zustand";
import { produce } from "immer";
import { type EmailsSettingsContent, type SettingsModel } from "@/domain/settings";
import { SETTINGS_NAMES, type EmailsSettingsContent, type SettingsModel } from "@/domain/settings";
import { get as getSettings, save as saveSettings } from "@/repository/settings";
export interface ContactState {
initialized: boolean;
emails: string[];
setEmails: (emails: string[]) => void;
fetchEmails: () => Promise<void>;
}
export const useContactStore = create<ContactState>((set) => {
let settings: SettingsModel<EmailsSettingsContent>;
let fetcher: Promise<SettingsModel<EmailsSettingsContent>> | null = null; // 防止多次重复请求
let settings: SettingsModel<EmailsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
return {
initialized: false,
emails: [],
setEmails: async (emails: string[]) => {
settings ??= await getSettings<EmailsSettingsContent>("emails");
setEmails: async (emails) => {
settings ??= await getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS);
settings = await saveSettings<EmailsSettingsContent>({
...settings,
content: {
@ -29,16 +32,20 @@ export const useContactStore = create<ContactState>((set) => {
set(
produce((state: ContactState) => {
state.emails = settings.content.emails;
state.initialized = true;
})
);
},
fetchEmails: async () => {
settings = await getSettings<EmailsSettingsContent>("emails");
fetcher ??= getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS);
set({
emails: settings.content.emails?.sort() ?? [],
});
try {
settings = await fetcher;
set({ emails: settings.content.emails?.sort() ?? [], initialized: true });
} finally {
fetcher = null;
}
},
};
});