mirror of
https://github.com/usual2970/certimate.git
synced 2025-06-28 07:09:58 +00:00
refactor(ui): clean code
This commit is contained in:
parent
e256d36cd1
commit
7f36621882
@ -4,8 +4,8 @@ import { useControllableValue } from "ahooks";
|
|||||||
import { Modal, notification } from "antd";
|
import { Modal, notification } from "antd";
|
||||||
|
|
||||||
import { type AccessModel } from "@/domain/access";
|
import { type AccessModel } from "@/domain/access";
|
||||||
import { useTriggerElement } from "@/hooks";
|
import { useTriggerElement, useZustandShallowSelector } from "@/hooks";
|
||||||
import { useAccessStore } from "@/stores/access";
|
import { useAccessesStore } from "@/stores/access";
|
||||||
import { getErrMsg } from "@/utils/error";
|
import { getErrMsg } from "@/utils/error";
|
||||||
|
|
||||||
import AccessEditForm, { type AccessEditFormInstance, type AccessEditFormProps } from "./AccessEditForm";
|
import AccessEditForm, { type AccessEditFormInstance, type AccessEditFormProps } from "./AccessEditForm";
|
||||||
@ -25,7 +25,7 @@ const AccessEditModal = ({ data, loading, trigger, preset, onSubmit, ...props }:
|
|||||||
|
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
const { createAccess, updateAccess } = useAccessStore();
|
const { createAccess, updateAccess } = useAccessesStore(useZustandShallowSelector(["createAccess", "updateAccess"]));
|
||||||
|
|
||||||
const [open, setOpen] = useControllableValue<boolean>(props, {
|
const [open, setOpen] = useControllableValue<boolean>(props, {
|
||||||
valuePropName: "open",
|
valuePropName: "open",
|
||||||
|
@ -3,7 +3,8 @@ import { Avatar, Select, Space, Typography, type SelectProps } from "antd";
|
|||||||
|
|
||||||
import { type AccessModel } from "@/domain/access";
|
import { type AccessModel } from "@/domain/access";
|
||||||
import { accessProvidersMap } from "@/domain/provider";
|
import { accessProvidersMap } from "@/domain/provider";
|
||||||
import { useAccessStore } from "@/stores/access";
|
import { useZustandShallowSelector } from "@/hooks";
|
||||||
|
import { useAccessesStore } from "@/stores/access";
|
||||||
|
|
||||||
export type AccessTypeSelectProps = Omit<
|
export type AccessTypeSelectProps = Omit<
|
||||||
SelectProps,
|
SelectProps,
|
||||||
@ -13,7 +14,7 @@ export type AccessTypeSelectProps = Omit<
|
|||||||
};
|
};
|
||||||
|
|
||||||
const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
|
const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
|
||||||
const { accesses, loadedAtOnce, fetchAccesses } = useAccessStore();
|
const { accesses, loadedAtOnce, fetchAccesses } = useAccessesStore(useZustandShallowSelector(["accesses", "loadedAtOnce", "fetchAccesses"]));
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAccesses();
|
fetchAccesses();
|
||||||
}, [fetchAccesses]);
|
}, [fetchAccesses]);
|
||||||
|
@ -5,7 +5,8 @@ import { Button, Collapse, message, notification, Skeleton, Space, Switch, type
|
|||||||
|
|
||||||
import Show from "@/components/Show";
|
import Show from "@/components/Show";
|
||||||
import { notifyChannelsMap } from "@/domain/settings";
|
import { notifyChannelsMap } from "@/domain/settings";
|
||||||
import { useNotifyChannelStore } from "@/stores/notify";
|
import { useZustandShallowSelector } from "@/hooks";
|
||||||
|
import { useNotifyChannelsStore } from "@/stores/notify";
|
||||||
import { getErrMsg } from "@/utils/error";
|
import { getErrMsg } from "@/utils/error";
|
||||||
|
|
||||||
import NotifyChannelEditForm, { type NotifyChannelEditFormInstance } from "./NotifyChannelEditForm";
|
import NotifyChannelEditForm, { type NotifyChannelEditFormInstance } from "./NotifyChannelEditForm";
|
||||||
@ -23,7 +24,7 @@ const NotifyChannel = ({ className, style, channel }: NotifyChannelProps) => {
|
|||||||
const [messageApi, MessageContextHolder] = message.useMessage();
|
const [messageApi, MessageContextHolder] = message.useMessage();
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
const { channels, setChannel } = useNotifyChannelStore();
|
const { channels, setChannel } = useNotifyChannelsStore(useZustandShallowSelector(["channels", "setChannel"]));
|
||||||
|
|
||||||
const channelConfig = useDeepCompareMemo(() => channels[channel], [channels, channel]);
|
const channelConfig = useDeepCompareMemo(() => channels[channel], [channels, channel]);
|
||||||
const channelFormRef = useRef<NotifyChannelEditFormInstance>(null);
|
const channelFormRef = useRef<NotifyChannelEditFormInstance>(null);
|
||||||
@ -78,7 +79,7 @@ export type NotifyChannelsProps = {
|
|||||||
const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannelsProps) => {
|
const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannelsProps) => {
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
|
|
||||||
const { channels, loadedAtOnce, setChannel, fetchChannels } = useNotifyChannelStore();
|
const { channels, loadedAtOnce, setChannel, fetchChannels } = useNotifyChannelsStore();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchChannels();
|
fetchChannels();
|
||||||
}, [fetchChannels]);
|
}, [fetchChannels]);
|
||||||
|
@ -35,7 +35,7 @@ const Node = ({ data }: NodeProps) => {
|
|||||||
|
|
||||||
updateNode(
|
updateNode(
|
||||||
produce(data, (draft) => {
|
produce(data, (draft) => {
|
||||||
draft.name = e.target.innerText;
|
draft.name = newName;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -66,8 +66,10 @@ const Node = ({ data }: NodeProps) => {
|
|||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
case WorkflowNodeType.Apply:
|
case WorkflowNodeType.Apply:
|
||||||
return <div className="text-muted-foreground truncate">{data.config?.domain as string}</div>;
|
return <div className="text-muted-foreground truncate">{data.config?.domain as string}</div>;
|
||||||
|
|
||||||
case WorkflowNodeType.Deploy: {
|
case WorkflowNodeType.Deploy: {
|
||||||
const provider = deployProvidersMap.get(data.config?.providerType as string);
|
const provider = deployProvidersMap.get(data.config?.providerType as string);
|
||||||
return (
|
return (
|
||||||
@ -77,6 +79,7 @@ const Node = ({ data }: NodeProps) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
case WorkflowNodeType.Notify: {
|
case WorkflowNodeType.Notify: {
|
||||||
const channelLabel = notifyChannelsMap.get(data.config?.channel as string);
|
const channelLabel = notifyChannelsMap.get(data.config?.channel as string);
|
||||||
return (
|
return (
|
||||||
|
@ -14,7 +14,7 @@ import MultipleInput from "@/components/core/MultipleInput";
|
|||||||
import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider";
|
import { ACCESS_USAGES, accessProvidersMap } from "@/domain/provider";
|
||||||
import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow";
|
import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow";
|
||||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||||
import { useContactStore } from "@/stores/contact";
|
import { useContactEmailsStore } from "@/stores/contact";
|
||||||
import { useWorkflowStore } from "@/stores/workflow";
|
import { useWorkflowStore } from "@/stores/workflow";
|
||||||
import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators";
|
import { validDomainName, validIPv4Address, validIPv6Address } from "@/utils/validators";
|
||||||
import { usePanel } from "../PanelProvider";
|
import { usePanel } from "../PanelProvider";
|
||||||
@ -38,7 +38,7 @@ const initFormModel = (): WorkflowNodeConfig => {
|
|||||||
const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
|
const ApplyNodeForm = ({ data }: ApplyNodeFormProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { addEmail } = useContactStore();
|
const { addEmail } = useContactEmailsStore(useZustandShallowSelector("addEmail"));
|
||||||
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
|
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
|
||||||
const { hidePanel } = usePanel();
|
const { hidePanel } = usePanel();
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ const FormFieldEmailSelect = ({
|
|||||||
value?: string;
|
value?: string;
|
||||||
onChange?: (value: string) => void;
|
onChange?: (value: string) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const { emails, fetchEmails } = useContactStore();
|
const { emails, fetchEmails } = useContactEmailsStore();
|
||||||
const emailsToOptions = useCallback(() => emails.map((email) => ({ label: email, value: email })), [emails]);
|
const emailsToOptions = useCallback(() => emails.map((email) => ({ label: email, value: email })), [emails]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchEmails();
|
fetchEmails();
|
||||||
|
@ -10,7 +10,7 @@ import { z } from "zod";
|
|||||||
import { notifyChannelsMap } from "@/domain/settings";
|
import { notifyChannelsMap } from "@/domain/settings";
|
||||||
import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow";
|
import { type WorkflowNode, type WorkflowNodeConfig } from "@/domain/workflow";
|
||||||
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
|
||||||
import { useNotifyChannelStore } from "@/stores/notify";
|
import { useNotifyChannelsStore } from "@/stores/notify";
|
||||||
import { useWorkflowStore } from "@/stores/workflow";
|
import { useWorkflowStore } from "@/stores/workflow";
|
||||||
import { usePanel } from "../PanelProvider";
|
import { usePanel } from "../PanelProvider";
|
||||||
|
|
||||||
@ -28,14 +28,18 @@ const initFormModel = (): WorkflowNodeConfig => {
|
|||||||
const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => {
|
const NotifyNodeForm = ({ data }: NotifyNodeFormProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
|
const {
|
||||||
const { hidePanel } = usePanel();
|
channels,
|
||||||
|
loadedAtOnce: channelsLoadedAtOnce,
|
||||||
const { channels, loadedAtOnce: channelsLoadedAtOnce, fetchChannels } = useNotifyChannelStore();
|
fetchChannels,
|
||||||
|
} = useNotifyChannelsStore(useZustandShallowSelector(["channels", "loadedAtOnce", "fetchChannels"]));
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchChannels();
|
fetchChannels();
|
||||||
}, [fetchChannels]);
|
}, [fetchChannels]);
|
||||||
|
|
||||||
|
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
|
||||||
|
const { hidePanel } = usePanel();
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
subject: z
|
subject: z
|
||||||
.string({ message: t("workflow_node.notify.form.subject.placeholder") })
|
.string({ message: t("workflow_node.notify.form.subject.placeholder") })
|
||||||
|
@ -15,7 +15,8 @@ import { ClientResponseError } from "pocketbase";
|
|||||||
import AccessEditModal from "@/components/access/AccessEditModal";
|
import AccessEditModal from "@/components/access/AccessEditModal";
|
||||||
import { type AccessModel } from "@/domain/access";
|
import { type AccessModel } from "@/domain/access";
|
||||||
import { accessProvidersMap } from "@/domain/provider";
|
import { accessProvidersMap } from "@/domain/provider";
|
||||||
import { useAccessStore } from "@/stores/access";
|
import { useZustandShallowSelector } from "@/hooks";
|
||||||
|
import { useAccessesStore } from "@/stores/access";
|
||||||
import { getErrMsg } from "@/utils/error";
|
import { getErrMsg } from "@/utils/error";
|
||||||
|
|
||||||
const AccessList = () => {
|
const AccessList = () => {
|
||||||
@ -24,7 +25,9 @@ const AccessList = () => {
|
|||||||
const [modalApi, ModelContextHolder] = Modal.useModal();
|
const [modalApi, ModelContextHolder] = Modal.useModal();
|
||||||
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
const [notificationApi, NotificationContextHolder] = notification.useNotification();
|
||||||
|
|
||||||
const { accesses, loadedAtOnce, fetchAccesses, deleteAccess } = useAccessStore();
|
const { accesses, loadedAtOnce, fetchAccesses, deleteAccess } = useAccessesStore(
|
||||||
|
useZustandShallowSelector(["accesses", "loadedAtOnce", "fetchAccesses", "deleteAccess"])
|
||||||
|
);
|
||||||
|
|
||||||
const tableColumns: TableProps<AccessModel>["columns"] = [
|
const tableColumns: TableProps<AccessModel>["columns"] = [
|
||||||
{
|
{
|
||||||
|
@ -3,12 +3,13 @@ import { Card, Divider } from "antd";
|
|||||||
|
|
||||||
import NotifyChannels from "@/components/notification/NotifyChannels";
|
import NotifyChannels from "@/components/notification/NotifyChannels";
|
||||||
import NotifyTemplate from "@/components/notification/NotifyTemplate";
|
import NotifyTemplate from "@/components/notification/NotifyTemplate";
|
||||||
import { useNotifyChannelStore } from "@/stores/notify";
|
import { useZustandShallowSelector } from "@/hooks";
|
||||||
|
import { useNotifyChannelsStore } from "@/stores/notify";
|
||||||
|
|
||||||
const SettingsNotification = () => {
|
const SettingsNotification = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { loadedAtOnce } = useNotifyChannelStore();
|
const { loadedAtOnce } = useNotifyChannelsStore(useZustandShallowSelector(["loadedAtOnce"]));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
@ -4,7 +4,7 @@ import { create } from "zustand";
|
|||||||
import { type AccessModel } from "@/domain/access";
|
import { type AccessModel } from "@/domain/access";
|
||||||
import { list as listAccess, save as saveAccess, remove as removeAccess } from "@/repository/access";
|
import { list as listAccess, save as saveAccess, remove as removeAccess } from "@/repository/access";
|
||||||
|
|
||||||
export interface AccessState {
|
export interface AccessesState {
|
||||||
accesses: AccessModel[];
|
accesses: AccessModel[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
loadedAtOnce: boolean;
|
loadedAtOnce: boolean;
|
||||||
@ -15,7 +15,7 @@ export interface AccessState {
|
|||||||
deleteAccess: (access: MaybeModelRecordWithId<AccessModel>) => Promise<AccessModel>;
|
deleteAccess: (access: MaybeModelRecordWithId<AccessModel>) => Promise<AccessModel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAccessStore = create<AccessState>((set) => {
|
export const useAccessesStore = create<AccessesState>((set) => {
|
||||||
let fetcher: Promise<AccessModel[]> | null = null; // 防止多次重复请求
|
let fetcher: Promise<AccessModel[]> | null = null; // 防止多次重复请求
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -39,7 +39,7 @@ export const useAccessStore = create<AccessState>((set) => {
|
|||||||
createAccess: async (access) => {
|
createAccess: async (access) => {
|
||||||
const record = await saveAccess(access);
|
const record = await saveAccess(access);
|
||||||
set(
|
set(
|
||||||
produce((state: AccessState) => {
|
produce((state: AccessesState) => {
|
||||||
state.accesses.unshift(record);
|
state.accesses.unshift(record);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -50,7 +50,7 @@ export const useAccessStore = create<AccessState>((set) => {
|
|||||||
updateAccess: async (access) => {
|
updateAccess: async (access) => {
|
||||||
const record = await saveAccess(access);
|
const record = await saveAccess(access);
|
||||||
set(
|
set(
|
||||||
produce((state: AccessState) => {
|
produce((state: AccessesState) => {
|
||||||
const index = state.accesses.findIndex((e) => e.id === record.id);
|
const index = state.accesses.findIndex((e) => e.id === record.id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.accesses[index] = record;
|
state.accesses[index] = record;
|
||||||
@ -64,7 +64,7 @@ export const useAccessStore = create<AccessState>((set) => {
|
|||||||
deleteAccess: async (access) => {
|
deleteAccess: async (access) => {
|
||||||
await removeAccess(access);
|
await removeAccess(access);
|
||||||
set(
|
set(
|
||||||
produce((state: AccessState) => {
|
produce((state: AccessesState) => {
|
||||||
state.accesses = state.accesses.filter((a) => a.id !== access.id);
|
state.accesses = state.accesses.filter((a) => a.id !== access.id);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@ import { create } from "zustand";
|
|||||||
import { SETTINGS_NAMES, 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";
|
import { get as getSettings, save as saveSettings } from "@/repository/settings";
|
||||||
|
|
||||||
export interface ContactState {
|
export interface ContactEmailsState {
|
||||||
emails: string[];
|
emails: string[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
loadedAtOnce: boolean;
|
loadedAtOnce: boolean;
|
||||||
@ -15,7 +15,7 @@ export interface ContactState {
|
|||||||
removeEmail: (email: string) => Promise<void>;
|
removeEmail: (email: string) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useContactStore = create<ContactState>((set, get) => {
|
export const useContactEmailsStore = create<ContactEmailsState>((set, get) => {
|
||||||
let fetcher: Promise<SettingsModel<EmailsSettingsContent>> | null = null; // 防止多次重复请求
|
let fetcher: Promise<SettingsModel<EmailsSettingsContent>> | null = null; // 防止多次重复请求
|
||||||
let settings: SettingsModel<EmailsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
|
let settings: SettingsModel<EmailsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ export const useContactStore = create<ContactState>((set, get) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
set(
|
set(
|
||||||
produce((state: ContactState) => {
|
produce((state: ContactEmailsState) => {
|
||||||
state.emails = settings.content.emails?.sort() ?? [];
|
state.emails = settings.content.emails?.sort() ?? [];
|
||||||
state.loadedAtOnce = true;
|
state.loadedAtOnce = true;
|
||||||
})
|
})
|
||||||
|
@ -4,7 +4,7 @@ import { create } from "zustand";
|
|||||||
import { SETTINGS_NAMES, type NotifyChannelsSettingsContent, type SettingsModel } from "@/domain/settings";
|
import { SETTINGS_NAMES, type NotifyChannelsSettingsContent, type SettingsModel } from "@/domain/settings";
|
||||||
import { get as getSettings, save as saveSettings } from "@/repository/settings";
|
import { get as getSettings, save as saveSettings } from "@/repository/settings";
|
||||||
|
|
||||||
export interface NotifyChannelState {
|
export interface NotifyChannelsState {
|
||||||
channels: NotifyChannelsSettingsContent;
|
channels: NotifyChannelsSettingsContent;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
loadedAtOnce: boolean;
|
loadedAtOnce: boolean;
|
||||||
@ -14,7 +14,7 @@ export interface NotifyChannelState {
|
|||||||
setChannels: (channels: NotifyChannelsSettingsContent) => Promise<void>;
|
setChannels: (channels: NotifyChannelsSettingsContent) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
|
export const useNotifyChannelsStore = create<NotifyChannelsState>((set, get) => {
|
||||||
let fetcher: Promise<SettingsModel<NotifyChannelsSettingsContent>> | null = null; // 防止多次重复请求
|
let fetcher: Promise<SettingsModel<NotifyChannelsSettingsContent>> | null = null; // 防止多次重复请求
|
||||||
let settings: SettingsModel<NotifyChannelsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
|
let settings: SettingsModel<NotifyChannelsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
set(
|
set(
|
||||||
produce((state: NotifyChannelState) => {
|
produce((state: NotifyChannelsState) => {
|
||||||
state.channels = settings.content;
|
state.channels = settings.content;
|
||||||
state.loadedAtOnce = true;
|
state.loadedAtOnce = true;
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user