refactor(ui): useZustandShallowSelector

This commit is contained in:
Fu Diwei 2024-12-24 15:07:39 +08:00
parent 52d24ff2f2
commit 8b1ae309fb
51 changed files with 194 additions and 269 deletions

View File

@ -41,6 +41,7 @@ func (s *certificateService) InitSchedule(ctx context.Context) error {
return
}
msg := buildMsg(certs)
// TODO: 空指针 Bug
if err := notify.SendToAllChannels(msg.Subject, msg.Message); err != nil {
app.GetApp().Logger().Error("failed to send expire soon certificate", "err", err)
}

9
ui/package-lock.json generated
View File

@ -31,6 +31,7 @@
"lucide-react": "^0.469.0",
"nanoid": "^5.0.9",
"pocketbase": "^0.21.5",
"radash": "^12.1.0",
"react": "^18.3.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.3.1",
@ -6743,6 +6744,14 @@
}
]
},
"node_modules/radash": {
"version": "12.1.0",
"resolved": "https://registry.npmmirror.com/radash/-/radash-12.1.0.tgz",
"integrity": "sha512-b0Zcf09AhqKS83btmUeYBS8tFK7XL2e3RvLmZcm0sTdF1/UUlHSsjXdCcWNxe7yfmAlPve5ym0DmKGtTzP6kVQ==",
"engines": {
"node": ">=14.18.0"
}
},
"node_modules/rc-cascader": {
"version": "3.30.0",
"resolved": "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.30.0.tgz",

View File

@ -33,6 +33,7 @@
"lucide-react": "^0.469.0",
"nanoid": "^5.0.9",
"pocketbase": "^0.21.5",
"radash": "^12.1.0",
"react": "^18.3.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.3.1",

View File

@ -12,7 +12,7 @@ export type AccessTypeSelectProps = Omit<
};
const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
const { initialized, accesses, fetchAccesses } = useAccessStore();
const { accesses, loadedAtOnce, fetchAccesses } = useAccessStore();
useEffect(() => {
fetchAccesses();
}, [fetchAccesses]);
@ -64,7 +64,7 @@ const AccessSelect = ({ filter, ...props }: AccessTypeSelectProps) => {
return <Typography.Text type="secondary">{props.placeholder}</Typography.Text>;
}}
loading={!initialized}
loading={!loadedAtOnce}
options={options}
optionFilterProp="label"
optionLabelProp={undefined}

View File

