From 201228ce2da7382d80679787ce308a0cba17dbcc Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 17 Mar 2026 06:33:51 -0700 Subject: [PATCH 1/2] fix(embedded): autolayout viewport calculation for resource view --- .../w/[workflowId]/hooks/use-auto-layout.ts | 5 +- .../[workspaceId]/w/[workflowId]/workflow.tsx | 8 +++- apps/sim/hooks/use-canvas-viewport.ts | 48 ++++++++++++++----- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-auto-layout.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-auto-layout.ts index 3bcb0676bba..6dfc29760e6 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-auto-layout.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-auto-layout.ts @@ -4,6 +4,7 @@ import { useReactFlow } from 'reactflow' import type { AutoLayoutOptions } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/auto-layout-utils' import { applyAutoLayoutAndUpdateStore as applyAutoLayoutStandalone } from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/auto-layout-utils' import { useSnapToGridSize } from '@/hooks/queries/general-settings' +import type { CanvasViewportOptions } from '@/hooks/use-canvas-viewport' import { useCanvasViewport } from '@/hooks/use-canvas-viewport' export type { AutoLayoutOptions } @@ -18,9 +19,9 @@ const logger = createLogger('useAutoLayout') * * Note: This hook requires a ReactFlowProvider ancestor. */ -export function useAutoLayout(workflowId: string | null) { +export function useAutoLayout(workflowId: string | null, options?: CanvasViewportOptions) { const reactFlowInstance = useReactFlow() - const { fitViewToBounds } = useCanvasViewport(reactFlowInstance) + const { fitViewToBounds } = useCanvasViewport(reactFlowInstance, options) const snapToGridSize = useSnapToGridSize() const applyAutoLayoutAndUpdateStore = useCallback( diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index c57a7a984be..3a7e91870a8 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -264,7 +264,9 @@ const WorkflowContent = React.memo( const router = useRouter() const reactFlowInstance = useReactFlow() const { screenToFlowPosition, getNodes, setNodes, getIntersectingNodes } = reactFlowInstance - const { fitViewToBounds, getViewportCenter } = useCanvasViewport(reactFlowInstance) + const { fitViewToBounds, getViewportCenter } = useCanvasViewport(reactFlowInstance, { + embedded, + }) const { emitCursorUpdate } = useSocket() useDynamicHandleRefresh() @@ -473,7 +475,9 @@ const WorkflowContent = React.memo( [] ) - const { handleAutoLayout: autoLayoutWithFitView } = useAutoLayout(activeWorkflowId || null) + const { handleAutoLayout: autoLayoutWithFitView } = useAutoLayout(activeWorkflowId || null, { + embedded, + }) const isWorkflowEmpty = useMemo(() => Object.keys(blocks).length === 0, [blocks]) diff --git a/apps/sim/hooks/use-canvas-viewport.ts b/apps/sim/hooks/use-canvas-viewport.ts index a3ff474bfd0..44d3739fd3a 100644 --- a/apps/sim/hooks/use-canvas-viewport.ts +++ b/apps/sim/hooks/use-canvas-viewport.ts @@ -1,4 +1,4 @@ -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import type { Node, ReactFlowInstance } from 'reactflow' import { BLOCK_DIMENSIONS } from '@/lib/workflows/blocks/block-dimensions' @@ -10,18 +10,34 @@ interface VisibleBounds { offsetBottom: number } +export interface CanvasViewportOptions { + embedded?: boolean +} + /** * Gets the visible canvas bounds accounting for sidebar, terminal, and panel overlays. - * Works correctly regardless of whether the ReactFlow container extends under the sidebar or not. + * When embedded, uses the container rect directly since CSS variable offsets don't apply. */ -function getVisibleCanvasBounds(): VisibleBounds { +function getVisibleCanvasBounds(options?: CanvasViewportOptions): VisibleBounds { + const flowContainer = document.querySelector('.react-flow') + + if (options?.embedded && flowContainer) { + const rect = flowContainer.getBoundingClientRect() + return { + width: rect.width, + height: rect.height, + offsetLeft: 0, + offsetRight: 0, + offsetBottom: 0, + } + } + const style = getComputedStyle(document.documentElement) const sidebarWidth = Number.parseInt(style.getPropertyValue('--sidebar-width') || '0', 10) const terminalHeight = Number.parseInt(style.getPropertyValue('--terminal-height') || '0', 10) const panelWidth = Number.parseInt(style.getPropertyValue('--panel-width') || '0', 10) - const flowContainer = document.querySelector('.react-flow') if (!flowContainer) { return { width: window.innerWidth - sidebarWidth - panelWidth, @@ -56,8 +72,8 @@ function getVisibleCanvasBounds(): VisibleBounds { /** * Gets the center of the visible canvas in screen coordinates. */ -function getVisibleCanvasCenter(): { x: number; y: number } { - const bounds = getVisibleCanvasBounds() +function getVisibleCanvasCenter(options?: CanvasViewportOptions): { x: number; y: number } { + const bounds = getVisibleCanvasBounds(options) const flowContainer = document.querySelector('.react-flow') const rect = flowContainer?.getBoundingClientRect() @@ -81,7 +97,16 @@ interface FitViewToBoundsOptions { /** * Hook providing canvas viewport utilities that account for sidebar, panel, and terminal overlays. */ -export function useCanvasViewport(reactFlowInstance: ReactFlowInstance | null) { +export function useCanvasViewport( + reactFlowInstance: ReactFlowInstance | null, + viewportOptions?: CanvasViewportOptions +) { + const embedded = viewportOptions?.embedded + const stableOptions = useMemo( + () => (embedded ? { embedded } : undefined), + [embedded] + ) + /** * Gets the center of the visible canvas in flow coordinates. */ @@ -90,9 +115,9 @@ export function useCanvasViewport(reactFlowInstance: ReactFlowInstance | null) { return { x: 0, y: 0 } } - const center = getVisibleCanvasCenter() + const center = getVisibleCanvasCenter(stableOptions) return reactFlowInstance.screenToFlowPosition(center) - }, [reactFlowInstance]) + }, [reactFlowInstance, stableOptions]) /** * Fits the view to show all nodes within the visible canvas bounds, @@ -116,7 +141,7 @@ export function useCanvasViewport(reactFlowInstance: ReactFlowInstance | null) { return } - const bounds = getVisibleCanvasBounds() + const bounds = getVisibleCanvasBounds(stableOptions) // Calculate node bounds let minX = Number.POSITIVE_INFINITY @@ -160,12 +185,11 @@ export function useCanvasViewport(reactFlowInstance: ReactFlowInstance | null) { reactFlowInstance.setViewport({ x, y, zoom }, { duration }) }, - [reactFlowInstance] + [reactFlowInstance, stableOptions] ) return { getViewportCenter, fitViewToBounds, - getVisibleCanvasBounds, } } From f910fce7a8d89c18dee8efa5f439721e3bf90f29 Mon Sep 17 00:00:00 2001 From: waleed Date: Tue, 17 Mar 2026 09:25:13 -0700 Subject: [PATCH 2/2] fix(embedded): default mothership view to 60% width, remove minimum --- .../home/components/mothership-view/mothership-view.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx index 70c28ad28ba..b055bede558 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/mothership-view.tsx @@ -60,11 +60,11 @@ export const MothershipView = memo(function MothershipView({
-
+