fix(embedded): autolayout viewport calculation for resource view (#3629)

* fix(embedded): autolayout viewport calculation for resource view

* fix(embedded): default mothership view to 60% width, remove minimum
This commit is contained in:
Waleed
2026-03-17 09:30:10 -07:00
committed by GitHub
parent 8fa4f3fdbb
commit 3e3c160789
4 changed files with 47 additions and 18 deletions
@@ -60,11 +60,11 @@ export const MothershipView = memo(function MothershipView({
<div
className={cn(
'relative z-10 flex h-full flex-col overflow-hidden border-[var(--border)] bg-[var(--bg)] transition-[width,min-width,border-width] duration-300 ease-out',
isCollapsed ? 'w-0 min-w-0 border-l-0' : 'w-[50%] min-w-[400px] border-l',
isCollapsed ? 'w-0 min-w-0 border-l-0' : 'w-[60%] border-l',
className
)}
>
<div className='flex min-h-0 min-w-[400px] flex-1 flex-col'>
<div className='flex min-h-0 flex-1 flex-col'>
<ResourceTabs
workspaceId={workspaceId}
chatId={chatId}
@@ -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(
@@ -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])
+36 -12
View File
@@ -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<CanvasViewportOptions | undefined>(
() => (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,
}
}