@ -70,7 +70,7 @@ export type NotifyChannelsProps = {
const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannelsProps) => {
const { t, i18n } = useTranslation();
const { initialized, channels, setChannel, fetchChannels } = useNotifyChannelStore();
const { channels, loadedAtOnce, setChannel, fetchChannels } = useNotifyChannelStore();
useEffect(() => {
fetchChannels();
}, [fetchChannels]);
@ -105,7 +105,7 @@ const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannels
return (
<div className={className} style={style}>
{!initialized ? (
{!loadedAtOnce ? (
<Skeleton active />
) : (
<Collapse className={classNames?.collapse} style={styles?.collapse} accordion={true} bordered={false} items={channelCollapseItems} />

View File

@ -3,8 +3,8 @@ import { Plus } from "lucide-react";
import { BrandNodeProps, NodeProps } from "./types";
import { newWorkflowNode, workflowNodeDropdownList, WorkflowNodeType } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow";
import {
DropdownMenu,
DropdownMenuContent,
@ -21,12 +21,8 @@ import DropdownMenuItemIcon from "./DropdownMenuItemIcon";
import Show from "../Show";
import { useTranslation } from "react-i18next";
const selectState = (state: WorkflowState) => ({
addNode: state.addNode,
});
const AddNode = ({ data }: NodeProps | BrandNodeProps) => {
const { addNode } = useWorkflowStore(useShallow(selectState));
const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
const { t } = useTranslation();
const handleTypeSelected = (type: WorkflowNodeType, provider?: string) => {

View File

@ -13,23 +13,20 @@ import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrig
import AccessEditModal from "@/components/access/AccessEditModal";
import EmailsEdit from "@/components/certimate/EmailsEdit";
import StringList from "@/components/certimate/StringList";
import { accessProvidersMap } from "@/domain/access";
import { useZustandShallowSelector } from "@/hooks";
import { useAccessStore } from "@/stores/access";
import { useContactStore } from "@/stores/contact";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { usePanel } from "./PanelProvider";
type ApplyFormProps = {
data: WorkflowNode;
};
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
});
const ApplyForm = ({ data }: ApplyFormProps) => {
const { updateNode } = useWorkflowStore(useShallow(selectState));
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
const { accesses } = useAccessStore();
const { emails, fetchEmails } = useContactStore();

View File

@ -4,15 +4,12 @@ import { WorkflowBranchNode, WorkflowNode } from "@/domain/workflow";
import NodeRender from "./NodeRender";
import { memo } from "react";
import { BrandNodeProps } from "./types";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { useTranslation } from "react-i18next";
const selectState = (state: WorkflowState) => ({
addBranch: state.addBranch,
});
const BranchNode = memo(({ data }: BrandNodeProps) => {
const { addBranch } = useWorkflowStore(useShallow(selectState));
const { addBranch } = useWorkflowStore(useZustandShallowSelector(["addBranch"]));
const { t } = useTranslation();

View File

@ -1,16 +1,12 @@
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useWorkflowStore } from "@/stores/workflow";
import AddNode from "./AddNode";
import { NodeProps } from "./types";
import { useShallow } from "zustand/shallow";
import { useZustandShallowSelector } from "@/hooks";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Ellipsis, Trash2 } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
removeBranch: state.removeBranch,
});
const ConditionNode = ({ data, branchId, branchIndex }: NodeProps) => {
const { updateNode, removeBranch } = useWorkflowStore(useShallow(selectState));
const { updateNode, removeBranch } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeBranch"]));
const handleNameBlur = (e: React.FocusEvent<HTMLDivElement>) => {
updateNode({ ...data, name: e.target.innerText });
};

View File

@ -6,8 +6,8 @@ import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import { DeployFormProps } from "./DeployForm";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@ -18,13 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToAliyunALB = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
@ -19,12 +19,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToAliyunCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -6,8 +6,8 @@ import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import { DeployFormProps } from "./DeployForm";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
@ -18,13 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToAliyunCLB = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -6,21 +6,16 @@ import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import { DeployFormProps } from "./DeployForm";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
import { Button } from "../ui/button";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToAliyunNLB = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,25 +7,19 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToAliyunOSS = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToBaiduCloudCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToByteplusCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
@ -19,12 +19,8 @@ import AccessSelect from "./AccessSelect";
import { Plus } from "lucide-react";
import AccessEditModal from "../access/AccessEditModal";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToDogeCloudCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
@ -20,12 +20,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToHuaweiCloudCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
@ -19,12 +19,8 @@ import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
import AccessSelect from "./AccessSelect";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToHuaweiCloudELB = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
@ -19,12 +19,8 @@ import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
import AccessSelect from "./AccessSelect";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToKubernetesSecret = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";
import { Button } from "../ui/button";
import { DeployFormProps } from "./DeployForm";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { useEffect, useState } from "react";
import i18n from "@/i18n";
@ -19,11 +19,6 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const t = i18n.t;
const formSchema = z
@ -75,7 +70,7 @@ const formSchema = z
});
const DeployToLocal = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
@ -19,12 +19,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToQiniuCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,8 +7,8 @@ import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";
import { Button } from "../ui/button";
import { DeployFormProps } from "./DeployForm";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { useEffect, useState } from "react";
import i18n from "@/i18n";
@ -18,11 +18,6 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const t = i18n.t;
const formSchema = z
@ -71,7 +66,7 @@ const formSchema = z
});
const DeployToSSH = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToTencentCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -21,12 +20,8 @@ import { Plus } from "lucide-react";
type TencentResourceType = "ssl-deploy" | "loadbalancer" | "listener" | "ruledomain";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToTencentCLB = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessEditModal from "../access/AccessEditModal";
import AccessSelect from "./AccessSelect";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToTencentCOS = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToTencentTEO = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToVolcengineCDN = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -7,11 +7,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,12 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToVolcengineLive = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -6,11 +6,10 @@ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { Button } from "../ui/button";
import { useEffect, useState } from "react";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../ui/select";
import { SelectLabel } from "@radix-ui/react-select";
@ -19,17 +18,12 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const KVTypeSchema = z.object({
key: z.string(),
value: z.string(),
});
const DeployToWebhook = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState));
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -1,7 +1,7 @@
import { WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
import AddNode from "./AddNode";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Ellipsis, Trash2 } from "lucide-react";
import { usePanel } from "./PanelProvider";
@ -17,12 +17,8 @@ type NodeProps = {
const i18nPrefix = "workflow.node";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
removeNode: state.removeNode,
});
const Node = ({ data }: NodeProps) => {
const { updateNode, removeNode } = useWorkflowStore(useShallow(selectState));
const { updateNode, removeNode } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeNode"]));
const handleNameBlur = (e: React.FocusEvent<HTMLDivElement>) => {
updateNode({ ...data, name: e.target.innerText });
};

View File

@ -5,8 +5,8 @@ import { z } from "zod";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger } from "../ui/select";
import { Input } from "../ui/input";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider";
import { useTranslation } from "react-i18next";
import { Button } from "../ui/button";
@ -21,9 +21,6 @@ type NotifyFormProps = {
data: WorkflowNode;
};
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
});
type ChannelName = {
key: string;
label: string;
@ -31,7 +28,7 @@ type ChannelName = {
const i18nPrefix = "workflow.node.notify.form";
const NotifyForm = ({ data }: NotifyFormProps) => {
const { updateNode } = useWorkflowStore(useShallow(selectState));
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();
const { channels: supportedChannels, fetchChannels } = useNotifyChannelStore();

View File

@ -5,12 +5,12 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { Radio } from "antd";
import { parseExpression } from "cron-parser";
import { z } from "zod";
import { useShallow } from "zustand/shallow";
import { Button } from "../ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
import { Input } from "../ui/input";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { useWorkflowStore } from "@/stores/workflow";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { usePanel } from "./PanelProvider";
import { RadioChangeEvent } from "antd/lib";
@ -41,11 +41,8 @@ type StartFormProps = {
const i18nPrefix = "workflow.node.start.form";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
});
const StartForm = ({ data }: StartFormProps) => {
const { updateNode } = useWorkflowStore(useShallow(selectState));
const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
const { hidePanel } = usePanel();
const { t } = useTranslation();

View File

@ -1,7 +1,7 @@
import { z } from "zod";
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { useWorkflowStore } from "@/stores/workflow";
import { useZustandShallowSelector } from "@/hooks";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
@ -20,12 +20,8 @@ const formSchema = z.object({
description: z.string(),
});
const selectState = (state: WorkflowState) => ({
setBaseInfo: state.setBaseInfo,
workflow: state.workflow,
});
const WorkflowNameBaseInfoDialog = ({ trigger }: WorkflowNameEditDialogProps) => {
const { setBaseInfo, workflow } = useWorkflowStore(useShallow(selectState));
const { setBaseInfo, workflow } = useWorkflowStore(useZustandShallowSelector(["setBaseInfo", "workflow"]));
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),

View File

@ -3,7 +3,7 @@ import { list as logs } from "@/repository/workflowRunLog";
import { ColumnDef } from "@tanstack/react-table";
import { useState } from "react";
import { DataTable } from "./DataTable";
import { useSearchParams } from "react-router-dom";
import { useParams } from "react-router-dom";
import { Check, X } from "lucide-react";
import WorkflowLogDetail from "./WorkflowLogDetail";
import { useTranslation } from "react-i18next";
@ -12,8 +12,7 @@ const WorkflowLog = () => {
const [data, setData] = useState<WorkflowRunLog[]>([]);
const [pageCount, setPageCount] = useState<number>(0);
const [searchParams] = useSearchParams();
const id = searchParams.get("id");
const { id } = useParams();
const { t } = useTranslation();

View File

@ -1,3 +1,4 @@
import useBrowserTheme from "./useBrowserTheme";
import useZustandShallowSelector from "./useZustandShallowSelector";
export { useBrowserTheme };
export { useBrowserTheme, useZustandShallowSelector };

View File

@ -1,5 +1,5 @@
import { useTheme } from "ahooks";
export default () => {
export default function () {
return useTheme({ localStorageKey: "certimate-ui-theme" });
};
}

View File

@ -0,0 +1,18 @@
import { pick, isArray } from "radash";
import { useRef } from "react";
import { shallow } from "zustand/shallow";
type MaybeMany<T> = T | readonly T[];
export default function <T extends object, TKeys extends keyof T>(paths: MaybeMany<TKeys>): (state: T) => Pick<T, TKeys> {
const prev = useRef<Pick<T, TKeys>>({} as Pick<T, TKeys>);
return (state: T) => {
if (state) {
const next = pick(state, isArray(paths) ? paths : [paths]);
return shallow(prev.current, next) ? prev.current : (prev.current = next);
}
return prev.current;
};
}

View File

@ -18,7 +18,7 @@ const AccessList = () => {
const [modalApi, ModelContextHolder] = Modal.useModal();
const [notificationApi, NotificationContextHolder] = notification.useNotification();
const { initialized, accesses, fetchAccesses, deleteAccess } = useAccessStore();
const { accesses, loadedAtOnce, fetchAccesses, deleteAccess } = useAccessStore();
const tableColumns: TableProps<AccessModel>["columns"] = [
{
@ -181,7 +181,7 @@ const AccessList = () => {
<Table<AccessModel>
columns={tableColumns}
dataSource={tableData}
loading={!initialized || loading}
loading={!loadedAtOnce || loading}
locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t("access.nodata")} />,
}}

View File

@ -120,7 +120,7 @@ const CertificateList = () => {
type="secondary"
ellipsis
onClick={() => {
navigate(`/workflows/detail?id=${workflowId}`);
navigate(`/workflows/${workflowId}`);
}}
>
{record.expand?.workflow?.name ?? ""}

View File

@ -8,7 +8,7 @@ import { useNotifyChannelStore } from "@/stores/notify";
const SettingsNotification = () => {
const { t } = useTranslation();
const { initialized } = useNotifyChannelStore();
const { loadedAtOnce } = useNotifyChannelStore();
return (
<div>
@ -20,7 +20,7 @@ const SettingsNotification = () => {
<Divider />
<Card className="shadow" styles={{ body: initialized ? { padding: 0 } : {} }} title={t("settings.notification.channels.card.title")}>
<Card className="shadow" styles={{ body: loadedAtOnce ? { padding: 0 } : {} }} title={t("settings.notification.channels.card.title")}>
<NotifyChannels classNames={{ form: "md:max-w-[40rem]" }} />
</Card>
</div>

View File

@ -1,8 +1,7 @@
import { useEffect, useMemo, useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { Button, message, notification, Switch } from "antd";
import { useShallow } from "zustand/shallow";
import { ArrowLeft as ArrowLeftIcon } from "lucide-react";
import Show from "@/components/Show";
@ -12,20 +11,14 @@ import WorkflowBaseInfoEditDialog from "@/components/workflow/WorkflowBaseInfoEd
import WorkflowLog from "@/components/workflow/WorkflowLog";
import WorkflowProvider from "@/components/workflow/WorkflowProvider";
import { cn } from "@/components/ui/utils";
import { useZustandShallowSelector } from "@/hooks";
import { allNodesValidated, WorkflowNode } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow";
import { useWorkflowStore } from "@/stores/workflow";
import { run as runWorkflow } from "@/api/workflow";
const selectState = (state: WorkflowState) => ({
workflow: state.workflow,
init: state.init,
switchEnable: state.switchEnable,
save: state.save,
});
const WorkflowDetail = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { id } = useParams();
const { t } = useTranslation();
@ -33,11 +26,10 @@ const WorkflowDetail = () => {
const [_, NotificationContextHolder] = notification.useNotification();
// 3. 使用正确的选择器和 shallow 比较
const { workflow, init, switchEnable, save } = useWorkflowStore(useShallow(selectState));
const { workflow, init, switchEnable, save } = useWorkflowStore(useZustandShallowSelector(["workflow", "init", "switchEnable", "save"]));
// 从 url 中获取 workflowId
const [locId, setLocId] = useState<string>("");
const id = searchParams.get("id");
const [tab, setTab] = useState("workflow");
@ -78,7 +70,7 @@ const WorkflowDetail = () => {
}
switchEnable();
if (!locId) {
navigate(`/workflows/detail?id=${workflow.id}`);
navigate(`/workflows/${workflow.id}`);
}
};
@ -89,7 +81,7 @@ const WorkflowDetail = () => {
}
save();
if (!locId) {
navigate(`/workflows/detail?id=${workflow.id}`);
navigate(`/workflows/${workflow.id}`);
}
};

View File

@ -180,7 +180,7 @@ const WorkflowList = () => {
type="link"
icon={<PencilIcon size={16} />}
onClick={() => {
navigate(`/workflows/detail?id=${record.id}`);
navigate(`/workflows/${record.id}`);
}}
/>
</Tooltip>
@ -276,7 +276,7 @@ const WorkflowList = () => {
};
const handleCreateClick = () => {
navigate("/workflows/detail");
navigate("/workflows/");
};
return (

View File

@ -23,5 +23,11 @@ export const save = async (record: MaybeModelRecord<AccessModel>) => {
export const remove = async (record: MaybeModelRecordWithId<AccessModel>) => {
record = { ...record, deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") };
// TODO: 仅为兼容旧版本,后续迭代时删除
if ("configType" in record && record.configType === "httpreq") record.configType = "acmehttpreq";
if ("configType" in record && record.configType === "tencent") record.configType = "tencentcloud";
if ("configType" in record && record.configType === "pdns") record.configType = "powerdns";
await getPocketBase().collection(COLLECTION_NAME).update<AccessModel>(record.id!, record);
};

View File

@ -36,3 +36,9 @@ export const list = async (request: ListCertificateRequest) => {
return pb.collection(COLLECTION_NAME).getList<CertificateModel>(page, perPage, options);
};
export const remove = async (record: MaybeModelRecordWithId<CertificateModel>) => {
record = { ...record, deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") };
await getPocketBase().collection(COLLECTION_NAME).update<CertificateModel>(record.id!, record);
};

View File

@ -17,7 +17,11 @@ export const list = async (request: ListWorkflowRequest) => {
const page = request.page || 1;
const perPage = request.perPage || 10;
const options: RecordListOptions = { requestKey: null, sort: "-created" };
const options: RecordListOptions = {
sort: "-created",
requestKey: null,
};
if (request.enabled != null) {
options.filter = pb.filter("enabled={:enabled}", { enabled: request.enabled });
}

View File

@ -1,6 +1,8 @@
import { type WorkflowRunLog } from "@/domain/workflow";
import { getPocketBase } from "./pocketbase";
const COLLECTION_NAME = "workflow_run_log";
export type ListWorkflowLogsRequest = {
id: string;
page?: number;
@ -12,7 +14,7 @@ export const list = async (request: ListWorkflowLogsRequest) => {
const perPage = request.perPage || 10;
return await getPocketBase()
.collection("workflow_run_log")
.collection(COLLECTION_NAME)
.getList<WorkflowRunLog>(page, perPage, {
filter: getPocketBase().filter("workflow={:workflowId}", { workflowId: request.id }),
sort: "-created",

View File

@ -36,7 +36,7 @@ export const router = createHashRouter([
element: <WorkflowList />,
},
{
path: "/workflows/detail",
path: "/workflows/:id",
element: <WorkflowDetail />,
},
{

View File

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

View File

@ -5,10 +5,12 @@ import { SETTINGS_NAMES, type EmailsSettingsContent, type SettingsModel } from "
import { get as getSettings, save as saveSettings } from "@/repository/settings";
export interface ContactState {
initialized: boolean;
emails: string[];
setEmails: (emails: string[]) => void;
loading: boolean;
loadedAtOnce: boolean;
fetchEmails: () => Promise<void>;
setEmails: (emails: string[]) => Promise<void>;
}
export const useContactStore = create<ContactState>((set) => {
@ -16,8 +18,9 @@ export const useContactStore = create<ContactState>((set) => {
let settings: SettingsModel<EmailsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
return {
initialized: false,
emails: [],
loading: false,
loadedAtOnce: false,
setEmails: async (emails) => {
settings ??= await getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS);
@ -32,7 +35,7 @@ export const useContactStore = create<ContactState>((set) => {
set(
produce((state: ContactState) => {
state.emails = settings.content.emails;
state.initialized = true;
state.loadedAtOnce = true;
})
);
},
@ -41,10 +44,12 @@ export const useContactStore = create<ContactState>((set) => {
fetcher ??= getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS);
try {
set({ loading: true });
settings = await fetcher;
set({ emails: settings.content.emails?.sort() ?? [], initialized: true });
set({ emails: settings.content.emails?.sort() ?? [], loadedAtOnce: true });
} finally {
fetcher = null;
set({ loading: false });
}
},
};

View File

@ -5,11 +5,13 @@ import { SETTINGS_NAMES, type NotifyChannelsSettingsContent, type SettingsModel
import { get as getSettings, save as saveSettings } from "@/repository/settings";
export interface NotifyChannelState {
initialized: boolean;
channels: NotifyChannelsSettingsContent;
setChannel: (channel: keyof NotifyChannelsSettingsContent, config: NotifyChannelsSettingsContent[keyof NotifyChannelsSettingsContent]) => void;
setChannels: (channels: NotifyChannelsSettingsContent) => void;
loading: boolean;
loadedAtOnce: boolean;
fetchChannels: () => Promise<void>;
setChannel: (channel: keyof NotifyChannelsSettingsContent, config: NotifyChannelsSettingsContent[keyof NotifyChannelsSettingsContent]) => Promise<void>;
setChannels: (channels: NotifyChannelsSettingsContent) => Promise<void>;
}
export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
@ -17,8 +19,9 @@ export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
let settings: SettingsModel<NotifyChannelsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
return {
initialized: false,
channels: {},
loading: false,
loadedAtOnce: false,
setChannel: async (channel, config) => {
settings ??= await getSettings<NotifyChannelsSettingsContent>(SETTINGS_NAMES.NOTIFY_CHANNELS);
@ -40,7 +43,7 @@ export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
set(
produce((state: NotifyChannelState) => {
state.channels = settings.content;
state.initialized = true;
state.loadedAtOnce = true;
})
);
},
@ -49,10 +52,12 @@ export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
fetcher ??= getSettings<NotifyChannelsSettingsContent>(SETTINGS_NAMES.NOTIFY_CHANNELS);
try {
set({ loading: true });
settings = await fetcher;
set({ channels: settings.content ?? {}, initialized: true });
set({ channels: settings.content ?? {}, loadedAtOnce: true });
} finally {
fetcher = null;
set({ loading: false });
}
},
};