diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 9b13576c64..c57a7a984b 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -208,7 +208,8 @@ const reactFlowStyles = [ '[&_.react-flow__node-subflowNode.selected]:!shadow-none', ].join(' ') const reactFlowFitViewOptions = { padding: 0.6, maxZoom: 1.0 } as const -const embeddedFitViewOptions = { padding: 0.15, maxZoom: 0.85, minZoom: 0.35 } as const +const embeddedFitViewOptions = { padding: 0.15, maxZoom: 0.85, minZoom: 0.1 } as const +const embeddedResizeFitViewOptions = { ...embeddedFitViewOptions, duration: 0 } as const const reactFlowProOptions = { hideAttribution: true } as const /** @@ -244,7 +245,10 @@ const WorkflowContent = React.memo( const [potentialParentId, setPotentialParentId] = useState(null) const [selectedEdges, setSelectedEdges] = useState(new Map()) const [isErrorConnectionDrag, setIsErrorConnectionDrag] = useState(false) + const canvasContainerRef = useRef(null) const selectedIdsRef = useRef(null) + const embeddedFitFrameRef = useRef(null) + const hasCompletedInitialEmbeddedFitRef = useRef(false) const canvasMode = useCanvasModeStore((state) => state.mode) const isHandMode = embedded ? true : canvasMode === 'hand' const { handleCanvasMouseDown, selectionProps } = useShiftSelectionLock({ isHandMode }) @@ -373,6 +377,34 @@ const WorkflowContent = React.memo( ] ) + const scheduleEmbeddedFit = useCallback(() => { + if (!embedded || !isWorkflowReady) return + + if (embeddedFitFrameRef.current !== null) { + cancelAnimationFrame(embeddedFitFrameRef.current) + } + + embeddedFitFrameRef.current = requestAnimationFrame(() => { + embeddedFitFrameRef.current = null + + const container = canvasContainerRef.current + if (!container) return + + const rect = container.getBoundingClientRect() + if (rect.width <= 0 || rect.height <= 0) return + + const nodes = reactFlowInstance.getNodes() + if (nodes.length > 0) { + void reactFlowInstance.fitView(embeddedResizeFitViewOptions) + } + + if (!hasCompletedInitialEmbeddedFitRef.current) { + hasCompletedInitialEmbeddedFitRef.current = true + setIsCanvasReady(true) + } + }) + }, [embedded, isWorkflowReady, reactFlowInstance]) + const { getNodeDepth, getNodeAbsolutePosition, @@ -3750,10 +3782,46 @@ const WorkflowContent = React.memo( activeWorkflowId, ]) + useEffect(() => { + if (!embedded || !isWorkflowReady) { + return + } + + const container = canvasContainerRef.current + if (!container) { + return + } + + scheduleEmbeddedFit() + + const resizeObserver = new ResizeObserver(() => { + scheduleEmbeddedFit() + }) + + resizeObserver.observe(container) + + return () => { + resizeObserver.disconnect() + + if (embeddedFitFrameRef.current !== null) { + cancelAnimationFrame(embeddedFitFrameRef.current) + embeddedFitFrameRef.current = null + } + } + }, [embedded, isWorkflowReady, scheduleEmbeddedFit]) + + useEffect(() => { + if (!embedded || !isWorkflowReady) { + return + } + + scheduleEmbeddedFit() + }, [blocksStructureHash, embedded, isWorkflowReady, scheduleEmbeddedFit]) + return (
-
+
{!isWorkflowReady && (
{ + if (embedded) { + return + } + requestAnimationFrame(() => { - instance.fitView(embedded ? embeddedFitViewOptions : reactFlowFitViewOptions) + instance.fitView(reactFlowFitViewOptions) setIsCanvasReady(true) }) }}