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 return
} }
msg := buildMsg(certs) msg := buildMsg(certs)
// TODO: 空指针 Bug
if err := notify.SendToAllChannels(msg.Subject, msg.Message); err != nil { if err := notify.SendToAllChannels(msg.Subject, msg.Message); err != nil {
app.GetApp().Logger().Error("failed to send expire soon certificate", "err", err) 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", "lucide-react": "^0.469.0",
"nanoid": "^5.0.9", "nanoid": "^5.0.9",
"pocketbase": "^0.21.5", "pocketbase": "^0.21.5",
"radash": "^12.1.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-copy-to-clipboard": "^5.1.0", "react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18.3.1", "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": { "node_modules/rc-cascader": {
"version": "3.30.0", "version": "3.30.0",
"resolved": "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.30.0.tgz", "resolved": "https://registry.npmmirror.com/rc-cascader/-/rc-cascader-3.30.0.tgz",

View File

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

View File

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

View File

@ -70,7 +70,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 { initialized, channels, setChannel, fetchChannels } = useNotifyChannelStore(); const { channels, loadedAtOnce, setChannel, fetchChannels } = useNotifyChannelStore();
useEffect(() => { useEffect(() => {
fetchChannels(); fetchChannels();
}, [fetchChannels]); }, [fetchChannels]);
@ -105,7 +105,7 @@ const NotifyChannels = ({ className, classNames, style, styles }: NotifyChannels
return ( return (
<div className={className} style={style}> <div className={className} style={style}>
{!initialized ? ( {!loadedAtOnce ? (
<Skeleton active /> <Skeleton active />
) : ( ) : (
<Collapse className={classNames?.collapse} style={styles?.collapse} accordion={true} bordered={false} items={channelCollapseItems} /> <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 { BrandNodeProps, NodeProps } from "./types";
import { newWorkflowNode, workflowNodeDropdownList, WorkflowNodeType } from "@/domain/workflow"; import { newWorkflowNode, workflowNodeDropdownList, WorkflowNodeType } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow"; import { useZustandShallowSelector } from "@/hooks";
import { useShallow } from "zustand/shallow"; import { useWorkflowStore } from "@/stores/workflow";
import { import {
DropdownMenu, DropdownMenu,
DropdownMenuContent, DropdownMenuContent,
@ -21,12 +21,8 @@ import DropdownMenuItemIcon from "./DropdownMenuItemIcon";
import Show from "../Show"; import Show from "../Show";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
const selectState = (state: WorkflowState) => ({
addNode: state.addNode,
});
const AddNode = ({ data }: NodeProps | BrandNodeProps) => { const AddNode = ({ data }: NodeProps | BrandNodeProps) => {
const { addNode } = useWorkflowStore(useShallow(selectState)); const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
const { t } = useTranslation(); const { t } = useTranslation();
const handleTypeSelected = (type: WorkflowNodeType, provider?: string) => { 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 AccessEditModal from "@/components/access/AccessEditModal";
import EmailsEdit from "@/components/certimate/EmailsEdit"; import EmailsEdit from "@/components/certimate/EmailsEdit";
import StringList from "@/components/certimate/StringList"; import StringList from "@/components/certimate/StringList";
import { accessProvidersMap } from "@/domain/access"; import { accessProvidersMap } from "@/domain/access";
import { useZustandShallowSelector } from "@/hooks";
import { useAccessStore } from "@/stores/access"; import { useAccessStore } from "@/stores/access";
import { useContactStore } from "@/stores/contact"; import { useContactStore } from "@/stores/contact";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow"; import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useShallow } from "zustand/shallow";
import { usePanel } from "./PanelProvider"; import { usePanel } from "./PanelProvider";
type ApplyFormProps = { type ApplyFormProps = {
data: WorkflowNode; data: WorkflowNode;
}; };
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
});
const ApplyForm = ({ data }: ApplyFormProps) => { const ApplyForm = ({ data }: ApplyFormProps) => {
const { updateNode } = useWorkflowStore(useShallow(selectState)); const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
const { accesses } = useAccessStore(); const { accesses } = useAccessStore();
const { emails, fetchEmails } = useContactStore(); const { emails, fetchEmails } = useContactStore();

View File

@ -4,15 +4,12 @@ import { WorkflowBranchNode, WorkflowNode } from "@/domain/workflow";
import NodeRender from "./NodeRender"; import NodeRender from "./NodeRender";
import { memo } from "react"; import { memo } from "react";
import { BrandNodeProps } from "./types"; import { BrandNodeProps } from "./types";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useShallow } from "zustand/shallow"; import { useZustandShallowSelector } from "@/hooks";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
const selectState = (state: WorkflowState) => ({
addBranch: state.addBranch,
});
const BranchNode = memo(({ data }: BrandNodeProps) => { const BranchNode = memo(({ data }: BrandNodeProps) => {
const { addBranch } = useWorkflowStore(useShallow(selectState)); const { addBranch } = useWorkflowStore(useZustandShallowSelector(["addBranch"]));
const { t } = useTranslation(); 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 AddNode from "./AddNode";
import { NodeProps } from "./types"; import { NodeProps } from "./types";
import { useShallow } from "zustand/shallow"; import { useZustandShallowSelector } from "@/hooks";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Ellipsis, Trash2 } from "lucide-react"; import { Ellipsis, Trash2 } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
removeBranch: state.removeBranch,
});
const ConditionNode = ({ data, branchId, branchIndex }: NodeProps) => { 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>) => { const handleNameBlur = (e: React.FocusEvent<HTMLDivElement>) => {
updateNode({ ...data, name: e.target.innerText }); 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 { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
import { DeployFormProps } from "./DeployForm"; import { DeployFormProps } from "./DeployForm";
import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow"; import { WorkflowNode, WorkflowNodeConfig } from "@/domain/workflow";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useShallow } from "zustand/shallow"; import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider"; import { usePanel } from "./PanelProvider";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
@ -18,13 +18,8 @@ import AccessSelect from "./AccessSelect";
import AccessEditModal from "../access/AccessEditModal"; import AccessEditModal from "../access/AccessEditModal";
import { Plus } from "lucide-react"; import { Plus } from "lucide-react";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
getWorkflowOuptutBeforeId: state.getWorkflowOuptutBeforeId,
});
const DeployToAliyunALB = ({ data }: DeployFormProps) => { const DeployToAliyunALB = ({ data }: DeployFormProps) => {
const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useShallow(selectState)); const { updateNode, getWorkflowOuptutBeforeId } = useWorkflowStore(useZustandShallowSelector(["updateNode", "getWorkflowOuptutBeforeId"]));
const { hidePanel } = usePanel(); const { hidePanel } = usePanel();
const { t } = useTranslation(); const { t } = useTranslation();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import { WorkflowNode, WorkflowNodeType } from "@/domain/workflow"; import { WorkflowNode, WorkflowNodeType } from "@/domain/workflow";
import AddNode from "./AddNode"; import AddNode from "./AddNode";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useShallow } from "zustand/shallow"; import { useZustandShallowSelector } from "@/hooks";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/dropdown-menu";
import { Ellipsis, Trash2 } from "lucide-react"; import { Ellipsis, Trash2 } from "lucide-react";
import { usePanel } from "./PanelProvider"; import { usePanel } from "./PanelProvider";
@ -17,12 +17,8 @@ type NodeProps = {
const i18nPrefix = "workflow.node"; const i18nPrefix = "workflow.node";
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
removeNode: state.removeNode,
});
const Node = ({ data }: NodeProps) => { const Node = ({ data }: NodeProps) => {
const { updateNode, removeNode } = useWorkflowStore(useShallow(selectState)); const { updateNode, removeNode } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeNode"]));
const handleNameBlur = (e: React.FocusEvent<HTMLDivElement>) => { const handleNameBlur = (e: React.FocusEvent<HTMLDivElement>) => {
updateNode({ ...data, name: e.target.innerText }); 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 { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../ui/form";
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger } from "../ui/select"; import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger } from "../ui/select";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { useWorkflowStore, WorkflowState } from "@/stores/workflow"; import { useWorkflowStore } from "@/stores/workflow";
import { useShallow } from "zustand/shallow"; import { useZustandShallowSelector } from "@/hooks";
import { usePanel } from "./PanelProvider"; import { usePanel } from "./PanelProvider";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
@ -21,9 +21,6 @@ type NotifyFormProps = {
data: WorkflowNode; data: WorkflowNode;
}; };
const selectState = (state: WorkflowState) => ({
updateNode: state.updateNode,
});
type ChannelName = { type ChannelName = {
key: string; key: string;
label: string; label: string;
@ -31,7 +28,7 @@ type ChannelName = {
const i18nPrefix = "workflow.node.notify.form"; const i18nPrefix = "workflow.node.notify.form";
const NotifyForm = ({ data }: NotifyFormProps) => { const NotifyForm = ({ data }: NotifyFormProps) => {
const { updateNode } = useWorkflowStore(useShallow(selectState)); const { updateNode } = useWorkflowStore(useZustandShallowSelector(["updateNode"]));
const { hidePanel } = usePanel(); const { hidePanel } = usePanel();
const { t } = useTranslation(); const { t } = useTranslation();
const { channels: supportedChannels, fetchChannels } = useNotifyChannelStore(); const { channels: supportedChannels, fetchChannels } = useNotifyChannelStore();

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import { useTheme } from "ahooks"; import { useTheme } from "ahooks";
export default () => { export default function () {
return useTheme({ localStorageKey: "certimate-ui-theme" }); 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 [modalApi, ModelContextHolder] = Modal.useModal();
const [notificationApi, NotificationContextHolder] = notification.useNotification(); const [notificationApi, NotificationContextHolder] = notification.useNotification();
const { initialized, accesses, fetchAccesses, deleteAccess } = useAccessStore(); const { accesses, loadedAtOnce, fetchAccesses, deleteAccess } = useAccessStore();
const tableColumns: TableProps<AccessModel>["columns"] = [ const tableColumns: TableProps<AccessModel>["columns"] = [
{ {
@ -181,7 +181,7 @@ const AccessList = () => {
<Table<AccessModel> <Table<AccessModel>
columns={tableColumns} columns={tableColumns}
dataSource={tableData} dataSource={tableData}
loading={!initialized || loading} loading={!loadedAtOnce || loading}
locale={{ locale={{
emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t("access.nodata")} />, emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description={t("access.nodata")} />,
}} }}

View File

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

View File

@ -8,7 +8,7 @@ import { useNotifyChannelStore } from "@/stores/notify";
const SettingsNotification = () => { const SettingsNotification = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { initialized } = useNotifyChannelStore(); const { loadedAtOnce } = useNotifyChannelStore();
return ( return (
<div> <div>
@ -20,7 +20,7 @@ const SettingsNotification = () => {
<Divider /> <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]" }} /> <NotifyChannels classNames={{ form: "md:max-w-[40rem]" }} />
</Card> </Card>
</div> </div>

View File

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

View File

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

View File

@ -23,5 +23,11 @@ export const save = async (record: MaybeModelRecord<AccessModel>) => {
export const remove = async (record: MaybeModelRecordWithId<AccessModel>) => { export const remove = async (record: MaybeModelRecordWithId<AccessModel>) => {
record = { ...record, deleted: dayjs.utc().format("YYYY-MM-DD HH:mm:ss") }; 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); 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); 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 page = request.page || 1;
const perPage = request.perPage || 10; const perPage = request.perPage || 10;
const options: RecordListOptions = { requestKey: null, sort: "-created" }; const options: RecordListOptions = {
sort: "-created",
requestKey: null,
};
if (request.enabled != null) { if (request.enabled != null) {
options.filter = pb.filter("enabled={:enabled}", { enabled: request.enabled }); options.filter = pb.filter("enabled={:enabled}", { enabled: request.enabled });
} }

View File

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

View File

@ -36,7 +36,7 @@ export const router = createHashRouter([
element: <WorkflowList />, element: <WorkflowList />,
}, },
{ {
path: "/workflows/detail", path: "/workflows/:id",
element: <WorkflowDetail />, 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"; import { list as listAccess, save as saveAccess, remove as removeAccess } from "@/repository/access";
export interface AccessState { export interface AccessState {
initialized: boolean;
accesses: AccessModel[]; accesses: AccessModel[];
createAccess: (access: MaybeModelRecord<AccessModel>) => void; loading: boolean;
updateAccess: (access: MaybeModelRecordWithId<AccessModel>) => void; loadedAtOnce: boolean;
deleteAccess: (access: MaybeModelRecordWithId<AccessModel>) => void;
fetchAccesses: () => Promise<void>; 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) => { export const useAccessStore = create<AccessState>((set) => {
let fetcher: Promise<AccessModel[]> | null = null; // 防止多次重复请求 let fetcher: Promise<AccessModel[]> | null = null; // 防止多次重复请求
return { return {
initialized: false,
accesses: [], accesses: [],
loading: false,
loadedAtOnce: false,
createAccess: async (access) => { createAccess: async (access) => {
const record = await saveAccess(access); const record = await saveAccess(access);
@ -57,10 +60,12 @@ export const useAccessStore = create<AccessState>((set) => {
fetcher ??= listAccess(); fetcher ??= listAccess();
try { try {
set({ loading: true });
const accesses = await fetcher; const accesses = await fetcher;
set({ accesses: accesses ?? [], initialized: true }); set({ accesses: accesses ?? [], loadedAtOnce: true });
} finally { } finally {
fetcher = null; 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"; import { get as getSettings, save as saveSettings } from "@/repository/settings";
export interface ContactState { export interface ContactState {
initialized: boolean;
emails: string[]; emails: string[];
setEmails: (emails: string[]) => void; loading: boolean;
loadedAtOnce: boolean;
fetchEmails: () => Promise<void>; fetchEmails: () => Promise<void>;
setEmails: (emails: string[]) => Promise<void>;
} }
export const useContactStore = create<ContactState>((set) => { export const useContactStore = create<ContactState>((set) => {
@ -16,8 +18,9 @@ export const useContactStore = create<ContactState>((set) => {
let settings: SettingsModel<EmailsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用 let settings: SettingsModel<EmailsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
return { return {
initialized: false,
emails: [], emails: [],
loading: false,
loadedAtOnce: false,
setEmails: async (emails) => { setEmails: async (emails) => {
settings ??= await getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS); settings ??= await getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS);
@ -32,7 +35,7 @@ export const useContactStore = create<ContactState>((set) => {
set( set(
produce((state: ContactState) => { produce((state: ContactState) => {
state.emails = settings.content.emails; 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); fetcher ??= getSettings<EmailsSettingsContent>(SETTINGS_NAMES.EMAILS);
try { try {
set({ loading: true });
settings = await fetcher; settings = await fetcher;
set({ emails: settings.content.emails?.sort() ?? [], initialized: true }); set({ emails: settings.content.emails?.sort() ?? [], loadedAtOnce: true });
} finally { } finally {
fetcher = null; 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"; import { get as getSettings, save as saveSettings } from "@/repository/settings";
export interface NotifyChannelState { export interface NotifyChannelState {
initialized: boolean;
channels: NotifyChannelsSettingsContent; channels: NotifyChannelsSettingsContent;
setChannel: (channel: keyof NotifyChannelsSettingsContent, config: NotifyChannelsSettingsContent[keyof NotifyChannelsSettingsContent]) => void; loading: boolean;
setChannels: (channels: NotifyChannelsSettingsContent) => void; loadedAtOnce: boolean;
fetchChannels: () => Promise<void>; 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) => { export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
@ -17,8 +19,9 @@ export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
let settings: SettingsModel<NotifyChannelsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用 let settings: SettingsModel<NotifyChannelsSettingsContent>; // 记录当前设置的其他字段,保存回数据库时用
return { return {
initialized: false,
channels: {}, channels: {},
loading: false,
loadedAtOnce: false,
setChannel: async (channel, config) => { setChannel: async (channel, config) => {
settings ??= await getSettings<NotifyChannelsSettingsContent>(SETTINGS_NAMES.NOTIFY_CHANNELS); settings ??= await getSettings<NotifyChannelsSettingsContent>(SETTINGS_NAMES.NOTIFY_CHANNELS);
@ -40,7 +43,7 @@ export const useNotifyChannelStore = create<NotifyChannelState>((set, get) => {
set( set(
produce((state: NotifyChannelState) => { produce((state: NotifyChannelState) => {
state.channels = settings.content; 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); fetcher ??= getSettings<NotifyChannelsSettingsContent>(SETTINGS_NAMES.NOTIFY_CHANNELS);
try { try {
set({ loading: true });
settings = await fetcher; settings = await fetcher;
set({ channels: settings.content ?? {}, initialized: true }); set({ channels: settings.content ?? {}, loadedAtOnce: true });
} finally { } finally {
fetcher = null; fetcher = null;
set({ loading: false });
} }
}, },
}; };