diff --git a/ui/src/components/access/AccessEditForm.tsx b/ui/src/components/access/AccessEditForm.tsx index b5d992bf..b7dbdb8c 100644 --- a/ui/src/components/access/AccessEditForm.tsx +++ b/ui/src/components/access/AccessEditForm.tsx @@ -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>; +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(( }, [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 ; + return ; case ACCESS_PROVIDER_TYPES.ALIYUN: - return ; + return ; case ACCESS_PROVIDER_TYPES.AWS: - return ; + return ; case ACCESS_PROVIDER_TYPES.BAIDUCLOUD: - return ; + return ; case ACCESS_PROVIDER_TYPES.BYTEPLUS: - return ; + return ; case ACCESS_PROVIDER_TYPES.CLOUDFLARE: - return ; + return ; case ACCESS_PROVIDER_TYPES.DOGECLOUD: - return ; + return ; case ACCESS_PROVIDER_TYPES.GODADDY: - return ; + return ; case ACCESS_PROVIDER_TYPES.HUAWEICLOUD: - return ; + return ; case ACCESS_PROVIDER_TYPES.KUBERNETES: - return ; + return ; case ACCESS_PROVIDER_TYPES.LOCAL: - return ; + return ; case ACCESS_PROVIDER_TYPES.NAMESILO: - return ; + return ; case ACCESS_PROVIDER_TYPES.POWERDNS: - return ; + return ; case ACCESS_PROVIDER_TYPES.QINIU: - return ; + return ; case ACCESS_PROVIDER_TYPES.SSH: - return ; + return ; case ACCESS_PROVIDER_TYPES.TENCENTCLOUD: - return ; + return ; case ACCESS_PROVIDER_TYPES.VOLCENGINE: - return ; + return ; case ACCESS_PROVIDER_TYPES.WEBHOOK: - return ; + return ; } }, [model, configType, configFormInst]); const handleFormProviderChange = (name: string) => { - if (name === "configForm") { + if (name === configFormName) { form.setFieldValue("config", configFormInst.getFieldsValue()); onModelChange?.(form.getFieldsValue(true)); } diff --git a/ui/src/components/access/AccessEditFormACMEHttpReqConfig.tsx b/ui/src/components/access/AccessEditFormACMEHttpReqConfig.tsx index 53638be6..a3d10c1c 100644 --- a/ui/src/components/access/AccessEditFormACMEHttpReqConfig.tsx +++ b/ui/src/components/access/AccessEditFormACMEHttpReqConfig.tsx @@ -11,6 +11,7 @@ type AccessEditFormACMEHttpReqConfigModelType = Partial 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 ( -
+ ; 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 ( - + ; 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 ( - + ; 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 ( - + ; 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 ( - + ; 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 ( - + ; 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 ( - + ; 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 ( - + 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 ( - + ; 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 ( - + ; 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 ; + return
; }; export default AccessEditFormLocalConfig; diff --git a/ui/src/components/access/AccessEditFormNameSiloConfig.tsx b/ui/src/components/access/AccessEditFormNameSiloConfig.tsx index fbe90c6c..822bf477 100644 --- a/ui/src/components/access/AccessEditFormNameSiloConfig.tsx +++ b/ui/src/components/access/AccessEditFormNameSiloConfig.tsx @@ -11,6 +11,7 @@ type AccessEditFormNameSiloConfigModelType = Partial; 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 ( -
+ ; 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 ( - + ; 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 ( - + ; 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 ( - +
diff --git a/ui/src/components/access/AccessEditFormTencentCloudConfig.tsx b/ui/src/components/access/AccessEditFormTencentCloudConfig.tsx index 7175e964..90d46844 100644 --- a/ui/src/components/access/AccessEditFormTencentCloudConfig.tsx +++ b/ui/src/components/access/AccessEditFormTencentCloudConfig.tsx @@ -11,6 +11,7 @@ type AccessEditFormTencentCloudConfigModelType = Partial { 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 ( - + ; 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 ( - + ; 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 ( - + diff --git a/ui/src/components/access/AccessSelect.tsx b/ui/src/components/access/AccessSelect.tsx index 3b0272cf..3cbca057 100644 --- a/ui/src/components/access/AccessSelect.tsx +++ b/ui/src/components/access/AccessSelect.tsx @@ -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 {props.placeholder}; }} + loading={!initialized} options={options} optionFilterProp="label" optionLabelProp={undefined} diff --git a/ui/src/i18n/locales/en/nls.access.json b/ui/src/i18n/locales/en/nls.access.json index 573e98c2..e24657d1 100644 --- a/ui/src/i18n/locales/en/nls.access.json +++ b/ui/src/i18n/locales/en/nls.access.json @@ -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 https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/

If empty, the Pod's ServiceAccount will be used.", + "access.form.k8s_kubeconfig.tooltip": "For more information, see https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/

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 https://www.namesilo.com/support/v2/articles/account-options/api-manager", diff --git a/ui/src/i18n/locales/zh/nls.access.json b/ui/src/i18n/locales/zh/nls.access.json index cc23b779..3a2a554f 100644 --- a/ui/src/i18n/locales/zh/nls.access.json +++ b/ui/src/i18n/locales/zh/nls.access.json @@ -20,7 +20,7 @@ "access.form.name.placeholder": "请输入授权名称", "access.form.type.label": "提供商", "access.form.type.placeholder": "请选择提供商", - "access.form.type.tooltip": "提供商分为两种类型:
【DNS 提供商】您的域名 DNS 托管方,用于在申请证书时管理您的域名解析记录。
【主机提供商】您的服务器或云服务的托管方,用于部署签发的证书。

该字段保存后不可修改。", + "access.form.type.tooltip": "提供商分为两种类型:
【DNS 提供商】您的 DNS 托管方,通常等同于域名注册商,用于在申请证书时管理您的域名解析记录。
【主机提供商】您的服务器或云服务的托管方,用于部署签发的证书。

该字段保存后不可修改。", "access.form.acmehttpreq_endpoint.label": "服务端点", "access.form.acmehttpreq_endpoint.placeholder": "请输入服务端点", "access.form.acmehttpreq_endpoint.tooltip": "这是什么?请参阅 https://go-acme.github.io/lego/dns/httpreq/", diff --git a/ui/src/i18n/locales/zh/nls.common.json b/ui/src/i18n/locales/zh/nls.common.json index 98a43c63..edee22d5 100644 --- a/ui/src/i18n/locales/zh/nls.common.json +++ b/ui/src/i18n/locales/zh/nls.common.json @@ -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": "阿里云", diff --git a/ui/src/repository/access.ts b/ui/src/repository/access.ts index f9912b64..085c1675 100644 --- a/ui/src/repository/access.ts +++ b/ui/src/repository/access.ts @@ -7,8 +7,9 @@ const COLLECTION_NAME = "access"; export const list = async () => { return await getPocketBase().collection(COLLECTION_NAME).getFullList({ - sort: "-created", filter: "deleted=null", + sort: "-created", + requestKey: null, }); }; diff --git a/ui/src/repository/certificate.ts b/ui/src/repository/certificate.ts index ca08151b..d37e10ca 100644 --- a/ui/src/repository/certificate.ts +++ b/ui/src/repository/certificate.ts @@ -21,6 +21,7 @@ export const list = async (req: CertificateListReq) => { const options: RecordListOptions = { sort: "-created", expand: "workflow", + requestKey: null, }; if (req.state === "expireSoon") { diff --git a/ui/src/stores/access/index.ts b/ui/src/stores/access/index.ts index 54262458..290ec27f 100644 --- a/ui/src/stores/access/index.ts +++ b/ui/src/stores/access/index.ts @@ -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) => void; updateAccess: (access: MaybeModelRecordWithId) => void; @@ -13,7 +14,10 @@ export interface AccessState { } export const useAccessStore = create((set) => { + let fetcher: Promise | null = null; // 防止多次重复请求 + return { + initialized: false, accesses: [], createAccess: async (access) => { @@ -50,11 +54,14 @@ export const useAccessStore = create((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; + } }, }; }); diff --git a/ui/src/stores/contact/index.ts b/ui/src/stores/contact/index.ts index 6d4dabfe..00889a65 100644 --- a/ui/src/stores/contact/index.ts +++ b/ui/src/stores/contact/index.ts @@ -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; } export const useContactStore = create((set) => { - let settings: SettingsModel; + let fetcher: Promise> | null = null; // 防止多次重复请求 + let settings: SettingsModel; // 记录当前设置的其他字段,保存回数据库时用 return { + initialized: false, emails: [], - setEmails: async (emails: string[]) => { - settings ??= await getSettings("emails"); + setEmails: async (emails) => { + settings ??= await getSettings(SETTINGS_NAMES.EMAILS); settings = await saveSettings({ ...settings, content: { @@ -29,16 +32,20 @@ export const useContactStore = create((set) => { set( produce((state: ContactState) => { state.emails = settings.content.emails; + state.initialized = true; }) ); }, fetchEmails: async () => { - settings = await getSettings("emails"); + fetcher ??= getSettings(SETTINGS_NAMES.EMAILS); - set({ - emails: settings.content.emails?.sort() ?? [], - }); + try { + settings = await fetcher; + set({ emails: settings.content.emails?.sort() ?? [], initialized: true }); + } finally { + fetcher = null; + } }, }; });