diff --git a/src/components/FloatingActionBar.tsx b/src/components/FloatingActionBar.tsx index be230f1c..3eef6b65 100644 --- a/src/components/FloatingActionBar.tsx +++ b/src/components/FloatingActionBar.tsx @@ -2,6 +2,7 @@ import { useRef, useState, useEffect, useMemo, useCallback } from "react"; import { useWorkflowStore } from "@/store/workflowStore"; +import { useShallow } from "zustand/shallow"; import { NodeType } from "@/types"; import { useReactFlow } from "@xyflow/react"; import { ModelSearchDialog } from "./modals/ModelSearchDialog"; @@ -320,7 +321,21 @@ export function FloatingActionBar() { setModelSearchOpen, modelSearchOpen, modelSearchProvider, - } = useWorkflowStore(); + } = useWorkflowStore(useShallow((state) => ({ + nodes: state.nodes, + isRunning: state.isRunning, + currentNodeIds: state.currentNodeIds, + executeWorkflow: state.executeWorkflow, + regenerateNode: state.regenerateNode, + executeSelectedNodes: state.executeSelectedNodes, + stopWorkflow: state.stopWorkflow, + validateWorkflow: state.validateWorkflow, + edgeStyle: state.edgeStyle, + setEdgeStyle: state.setEdgeStyle, + setModelSearchOpen: state.setModelSearchOpen, + modelSearchOpen: state.modelSearchOpen, + modelSearchProvider: state.modelSearchProvider, + }))); // Get display text for running nodes const runningNodeCount = currentNodeIds.length; diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c02a8f86..baf1ebda 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -2,6 +2,7 @@ import { useState, useRef, useMemo, useCallback } from "react"; import { useWorkflowStore, WorkflowFile } from "@/store/workflowStore"; +import { useShallow } from "zustand/shallow"; import { ProjectSetupModal } from "./ProjectSetupModal"; import { CostIndicator } from "./CostIndicator"; import { KeyboardShortcutsDialog } from "./KeyboardShortcutsDialog"; @@ -73,7 +74,22 @@ export function Header() { shortcutsDialogOpen, setShortcutsDialogOpen, setShowQuickstart, - } = useWorkflowStore(); + } = useWorkflowStore(useShallow((state) => ({ + workflowName: state.workflowName, + workflowId: state.workflowId, + saveDirectoryPath: state.saveDirectoryPath, + hasUnsavedChanges: state.hasUnsavedChanges, + lastSavedAt: state.lastSavedAt, + isSaving: state.isSaving, + setWorkflowMetadata: state.setWorkflowMetadata, + saveToFile: state.saveToFile, + loadWorkflow: state.loadWorkflow, + previousWorkflowSnapshot: state.previousWorkflowSnapshot, + revertToSnapshot: state.revertToSnapshot, + shortcutsDialogOpen: state.shortcutsDialogOpen, + setShortcutsDialogOpen: state.setShortcutsDialogOpen, + setShowQuickstart: state.setShowQuickstart, + }))); const [showProjectModal, setShowProjectModal] = useState(false); const [projectModalMode, setProjectModalMode] = useState<"new" | "settings">("new"); diff --git a/src/components/WorkflowCanvas.tsx b/src/components/WorkflowCanvas.tsx index 1a5103b8..ad7d5717 100644 --- a/src/components/WorkflowCanvas.tsx +++ b/src/components/WorkflowCanvas.tsx @@ -1283,7 +1283,10 @@ export function WorkflowCanvas() { }, []); // Get copy/paste functions and clipboard from store - const { copySelectedNodes, pasteNodes, clearClipboard, clipboard } = useWorkflowStore(); + const copySelectedNodes = useWorkflowStore((state) => state.copySelectedNodes); + const pasteNodes = useWorkflowStore((state) => state.pasteNodes); + const clearClipboard = useWorkflowStore((state) => state.clearClipboard); + const clipboard = useWorkflowStore((state) => state.clipboard); // Add non-passive wheel listener to handle zoom/pan and prevent browser navigation // This replaces the onWheel prop which is passive by default and can't preventDefault