From bb3009a124a1ae7cc41f59d7db086ef3bc6f805a Mon Sep 17 00:00:00 2001 From: Fu Diwei Date: Wed, 11 Dec 2024 19:55:50 +0800 Subject: [PATCH] refactor(ui): refactor accesses state using zustand store --- ui/src/api/statistics.ts | 5 +- .../certificate/CertificateDetail.tsx | 4 +- .../certificate/CertificateDetailDrawer.tsx | 4 +- .../components/certimate/AccessAliyunForm.tsx | 14 ++- ui/src/components/certimate/AccessAwsForm.tsx | 15 ++- .../certimate/AccessBaiduCloudForm.tsx | 15 ++- .../certimate/AccessByteplusForm.tsx | 12 +- .../certimate/AccessCloudflareForm.tsx | 12 +- .../certimate/AccessDogeCloudForm.tsx | 12 +- .../components/certimate/AccessEditDialog.tsx | 4 +- .../certimate/AccessGodaddyForm.tsx | 12 +- .../certimate/AccessHttpreqForm.tsx | 12 +- .../certimate/AccessHuaweicloudForm.tsx | 12 +- .../certimate/AccessKubernetesForm.tsx | 12 +- .../components/certimate/AccessLocalForm.tsx | 12 +- .../certimate/AccessNamesiloForm.tsx | 12 +- .../components/certimate/AccessPdnsForm.tsx | 12 +- .../components/certimate/AccessQiniuForm.tsx | 12 +- ui/src/components/certimate/AccessSSHForm.tsx | 12 +- .../certimate/AccessTencentForm.tsx | 12 +- .../certimate/AccessVolcengineForm.tsx | 12 +- .../certimate/AccessWebhookForm.tsx | 12 +- ui/src/components/workflow/AccessSelect.tsx | 6 +- ui/src/components/workflow/ApplyForm.tsx | 6 +- .../components/workflow/WorkflowProvider.tsx | 12 +- ui/src/domain/access.ts | 9 +- ui/src/domain/certificate.ts | 14 +-- ui/src/domain/domain.ts | 10 -- ui/src/domain/settings.ts | 2 +- ui/src/domain/statistics.ts | 8 ++ ui/src/domain/workflow.ts | 10 +- ui/src/pages/ConsoleLayout.tsx | 111 +++++++++--------- ui/src/pages/accesses/AccessList.tsx | 28 +++-- ui/src/pages/certificates/CertificateList.tsx | 12 +- ui/src/pages/dashboard/Dashboard.tsx | 32 ++--- ui/src/pages/settings/SSLProvider.tsx | 14 +-- ui/src/pages/workflows/WorkflowList.tsx | 12 +- ui/src/providers/config/index.tsx | 61 ---------- ui/src/providers/config/reducer.ts | 39 ------ ui/src/providers/notify/index.tsx | 8 +- ui/src/providers/notify/reducer.tsx | 6 +- ui/src/repository/access.ts | 20 ++-- ui/src/repository/certificate.ts | 6 +- ui/src/repository/settings.ts | 12 +- ui/src/repository/workflow.ts | 18 +-- ui/src/stores/access/index.ts | 58 +++++++++ ui/src/stores/contact/index.ts | 4 +- ui/src/stores/workflow/index.ts | 4 +- 48 files changed, 359 insertions(+), 404 deletions(-) create mode 100644 ui/src/domain/statistics.ts delete mode 100644 ui/src/providers/config/index.tsx delete mode 100644 ui/src/providers/config/reducer.ts create mode 100644 ui/src/stores/access/index.ts diff --git a/ui/src/api/statistics.ts b/ui/src/api/statistics.ts index 56a0471f..fb5e8b94 100644 --- a/ui/src/api/statistics.ts +++ b/ui/src/api/statistics.ts @@ -1,3 +1,4 @@ +import { Statistics } from "@/domain/statistics"; import { getPocketBase } from "@/repository/pocketbase"; export const get = async () => { @@ -7,9 +8,9 @@ export const get = async () => { method: "GET", }); - if (resp.code != 0) { + if (resp.code !== 0) { throw new Error(resp.msg); } - return resp.data; + return resp.data as Statistics; }; diff --git a/ui/src/components/certificate/CertificateDetail.tsx b/ui/src/components/certificate/CertificateDetail.tsx index 7ecaceb8..02b7a91e 100644 --- a/ui/src/components/certificate/CertificateDetail.tsx +++ b/ui/src/components/certificate/CertificateDetail.tsx @@ -3,11 +3,11 @@ import { Button, Dropdown, Form, Input, message, Space, Tooltip } from "antd"; import { CopyToClipboard } from "react-copy-to-clipboard"; import { ChevronDown as ChevronDownIcon, Clipboard as ClipboardIcon, ThumbsUp as ThumbsUpIcon } from "lucide-react"; -import { type Certificate } from "@/domain/certificate"; +import { type CertificateModel } from "@/domain/certificate"; import { saveFiles2Zip } from "@/utils/file"; type CertificateDetailProps = { - data: Certificate; + data: CertificateModel; }; const CertificateDetail = ({ data }: CertificateDetailProps) => { diff --git a/ui/src/components/certificate/CertificateDetailDrawer.tsx b/ui/src/components/certificate/CertificateDetailDrawer.tsx index 40fd5982..6aefd7d6 100644 --- a/ui/src/components/certificate/CertificateDetailDrawer.tsx +++ b/ui/src/components/certificate/CertificateDetailDrawer.tsx @@ -1,11 +1,11 @@ import { useEffect, useState } from "react"; import { Drawer } from "antd"; -import { type Certificate } from "@/domain/certificate"; +import { type CertificateModel } from "@/domain/certificate"; import CertificateDetail from "./CertificateDetail"; type CertificateDetailDrawerProps = { - data?: Certificate; + data?: CertificateModel; open?: boolean; onClose?: () => void; }; diff --git a/ui/src/components/certimate/AccessAliyunForm.tsx b/ui/src/components/certimate/AccessAliyunForm.tsx index 54da504d..14352078 100644 --- a/ui/src/components/certimate/AccessAliyunForm.tsx +++ b/ui/src/components/certimate/AccessAliyunForm.tsx @@ -8,19 +8,21 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type AliyunConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type AliyunConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessAliyunFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessAliyunForm = ({ data, op, onAfterReq }: AccessAliyunFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); const { t } = useTranslation(); + + const { createAccess, updateAccess } = useAccessStore(); + const formSchema = z.object({ id: z.string().optional(), name: z @@ -56,7 +58,7 @@ const AccessAliyunForm = ({ data, op, onAfterReq }: AccessAliyunFormProps) => { }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -81,7 +83,7 @@ const AccessAliyunForm = ({ data, op, onAfterReq }: AccessAliyunFormProps) => { return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessAwsForm.tsx b/ui/src/components/certimate/AccessAwsForm.tsx index 2aa2fc12..28f3c69d 100644 --- a/ui/src/components/certimate/AccessAwsForm.tsx +++ b/ui/src/components/certimate/AccessAwsForm.tsx @@ -8,19 +8,21 @@ import { Input } from "@/components/ui/input"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Button } from "@/components/ui/button"; import { PbErrorData } from "@/domain/base"; -import { Access, accessProvidersMap, accessTypeFormSchema, type AwsConfig } from "@/domain/access"; +import { AccessModel, accessProvidersMap, accessTypeFormSchema, type AwsConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessAwsFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessAwsForm = ({ data, op, onAfterReq }: AccessAwsFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); const { t } = useTranslation(); + + const { createAccess, updateAccess } = useAccessStore(); + const formSchema = z.object({ id: z.string().optional(), name: z @@ -68,7 +70,7 @@ const AccessAwsForm = ({ data, op, onAfterReq }: AccessAwsFormProps) => { }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -94,7 +96,8 @@ const AccessAwsForm = ({ data, op, onAfterReq }: AccessAwsFormProps) => { updateAccess(req); return; } - addAccess(req); + + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessBaiduCloudForm.tsx b/ui/src/components/certimate/AccessBaiduCloudForm.tsx index a5dd56db..033d34e4 100644 --- a/ui/src/components/certimate/AccessBaiduCloudForm.tsx +++ b/ui/src/components/certimate/AccessBaiduCloudForm.tsx @@ -8,19 +8,21 @@ import { Input } from "@/components/ui/input"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Button } from "@/components/ui/button"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type BaiduCloudConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type BaiduCloudConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessBaiduCloudFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessBaiduCloudForm = ({ data, op, onAfterReq }: AccessBaiduCloudFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); const { t } = useTranslation(); + + const { createAccess, updateAccess } = useAccessStore(); + const formSchema = z.object({ id: z.string().optional(), name: z @@ -56,7 +58,7 @@ const AccessBaiduCloudForm = ({ data, op, onAfterReq }: AccessBaiduCloudFormProp }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -80,7 +82,8 @@ const AccessBaiduCloudForm = ({ data, op, onAfterReq }: AccessBaiduCloudFormProp updateAccess(req); return; } - addAccess(req); + + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessByteplusForm.tsx b/ui/src/components/certimate/AccessByteplusForm.tsx index 82ed53d1..f7fc213b 100644 --- a/ui/src/components/certimate/AccessByteplusForm.tsx +++ b/ui/src/components/certimate/AccessByteplusForm.tsx @@ -8,18 +8,18 @@ import { Input } from "@/components/ui/input"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Button } from "@/components/ui/button"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type ByteplusConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type ByteplusConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessByteplusFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessByteplusForm = ({ data, op, onAfterReq }: AccessByteplusFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -56,7 +56,7 @@ const AccessByteplusForm = ({ data, op, onAfterReq }: AccessByteplusFormProps) = }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -80,7 +80,7 @@ const AccessByteplusForm = ({ data, op, onAfterReq }: AccessByteplusFormProps) = updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessCloudflareForm.tsx b/ui/src/components/certimate/AccessCloudflareForm.tsx index 03b8a6c7..0a347223 100644 --- a/ui/src/components/certimate/AccessCloudflareForm.tsx +++ b/ui/src/components/certimate/AccessCloudflareForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type CloudflareConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type CloudflareConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessCloudflareFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessCloudflareForm = ({ data, op, onAfterReq }: AccessCloudflareFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -50,7 +50,7 @@ const AccessCloudflareForm = ({ data, op, onAfterReq }: AccessCloudflareFormProp }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -73,7 +73,7 @@ const AccessCloudflareForm = ({ data, op, onAfterReq }: AccessCloudflareFormProp updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessDogeCloudForm.tsx b/ui/src/components/certimate/AccessDogeCloudForm.tsx index bff658cb..13283ee1 100644 --- a/ui/src/components/certimate/AccessDogeCloudForm.tsx +++ b/ui/src/components/certimate/AccessDogeCloudForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type DogeCloudConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type DogeCloudConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessDogeCloudFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessDogeCloudForm = ({ data, op, onAfterReq }: AccessDogeCloudFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -50,7 +50,7 @@ const AccessDogeCloudForm = ({ data, op, onAfterReq }: AccessDogeCloudFormProps) }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -74,7 +74,7 @@ const AccessDogeCloudForm = ({ data, op, onAfterReq }: AccessDogeCloudFormProps) updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessEditDialog.tsx b/ui/src/components/certimate/AccessEditDialog.tsx index b2d89c12..a9e8986f 100644 --- a/ui/src/components/certimate/AccessEditDialog.tsx +++ b/ui/src/components/certimate/AccessEditDialog.tsx @@ -23,14 +23,14 @@ import AccessWebhookForm from "./AccessWebhookForm"; import AccessKubernetesForm from "./AccessKubernetesForm"; import AccessVolcengineForm from "./AccessVolcengineForm"; import AccessByteplusForm from "./AccessByteplusForm"; -import { Access } from "@/domain/access"; +import { AccessModel } from "@/domain/access"; import { AccessTypeSelect } from "./AccessTypeSelect"; type AccessEditProps = { op: "add" | "edit" | "copy"; className?: string; trigger: React.ReactNode; - data?: Access; + data?: AccessModel; outConfigType?: string; }; diff --git a/ui/src/components/certimate/AccessGodaddyForm.tsx b/ui/src/components/certimate/AccessGodaddyForm.tsx index 0a7a3f84..1c8f40a5 100644 --- a/ui/src/components/certimate/AccessGodaddyForm.tsx +++ b/ui/src/components/certimate/AccessGodaddyForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type GodaddyConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type GodaddyConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessGodaddyFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessGodaddyForm = ({ data, op, onAfterReq }: AccessGodaddyFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -56,7 +56,7 @@ const AccessGodaddyForm = ({ data, op, onAfterReq }: AccessGodaddyFormProps) => }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -80,7 +80,7 @@ const AccessGodaddyForm = ({ data, op, onAfterReq }: AccessGodaddyFormProps) => updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessHttpreqForm.tsx b/ui/src/components/certimate/AccessHttpreqForm.tsx index 865324ff..38abf92f 100644 --- a/ui/src/components/certimate/AccessHttpreqForm.tsx +++ b/ui/src/components/certimate/AccessHttpreqForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type HttpreqConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type HttpreqConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessHttpreqFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessHttpreqForm = ({ data, op, onAfterReq }: AccessHttpreqFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -62,7 +62,7 @@ const AccessHttpreqForm = ({ data, op, onAfterReq }: AccessHttpreqFormProps) => }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -89,7 +89,7 @@ const AccessHttpreqForm = ({ data, op, onAfterReq }: AccessHttpreqFormProps) => return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessHuaweicloudForm.tsx b/ui/src/components/certimate/AccessHuaweicloudForm.tsx index 17f32351..16c7c746 100644 --- a/ui/src/components/certimate/AccessHuaweicloudForm.tsx +++ b/ui/src/components/certimate/AccessHuaweicloudForm.tsx @@ -8,18 +8,18 @@ import { Input } from "@/components/ui/input"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Button } from "@/components/ui/button"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type HuaweiCloudConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type HuaweiCloudConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessHuaweiCloudFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessHuaweiCloudForm = ({ data, op, onAfterReq }: AccessHuaweiCloudFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -62,7 +62,7 @@ const AccessHuaweiCloudForm = ({ data, op, onAfterReq }: AccessHuaweiCloudFormPr }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -87,7 +87,7 @@ const AccessHuaweiCloudForm = ({ data, op, onAfterReq }: AccessHuaweiCloudFormPr updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessKubernetesForm.tsx b/ui/src/components/certimate/AccessKubernetesForm.tsx index 9780bd73..55ccc204 100644 --- a/ui/src/components/certimate/AccessKubernetesForm.tsx +++ b/ui/src/components/certimate/AccessKubernetesForm.tsx @@ -10,18 +10,18 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from " import { Input } from "@/components/ui/input"; import { readFileContent } from "@/utils/file"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type KubernetesConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type KubernetesConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessKubernetesFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessKubernetesForm = ({ data, op, onAfterReq }: AccessKubernetesFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const fileInputRef = useRef(null); const [fileName, setFileName] = useState(""); @@ -60,7 +60,7 @@ const AccessKubernetesForm = ({ data, op, onAfterReq }: AccessKubernetesFormProp }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -82,7 +82,7 @@ const AccessKubernetesForm = ({ data, op, onAfterReq }: AccessKubernetesFormProp if (data.id && op == "edit") { updateAccess(req); } else { - addAccess(req); + createAccess(req); } } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessLocalForm.tsx b/ui/src/components/certimate/AccessLocalForm.tsx index e13f9c0e..427fad63 100644 --- a/ui/src/components/certimate/AccessLocalForm.tsx +++ b/ui/src/components/certimate/AccessLocalForm.tsx @@ -8,18 +8,18 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from " import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessLocalFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessLocalForm = ({ data, op, onAfterReq }: AccessLocalFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ @@ -41,7 +41,7 @@ const AccessLocalForm = ({ data, op, onAfterReq }: AccessLocalFormProps) => { }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -62,7 +62,7 @@ const AccessLocalForm = ({ data, op, onAfterReq }: AccessLocalFormProps) => { if (data.id && op == "edit") { updateAccess(req); } else { - addAccess(req); + createAccess(req); } } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessNamesiloForm.tsx b/ui/src/components/certimate/AccessNamesiloForm.tsx index c846e855..31bce833 100644 --- a/ui/src/components/certimate/AccessNamesiloForm.tsx +++ b/ui/src/components/certimate/AccessNamesiloForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type NamesiloConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type NamesiloConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessNamesiloFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessNamesiloForm = ({ data, op, onAfterReq }: AccessNamesiloFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -50,7 +50,7 @@ const AccessNamesiloForm = ({ data, op, onAfterReq }: AccessNamesiloFormProps) = }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -73,7 +73,7 @@ const AccessNamesiloForm = ({ data, op, onAfterReq }: AccessNamesiloFormProps) = updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessPdnsForm.tsx b/ui/src/components/certimate/AccessPdnsForm.tsx index e2be6f47..e75df10a 100644 --- a/ui/src/components/certimate/AccessPdnsForm.tsx +++ b/ui/src/components/certimate/AccessPdnsForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type PdnsConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type PdnsConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessPdnsFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessPdnsForm = ({ data, op, onAfterReq }: AccessPdnsFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -53,7 +53,7 @@ const AccessPdnsForm = ({ data, op, onAfterReq }: AccessPdnsFormProps) => { }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -78,7 +78,7 @@ const AccessPdnsForm = ({ data, op, onAfterReq }: AccessPdnsFormProps) => { return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessQiniuForm.tsx b/ui/src/components/certimate/AccessQiniuForm.tsx index e26a109f..36b644cb 100644 --- a/ui/src/components/certimate/AccessQiniuForm.tsx +++ b/ui/src/components/certimate/AccessQiniuForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type QiniuConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type QiniuConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessQiniuFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessQiniuForm = ({ data, op, onAfterReq }: AccessQiniuFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -50,7 +50,7 @@ const AccessQiniuForm = ({ data, op, onAfterReq }: AccessQiniuFormProps) => { }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -74,7 +74,7 @@ const AccessQiniuForm = ({ data, op, onAfterReq }: AccessQiniuFormProps) => { updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessSSHForm.tsx b/ui/src/components/certimate/AccessSSHForm.tsx index 128b931d..d9b40774 100644 --- a/ui/src/components/certimate/AccessSSHForm.tsx +++ b/ui/src/components/certimate/AccessSSHForm.tsx @@ -10,18 +10,18 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from " import { Input } from "@/components/ui/input"; import { readFileContent } from "@/utils/file"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type SSHConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type SSHConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessSSHFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessSSHForm = ({ data, op, onAfterReq }: AccessSSHFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const fileInputRef = useRef(null); @@ -103,7 +103,7 @@ const AccessSSHForm = ({ data, op, onAfterReq }: AccessSSHFormProps) => { let group = data.group; if (group == "emptyId") group = ""; - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -131,7 +131,7 @@ const AccessSSHForm = ({ data, op, onAfterReq }: AccessSSHFormProps) => { if (data.id && op == "edit") { updateAccess(req); } else { - addAccess(req); + createAccess(req); } } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessTencentForm.tsx b/ui/src/components/certimate/AccessTencentForm.tsx index 4cd95de2..aa3246d5 100644 --- a/ui/src/components/certimate/AccessTencentForm.tsx +++ b/ui/src/components/certimate/AccessTencentForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type TencentConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type TencentConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessTencentFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessTencentForm = ({ data, op, onAfterReq }: AccessTencentFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -56,7 +56,7 @@ const AccessTencentForm = ({ data, op, onAfterReq }: AccessTencentFormProps) => }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -80,7 +80,7 @@ const AccessTencentForm = ({ data, op, onAfterReq }: AccessTencentFormProps) => updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessVolcengineForm.tsx b/ui/src/components/certimate/AccessVolcengineForm.tsx index 3e55ea7f..1a62ac1b 100644 --- a/ui/src/components/certimate/AccessVolcengineForm.tsx +++ b/ui/src/components/certimate/AccessVolcengineForm.tsx @@ -8,18 +8,18 @@ import { Input } from "@/components/ui/input"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Button } from "@/components/ui/button"; import { PbErrorData } from "@/domain/base"; -import { accessProvidersMap, accessTypeFormSchema, type Access, type VolcengineConfig } from "@/domain/access"; +import { accessProvidersMap, accessTypeFormSchema, type AccessModel, type VolcengineConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessVolcengineFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessVolcengineForm = ({ data, op, onAfterReq }: AccessVolcengineFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -56,7 +56,7 @@ const AccessVolcengineForm = ({ data, op, onAfterReq }: AccessVolcengineFormProp }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -80,7 +80,7 @@ const AccessVolcengineForm = ({ data, op, onAfterReq }: AccessVolcengineFormProp updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/certimate/AccessWebhookForm.tsx b/ui/src/components/certimate/AccessWebhookForm.tsx index 284506a7..6450d4d7 100644 --- a/ui/src/components/certimate/AccessWebhookForm.tsx +++ b/ui/src/components/certimate/AccessWebhookForm.tsx @@ -8,18 +8,18 @@ import { Button } from "@/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { PbErrorData } from "@/domain/base"; -import { Access, accessProvidersMap, accessTypeFormSchema, WebhookConfig } from "@/domain/access"; +import { AccessModel, accessProvidersMap, accessTypeFormSchema, WebhookConfig } from "@/domain/access"; import { save } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; type AccessWebhookFormProps = { op: "add" | "edit" | "copy"; - data?: Access; + data?: AccessModel; onAfterReq: () => void; }; const AccessWebhookForm = ({ data, op, onAfterReq }: AccessWebhookFormProps) => { - const { addAccess, updateAccess } = useConfigContext(); + const { createAccess, updateAccess } = useAccessStore(); const { t } = useTranslation(); const formSchema = z.object({ id: z.string().optional(), @@ -47,7 +47,7 @@ const AccessWebhookForm = ({ data, op, onAfterReq }: AccessWebhookFormProps) => }); const onSubmit = async (data: z.infer) => { - const req: Access = { + const req: AccessModel = { id: data.id as string, name: data.name, configType: data.configType, @@ -70,7 +70,7 @@ const AccessWebhookForm = ({ data, op, onAfterReq }: AccessWebhookFormProps) => updateAccess(req); return; } - addAccess(req); + createAccess(req); } catch (e) { const err = e as ClientResponseError; diff --git a/ui/src/components/workflow/AccessSelect.tsx b/ui/src/components/workflow/AccessSelect.tsx index 73834468..8ced0156 100644 --- a/ui/src/components/workflow/AccessSelect.tsx +++ b/ui/src/components/workflow/AccessSelect.tsx @@ -2,7 +2,7 @@ import React, { useEffect } from "react"; import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select"; import { accessProvidersMap } from "@/domain/access"; import { useTranslation } from "react-i18next"; -import { useConfigContext } from "@/providers/config"; +import { useAccessStore } from "@/stores/access"; import { deployTargetsMap } from "@/domain/domain"; type AccessSelectProps = { @@ -13,9 +13,7 @@ type AccessSelectProps = { const AccessSelect = ({ value, onValueChange, providerType }: AccessSelectProps) => { const [localValue, setLocalValue] = React.useState(""); const { t } = useTranslation(); - const { - config: { accesses }, - } = useConfigContext(); + const { accesses } = useAccessStore(); useEffect(() => { setLocalValue(value); diff --git a/ui/src/components/workflow/ApplyForm.tsx b/ui/src/components/workflow/ApplyForm.tsx index c4a6e306..fffcd163 100644 --- a/ui/src/components/workflow/ApplyForm.tsx +++ b/ui/src/components/workflow/ApplyForm.tsx @@ -15,8 +15,8 @@ import EmailsEdit from "@/components/certimate/EmailsEdit"; import StringList from "@/components/certimate/StringList"; import { accessProvidersMap } from "@/domain/access"; +import { useAccessStore } from "@/stores/access"; import { useContactStore } from "@/stores/contact"; -import { useConfigContext } from "@/providers/config"; import { Switch } from "@/components/ui/switch"; import { TooltipFast } from "@/components/ui/tooltip"; import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow"; @@ -33,9 +33,7 @@ const selectState = (state: WorkflowState) => ({ const ApplyForm = ({ data }: ApplyFormProps) => { const { updateNode } = useWorkflowStore(useShallow(selectState)); - const { - config: { accesses }, - } = useConfigContext(); + const { accesses } = useAccessStore(); const { emails, fetchEmails } = useContactStore(); useEffect(() => { diff --git a/ui/src/components/workflow/WorkflowProvider.tsx b/ui/src/components/workflow/WorkflowProvider.tsx index 8299a228..5e260348 100644 --- a/ui/src/components/workflow/WorkflowProvider.tsx +++ b/ui/src/components/workflow/WorkflowProvider.tsx @@ -1,15 +1,13 @@ -import { ConfigProvider } from "@/providers/config"; import React from "react"; -import { PanelProvider } from "./PanelProvider"; + import { NotifyProvider } from "@/providers/notify"; +import { PanelProvider } from "./PanelProvider"; const WorkflowProvider = ({ children }: { children: React.ReactNode }) => { return ( - - - {children} - - + + {children} + ); }; diff --git a/ui/src/domain/access.ts b/ui/src/domain/access.ts index 27090202..8da18ceb 100644 --- a/ui/src/domain/access.ts +++ b/ui/src/domain/access.ts @@ -1,4 +1,5 @@ import { z } from "zod"; +import { type BaseModel } from "pocketbase"; type AccessUsages = "apply" | "deploy" | "all"; @@ -59,8 +60,7 @@ export const accessTypeFormSchema = z.union( { message: "access.authorization.form.type.placeholder" } ); -export type Access = { - id: string; +export interface AccessModel extends BaseModel { name: string; configType: string; usage: AccessUsages; @@ -83,10 +83,7 @@ export type Access = { | KubernetesConfig | VolcengineConfig | ByteplusConfig; - deleted?: string; - created?: string; - updated?: string; -}; +} export type AliyunConfig = { accessKeyId: string; diff --git a/ui/src/domain/certificate.ts b/ui/src/domain/certificate.ts index 457efc7a..3f828f79 100644 --- a/ui/src/domain/certificate.ts +++ b/ui/src/domain/certificate.ts @@ -1,7 +1,8 @@ -import { Workflow } from "./workflow"; +import { type BaseModel } from "pocketbase"; -export type Certificate = { - id: string; +import { WorkflowModel } from "./workflow"; + +export interface CertificateModel extends BaseModel { san: string; certificate: string; privateKey: string; @@ -12,10 +13,7 @@ export type Certificate = { expireAt: string; workflow: string; nodeId: string; - created: string; - updated: string; - expand: { - workflow?: Workflow; + workflow?: WorkflowModel; }; -}; +} diff --git a/ui/src/domain/domain.ts b/ui/src/domain/domain.ts index 3d6129be..00ae9fbe 100644 --- a/ui/src/domain/domain.ts +++ b/ui/src/domain/domain.ts @@ -56,16 +56,6 @@ export type ApplyConfig = { disableFollowCNAME?: boolean; }; -export type Statistic = { - certificateTotal: number; - certificateExpired: number; - certificateExpireSoon: number; - - workflowTotal: number; - workflowEnabled: number; - workflowDisabled: number; -}; - export type DeployTarget = { type: string; provider: string; diff --git a/ui/src/domain/settings.ts b/ui/src/domain/settings.ts index df2e2b04..8ebd4ea6 100644 --- a/ui/src/domain/settings.ts +++ b/ui/src/domain/settings.ts @@ -1,6 +1,6 @@ import { type BaseModel } from "pocketbase"; -export interface Settings extends BaseModel { +export interface SettingsModel extends BaseModel { name: string; content: T; } diff --git a/ui/src/domain/statistics.ts b/ui/src/domain/statistics.ts new file mode 100644 index 00000000..588eda7f --- /dev/null +++ b/ui/src/domain/statistics.ts @@ -0,0 +1,8 @@ +export type Statistics = { + certificateTotal: number; + certificateExpired: number; + certificateExpireSoon: number; + workflowTotal: number; + workflowEnabled: number; + workflowDisabled: number; +}; diff --git a/ui/src/domain/workflow.ts b/ui/src/domain/workflow.ts index 0f74bc09..6c8af35d 100644 --- a/ui/src/domain/workflow.ts +++ b/ui/src/domain/workflow.ts @@ -1,5 +1,6 @@ import { produce } from "immer"; import { nanoid } from "nanoid"; +import { type BaseModel } from "pocketbase"; import i18n from "@/i18n"; import { deployTargets, KVType } from "./domain"; @@ -27,8 +28,7 @@ export type WorkflowOutput = { error: string; }; -export type Workflow = { - id: string; +export interface WorkflowModel extends BaseModel { name: string; description?: string; type: string; @@ -37,9 +37,7 @@ export type Workflow = { draft?: WorkflowNode; enabled?: boolean; hasDraft?: boolean; - created?: string; - updated?: string; -}; +} export enum WorkflowNodeType { Start = "start", @@ -131,7 +129,7 @@ type NewWorkflowNodeOptions = { providerType?: string; }; -export const initWorkflow = (): Workflow => { +export const initWorkflow = (): WorkflowModel => { // 开始节点 const rs = newWorkflowNode(WorkflowNodeType.Start, {}); let root = rs; diff --git a/ui/src/pages/ConsoleLayout.tsx b/ui/src/pages/ConsoleLayout.tsx index bc5d6b2f..7f0824b7 100644 --- a/ui/src/pages/ConsoleLayout.tsx +++ b/ui/src/pages/ConsoleLayout.tsx @@ -18,7 +18,6 @@ import { import Version from "@/components/certimate/Version"; import { useTheme } from "@/hooks"; import { getPocketBase } from "@/repository/pocketbase"; -import { ConfigProvider } from "@/providers/config"; const ConsoleLayout = () => { const navigate = useNavigate(); @@ -52,65 +51,61 @@ const ConsoleLayout = () => { } return ( - <> - - - -
-
- -
-
- -
+ + +
+
+ +
+
+ +
+
+
+ + + +
+
+
- +
+ + + + + + + +
+
+
- - -
-
-
-
- - - - - - - -
-
-
- - -
- -
-
-
-
- - + +
+ +
+
+
+ ); }; diff --git a/ui/src/pages/accesses/AccessList.tsx b/ui/src/pages/accesses/AccessList.tsx index 174db0b6..ee346d2f 100644 --- a/ui/src/pages/accesses/AccessList.tsx +++ b/ui/src/pages/accesses/AccessList.tsx @@ -7,9 +7,8 @@ import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; import AccessEditDialog from "@/components/certimate/AccessEditDialog"; -import { accessProvidersMap, type Access as AccessType } from "@/domain/access"; -import { remove as removeAccess } from "@/repository/access"; -import { useConfigContext } from "@/providers/config"; +import { accessProvidersMap, type AccessModel } from "@/domain/access"; +import { useAccessStore } from "@/stores/access"; const AccessList = () => { const { t } = useTranslation(); @@ -17,9 +16,11 @@ const AccessList = () => { const [modalApi, ModelContextHolder] = Modal.useModal(); const [notificationApi, NotificationContextHolder] = notification.useNotification(); + const { accesses, fetchAccesses, deleteAccess } = useAccessStore(); + const [loading, setLoading] = useState(false); - const tableColumns: TableProps["columns"] = [ + const tableColumns: TableProps["columns"] = [ { key: "$index", align: "center", @@ -105,13 +106,15 @@ const AccessList = () => { ), }, ]; - const [tableData, setTableData] = useState([]); + const [tableData, setTableData] = useState([]); const [tableTotal, setTableTotal] = useState(0); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); - const configContext = useConfigContext(); + useEffect(() => { + fetchAccesses(); + }, []); const fetchTableData = useCallback(async () => { if (loading) return; @@ -120,10 +123,10 @@ const AccessList = () => { try { const startIndex = (page - 1) * pageSize; const endIndex = startIndex + pageSize; - const items = configContext.config?.accesses?.slice(startIndex, endIndex) ?? []; + const items = accesses.slice(startIndex, endIndex); setTableData(items); - setTableTotal(configContext.config?.accesses?.length ?? 0); + setTableTotal(accesses.length); } catch (err) { if (err instanceof ClientResponseError && err.isAbort) { return; @@ -134,21 +137,20 @@ const AccessList = () => { } finally { setLoading(false); } - }, [page, pageSize, configContext.config.accesses]); + }, [page, pageSize, accesses]); useEffect(() => { fetchTableData(); }, [fetchTableData]); - const handleDeleteClick = async (data: AccessType) => { + const handleDeleteClick = async (data: AccessModel) => { modalApi.confirm({ title: t("access.action.delete"), content: t("access.action.delete.confirm"), onOk: async () => { // TODO: 有关联数据的不允许被删除 try { - const res = await removeAccess(data); - configContext.deleteAccess(res.id); + await deleteAccess(data); } catch (err) { console.error(err); notificationApi.error({ message: t("common.text.request_error"), description: <>{String(err)} }); @@ -177,7 +179,7 @@ const AccessList = () => { ]} /> - + columns={tableColumns} dataSource={tableData} loading={loading} diff --git a/ui/src/pages/certificates/CertificateList.tsx b/ui/src/pages/certificates/CertificateList.tsx index 2f918087..9938c011 100644 --- a/ui/src/pages/certificates/CertificateList.tsx +++ b/ui/src/pages/certificates/CertificateList.tsx @@ -8,7 +8,7 @@ import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; import CertificateDetailDrawer from "@/components/certificate/CertificateDetailDrawer"; -import { Certificate as CertificateType } from "@/domain/certificate"; +import { CertificateModel } from "@/domain/certificate"; import { list as listCertificate, type CertificateListReq } from "@/repository/certificate"; const CertificateList = () => { @@ -23,7 +23,7 @@ const CertificateList = () => { const [loading, setLoading] = useState(false); - const tableColumns: TableProps["columns"] = [ + const tableColumns: TableProps["columns"] = [ { key: "$index", align: "center", @@ -165,7 +165,7 @@ const CertificateList = () => { ), }, ]; - const [tableData, setTableData] = useState([]); + const [tableData, setTableData] = useState([]); const [tableTotal, setTableTotal] = useState(0); const [filters, setFilters] = useState>(() => { @@ -177,7 +177,7 @@ const CertificateList = () => { const [page, setPage] = useState(() => parseInt(+searchParams.get("page")! + "") || 1); const [pageSize, setPageSize] = useState(() => parseInt(+searchParams.get("perPage")! + "") || 10); - const [currentRecord, setCurrentRecord] = useState(); + const [currentRecord, setCurrentRecord] = useState(); const [drawerOpen, setDrawerOpen] = useState(false); @@ -210,7 +210,7 @@ const CertificateList = () => { fetchTableData(); }, [fetchTableData]); - const handleViewClick = (certificate: CertificateType) => { + const handleViewClick = (certificate: CertificateModel) => { setDrawerOpen(true); setCurrentRecord(certificate); }; @@ -221,7 +221,7 @@ const CertificateList = () => { - + columns={tableColumns} dataSource={tableData} loading={loading} diff --git a/ui/src/pages/dashboard/Dashboard.tsx b/ui/src/pages/dashboard/Dashboard.tsx index f767037a..3ca4a51a 100644 --- a/ui/src/pages/dashboard/Dashboard.tsx +++ b/ui/src/pages/dashboard/Dashboard.tsx @@ -12,7 +12,7 @@ import { } from "lucide-react"; import { ClientResponseError } from "pocketbase"; -import { type Statistic as StatisticType } from "@/domain/domain"; +import { type Statistics } from "@/domain/statistics"; import { get as getStatistics } from "@/api/statistics"; const Dashboard = () => { @@ -26,7 +26,7 @@ const Dashboard = () => { const [loading, setLoading] = useState(false); - const statisticGridSpans = { + const statisticsGridSpans = { xs: { flex: "50%" }, md: { flex: "50%" }, lg: { flex: "33.3333%" }, @@ -34,15 +34,15 @@ const Dashboard = () => { xxl: { flex: "20%" }, }; - const [statistic, setStatistic] = useState(); + const [statistics, setStatistics] = useState(); - const fetchStatistic = useCallback(async () => { + const fetchStatistics = useCallback(async () => { if (loading) return; setLoading(true); try { const data = await getStatistics(); - setStatistic(data); + setStatistics(data); } catch (err) { if (err instanceof ClientResponseError && err.isAbort) { return; @@ -56,7 +56,7 @@ const Dashboard = () => { }, []); useEffect(() => { - fetchStatistic(); + fetchStatistics(); }, []); return ( @@ -66,47 +66,47 @@ const Dashboard = () => { - + } label={t("dashboard.statistics.all_certificates")} - value={statistic?.certificateTotal ?? "-"} + value={statistics?.certificateTotal ?? "-"} suffix={t("dashboard.statistics.unit")} onClick={() => navigate("/certificates")} /> - + } label={t("dashboard.statistics.expire_soon_certificates")} - value={statistic?.certificateExpireSoon ?? "-"} + value={statistics?.certificateExpireSoon ?? "-"} suffix={t("dashboard.statistics.unit")} onClick={() => navigate("/certificates?state=expireSoon")} /> - + } label={t("dashboard.statistics.expired_certificates")} - value={statistic?.certificateExpired ?? "-"} + value={statistics?.certificateExpired ?? "-"} suffix={t("dashboard.statistics.unit")} onClick={() => navigate("/certificates?state=expired")} /> - + } label={t("dashboard.statistics.all_workflows")} - value={statistic?.workflowTotal ?? "-"} + value={statistics?.workflowTotal ?? "-"} suffix={t("dashboard.statistics.unit")} onClick={() => navigate("/workflows")} /> - + } label={t("dashboard.statistics.enabled_workflows")} - value={statistic?.workflowEnabled ?? "-"} + value={statistics?.workflowEnabled ?? "-"} suffix={t("dashboard.statistics.unit")} onClick={() => navigate("/workflows?state=enabled")} /> diff --git a/ui/src/pages/settings/SSLProvider.tsx b/ui/src/pages/settings/SSLProvider.tsx index 879e1472..34477613 100644 --- a/ui/src/pages/settings/SSLProvider.tsx +++ b/ui/src/pages/settings/SSLProvider.tsx @@ -12,14 +12,14 @@ import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { useToast } from "@/components/ui/use-toast"; import { getErrMsg } from "@/utils/error"; -import { SSLProvider as SSLProviderType, SSLProviderSetting, Settings } from "@/domain/settings"; +import { SSLProvider as SSLProviderType, SSLProviderSetting, SettingsModel } from "@/domain/settings"; import { get, save } from "@/repository/settings"; import { produce } from "immer"; type SSLProviderContext = { - setting: Settings; - onSubmit: (data: Settings) => void; - setConfig: (config: Settings) => void; + setting: SettingsModel; + onSubmit: (data: SettingsModel) => void; + setConfig: (config: SettingsModel) => void; }; const Context = createContext({} as SSLProviderContext); @@ -31,12 +31,12 @@ export const useSSLProviderContext = () => { const SSLProvider = () => { const { t } = useTranslation(); - const [config, setConfig] = useState>({ + const [config, setConfig] = useState>({ content: { provider: "letsencrypt", config: {}, }, - } as Settings); + } as SettingsModel); const { toast } = useToast(); @@ -73,7 +73,7 @@ const SSLProvider = () => { return ""; }; - const onSubmit = async (data: Settings) => { + const onSubmit = async (data: SettingsModel) => { try { console.log(data); const resp = await save({ ...data }); diff --git a/ui/src/pages/workflows/WorkflowList.tsx b/ui/src/pages/workflows/WorkflowList.tsx index 320a934c..d3923ee9 100644 --- a/ui/src/pages/workflows/WorkflowList.tsx +++ b/ui/src/pages/workflows/WorkflowList.tsx @@ -23,7 +23,7 @@ import { Filter as FilterIcon, Pencil as PencilIcon, Plus as PlusIcon, Trash2 as import dayjs from "dayjs"; import { ClientResponseError } from "pocketbase"; -import { Workflow as WorkflowType } from "@/domain/workflow"; +import { WorkflowModel } from "@/domain/workflow"; import { list as listWorkflow, remove as removeWorkflow, save as saveWorkflow } from "@/repository/workflow"; const WorkflowList = () => { @@ -39,7 +39,7 @@ const WorkflowList = () => { const [loading, setLoading] = useState(false); - const tableColumns: TableProps["columns"] = [ + const tableColumns: TableProps["columns"] = [ { key: "$index", align: "center", @@ -196,7 +196,7 @@ const WorkflowList = () => { ), }, ]; - const [tableData, setTableData] = useState([]); + const [tableData, setTableData] = useState([]); const [tableTotal, setTableTotal] = useState(0); const [filters, setFilters] = useState>(() => { @@ -237,7 +237,7 @@ const WorkflowList = () => { fetchTableData(); }, [fetchTableData]); - const handleEnabledChange = async (workflow: WorkflowType) => { + const handleEnabledChange = async (workflow: WorkflowModel) => { try { const resp = await saveWorkflow({ id: workflow.id, @@ -259,7 +259,7 @@ const WorkflowList = () => { } }; - const handleDeleteClick = (workflow: WorkflowType) => { + const handleDeleteClick = (workflow: WorkflowModel) => { modalApi.confirm({ title: t("workflow.action.delete"), content: t("workflow.action.delete.confirm"), @@ -302,7 +302,7 @@ const WorkflowList = () => { ]} /> - + columns={tableColumns} dataSource={tableData} loading={loading} diff --git a/ui/src/providers/config/index.tsx b/ui/src/providers/config/index.tsx deleted file mode 100644 index 7a3162fa..00000000 --- a/ui/src/providers/config/index.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { createContext, useCallback, useContext, useEffect, useReducer, type ReactNode } from "react"; - -import { type Access as AccessType } from "@/domain/access"; -import { list as listAccess } from "@/repository/access"; -import { configReducer } from "./reducer"; - -export type ConfigData = { - accesses: AccessType[]; -}; - -export type ConfigContext = { - config: ConfigData; - addAccess: (access: AccessType) => void; - updateAccess: (access: AccessType) => void; - deleteAccess: (id: string) => void; -}; - -const Context = createContext({} as ConfigContext); - -export const useConfigContext = () => useContext(Context); - -export const ConfigProvider = ({ children }: { children: ReactNode }) => { - const [config, dispatchConfig] = useReducer(configReducer, { - accesses: [], - }); - - useEffect(() => { - const featchData = async () => { - const data = await listAccess(); - dispatchConfig({ type: "SET_ACCESSES", payload: data }); - }; - featchData(); - }, []); - - const deleteAccess = useCallback((id: string) => { - dispatchConfig({ type: "DELETE_ACCESS", payload: id }); - }, []); - - const addAccess = useCallback((access: AccessType) => { - dispatchConfig({ type: "ADD_ACCESS", payload: access }); - }, []); - - const updateAccess = useCallback((access: AccessType) => { - dispatchConfig({ type: "UPDATE_ACCESS", payload: access }); - }, []); - - return ( - - {children} - - ); -}; diff --git a/ui/src/providers/config/reducer.ts b/ui/src/providers/config/reducer.ts deleted file mode 100644 index 7864d30d..00000000 --- a/ui/src/providers/config/reducer.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Access } from "@/domain/access"; -import { ConfigData } from "./"; - -type Action = - | { type: "ADD_ACCESS"; payload: Access } - | { type: "DELETE_ACCESS"; payload: string } - | { type: "UPDATE_ACCESS"; payload: Access } - | { type: "SET_ACCESSES"; payload: Access[] }; - -export const configReducer = (state: ConfigData, action: Action): ConfigData => { - switch (action.type) { - case "SET_ACCESSES": { - return { - ...state, - accesses: action.payload, - }; - } - case "ADD_ACCESS": { - return { - ...state, - accesses: [action.payload, ...state.accesses], - }; - } - case "DELETE_ACCESS": { - return { - ...state, - accesses: state.accesses.filter((access) => access.id !== action.payload), - }; - } - case "UPDATE_ACCESS": { - return { - ...state, - accesses: state.accesses.map((access) => (access.id === action.payload.id ? action.payload : access)), - }; - } - default: - return state; - } -}; diff --git a/ui/src/providers/notify/index.tsx b/ui/src/providers/notify/index.tsx index 73a331fa..963babd9 100644 --- a/ui/src/providers/notify/index.tsx +++ b/ui/src/providers/notify/index.tsx @@ -1,13 +1,13 @@ import { ReactNode, useContext, createContext, useEffect, useReducer, useCallback } from "react"; -import { NotifyChannel, NotifyChannels, Settings } from "@/domain/settings"; +import { NotifyChannel, NotifyChannels, SettingsModel } from "@/domain/settings"; import { get } from "@/repository/settings"; import { notifyReducer } from "./reducer"; export type NotifyContext = { - config: Settings; + config: SettingsModel; setChannel: (data: { channel: string; data: NotifyChannel }) => void; - setChannels: (data: Settings) => void; + setChannels: (data: SettingsModel) => void; initChannels: () => void; }; @@ -45,7 +45,7 @@ export const NotifyProvider = ({ children }: NotifyProviderProps) => { }); }, []); - const setChannels = useCallback((setting: Settings) => { + const setChannels = useCallback((setting: SettingsModel) => { dispatchNotify({ type: "SET_CHANNELS", payload: setting, diff --git a/ui/src/providers/notify/reducer.tsx b/ui/src/providers/notify/reducer.tsx index 1641c594..cea2092c 100644 --- a/ui/src/providers/notify/reducer.tsx +++ b/ui/src/providers/notify/reducer.tsx @@ -1,4 +1,4 @@ -import { NotifyChannel, NotifyChannels, Settings } from "@/domain/settings"; +import { NotifyChannel, NotifyChannels, SettingsModel } from "@/domain/settings"; type Action = | { @@ -10,10 +10,10 @@ type Action = } | { type: "SET_CHANNELS"; - payload: Settings; + payload: SettingsModel; }; -export const notifyReducer = (state: Settings, action: Action) => { +export const notifyReducer = (state: SettingsModel, action: Action) => { switch (action.type) { case "SET_CHANNEL": { const channel = action.payload.channel; diff --git a/ui/src/repository/access.ts b/ui/src/repository/access.ts index 08bd7833..bc4ab8c8 100644 --- a/ui/src/repository/access.ts +++ b/ui/src/repository/access.ts @@ -1,24 +1,26 @@ import dayjs from "dayjs"; -import { type Access } from "@/domain/access"; +import { type AccessModel } from "@/domain/access"; import { getPocketBase } from "./pocketbase"; +const COLLECTION_NAME = "access"; + export const list = async () => { - return await getPocketBase().collection("access").getFullList({ + return await getPocketBase().collection(COLLECTION_NAME).getFullList({ sort: "-created", - filter: "deleted = null", + filter: "deleted=null", }); }; -export const save = async (record: Access) => { +export const save = async (record: AccessModel) => { if (record.id) { - return await getPocketBase().collection("access").update(record.id, record); + return await getPocketBase().collection(COLLECTION_NAME).update(record.id, record); } - return await getPocketBase().collection("access").create(record); + return await getPocketBase().collection(COLLECTION_NAME).create(record); }; -export const remove = async (record: Access) => { - record.deleted = dayjs.utc().format("YYYY-MM-DD HH:mm:ss"); - return await getPocketBase().collection("access").update(record.id, record); +export const remove = async (record: AccessModel) => { + record = { ...record, deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") }; + await getPocketBase().collection(COLLECTION_NAME).update(record.id, record); }; diff --git a/ui/src/repository/certificate.ts b/ui/src/repository/certificate.ts index 52487192..ca08151b 100644 --- a/ui/src/repository/certificate.ts +++ b/ui/src/repository/certificate.ts @@ -1,9 +1,11 @@ import dayjs from "dayjs"; import { type RecordListOptions } from "pocketbase"; -import { type Certificate } from "@/domain/certificate"; +import { type CertificateModel } from "@/domain/certificate"; import { getPocketBase } from "./pocketbase"; +const COLLECTION_NAME = "certificate"; + export type CertificateListReq = { page?: number; perPage?: number; @@ -31,5 +33,5 @@ export const list = async (req: CertificateListReq) => { }); } - return pb.collection("certificate").getList(page, perPage, options); + return pb.collection(COLLECTION_NAME).getList(page, perPage, options); }; diff --git a/ui/src/repository/settings.ts b/ui/src/repository/settings.ts index 3ea1b5ba..613a430f 100644 --- a/ui/src/repository/settings.ts +++ b/ui/src/repository/settings.ts @@ -1,22 +1,22 @@ -import { Settings } from "@/domain/settings"; +import { SettingsModel } from "@/domain/settings"; import { getPocketBase } from "./pocketbase"; export const get = async (name: string) => { try { - const resp = await getPocketBase().collection("settings").getFirstListItem>(`name='${name}'`); + const resp = await getPocketBase().collection("settings").getFirstListItem>(`name='${name}'`); return resp; } catch { return { name: name, content: {} as T, - } as Settings; + } as SettingsModel; } }; -export const save = async (record: Settings) => { +export const save = async (record: SettingsModel) => { if (record.id) { - return await getPocketBase().collection("settings").update>(record.id, record); + return await getPocketBase().collection("settings").update>(record.id, record); } - return await getPocketBase().collection("settings").create>(record); + return await getPocketBase().collection("settings").create>(record); }; diff --git a/ui/src/repository/workflow.ts b/ui/src/repository/workflow.ts index a74c6cb4..2aecfb1e 100644 --- a/ui/src/repository/workflow.ts +++ b/ui/src/repository/workflow.ts @@ -1,8 +1,10 @@ import { type RecordListOptions } from "pocketbase"; -import { type Workflow, type WorkflowNode, type WorkflowRunLog } from "@/domain/workflow"; +import { type WorkflowModel, type WorkflowNode, type WorkflowRunLog } from "@/domain/workflow"; import { getPocketBase } from "./pocketbase"; +const COLLECTION_NAME = "workflow"; + export type WorkflowListReq = { page?: number; perPage?: number; @@ -20,25 +22,25 @@ export const list = async (req: WorkflowListReq) => { options.filter = pb.filter("enabled={:enabled}", { enabled: req.enabled }); } - return await pb.collection("workflow").getList(page, perPage, options); + return await pb.collection(COLLECTION_NAME).getList(page, perPage, options); }; export const get = async (id: string) => { - return await getPocketBase().collection("workflow").getOne(id); + return await getPocketBase().collection(COLLECTION_NAME).getOne(id); }; export const save = async (record: Record) => { if (record.id) { return await getPocketBase() - .collection("workflow") - .update(record.id as string, record); + .collection(COLLECTION_NAME) + .update(record.id as string, record); } - return await getPocketBase().collection("workflow").create(record); + return await getPocketBase().collection(COLLECTION_NAME).create(record); }; -export const remove = async (record: Workflow) => { - return await getPocketBase().collection("workflow").delete(record.id); +export const remove = async (record: WorkflowModel) => { + await getPocketBase().collection(COLLECTION_NAME).delete(record.id); }; type WorkflowLogsReq = { diff --git a/ui/src/stores/access/index.ts b/ui/src/stores/access/index.ts new file mode 100644 index 00000000..c67167e7 --- /dev/null +++ b/ui/src/stores/access/index.ts @@ -0,0 +1,58 @@ +import { create } from "zustand"; +import { produce } from "immer"; + +import { type AccessModel } from "@/domain/access"; +import { list as listAccess, save as saveAccess, remove as removeAccess } from "@/repository/access"; + +export interface AccessState { + accesses: AccessModel[]; + createAccess: (access: AccessModel) => void; + updateAccess: (access: AccessModel) => void; + deleteAccess: (access: AccessModel) => void; + fetchAccesses: () => Promise; +} + +export const useAccessStore = create((set) => { + return { + accesses: [], + + createAccess: async (access) => { + access = await saveAccess(access); + + set( + produce((state: AccessState) => { + state.accesses.unshift(access); + }) + ); + }, + + updateAccess: async (access) => { + access = await saveAccess(access); + + set( + produce((state: AccessState) => { + const index = state.accesses.findIndex((e) => e.id === access.id); + state.accesses[index] = access; + }) + ); + }, + + deleteAccess: async (access) => { + await removeAccess(access); + + set( + produce((state: AccessState) => { + state.accesses = state.accesses.filter((a) => a.id !== access.id); + }) + ); + }, + + fetchAccesses: async () => { + const accesses = await listAccess(); + + set({ + accesses: accesses ?? [], + }); + }, + }; +}); diff --git a/ui/src/stores/contact/index.ts b/ui/src/stores/contact/index.ts index 8b0bb3ef..6d4dabfe 100644 --- a/ui/src/stores/contact/index.ts +++ b/ui/src/stores/contact/index.ts @@ -1,7 +1,7 @@ import { create } from "zustand"; import { produce } from "immer"; -import { type EmailsSettingsContent, type Settings } from "@/domain/settings"; +import { type EmailsSettingsContent, type SettingsModel } from "@/domain/settings"; import { get as getSettings, save as saveSettings } from "@/repository/settings"; export interface ContactState { @@ -11,7 +11,7 @@ export interface ContactState { } export const useContactStore = create((set) => { - let settings: Settings; + let settings: SettingsModel; return { emails: [], diff --git a/ui/src/stores/workflow/index.ts b/ui/src/stores/workflow/index.ts index 6cdbdcd4..ef6c72bb 100644 --- a/ui/src/stores/workflow/index.ts +++ b/ui/src/stores/workflow/index.ts @@ -9,7 +9,7 @@ import { removeBranch, removeNode, updateNode, - Workflow, + WorkflowModel, WorkflowBranchNode, WorkflowNode, WorkflowNodeType, @@ -17,7 +17,7 @@ import { import { get as getWorkflow, save as saveWorkflow } from "@/repository/workflow"; export type WorkflowState = { - workflow: Workflow; + workflow: WorkflowModel; initialized: boolean; updateNode: (node: WorkflowNode) => void; addNode: (node: WorkflowNode, preId: string) => void;