Skip to content

Commit 04ec0a4

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
fix(mothership): persist embedded workflow positions
1 parent 49e2bb5 commit 04ec0a4

3 files changed

Lines changed: 57 additions & 12 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-canvas-helpers.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,39 @@
44
import { describe, expect, it } from 'vitest'
55
import {
66
getArrowNavigationDirection,
7+
getWorkflowCanvasInteractionPolicy,
78
isPositionalTriggerBlock,
89
reconcileCanvasEdges,
910
reconcileCanvasNodes,
1011
shouldHighlightContainerDropTarget,
1112
} from '@/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-canvas-helpers'
1213

14+
describe('getWorkflowCanvasInteractionPolicy', () => {
15+
it('allows position changes and re-parenting in the editable workflow editor', () => {
16+
expect(getWorkflowCanvasInteractionPolicy({ embedded: false, canEdit: true })).toEqual({
17+
canDragNodes: true,
18+
canReparentNodes: true,
19+
})
20+
})
21+
22+
it('allows position changes without re-parenting in an editable embedded canvas', () => {
23+
expect(getWorkflowCanvasInteractionPolicy({ embedded: true, canEdit: true })).toEqual({
24+
canDragNodes: true,
25+
canReparentNodes: false,
26+
})
27+
})
28+
29+
it.each([false, true])(
30+
'disables dragging when edit access is denied (embedded=%s)',
31+
(embedded) => {
32+
expect(getWorkflowCanvasInteractionPolicy({ embedded, canEdit: false })).toEqual({
33+
canDragNodes: false,
34+
canReparentNodes: false,
35+
})
36+
}
37+
)
38+
})
39+
1340
describe('getArrowNavigationDirection', () => {
1441
it('moves once for a fresh horizontal arrow press', () => {
1542
expect(

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/workflow-canvas-helpers.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,22 @@ import type { BlockState } from '@/stores/workflows/workflow/types'
77

88
export const SUBFLOW_DROP_TARGET_CLASS = 'subflow-node-drop-target'
99

10+
interface WorkflowCanvasInteractionPolicyInput {
11+
embedded: boolean
12+
canEdit: boolean
13+
}
14+
15+
/** Separates position editing from structural re-parenting for embedded canvases. */
16+
export function getWorkflowCanvasInteractionPolicy({
17+
embedded,
18+
canEdit,
19+
}: WorkflowCanvasInteractionPolicyInput) {
20+
return {
21+
canDragNodes: canEdit,
22+
canReparentNodes: canEdit && !embedded,
23+
} as const
24+
}
25+
1026
type ArrowNavigationEvent = Pick<
1127
KeyboardEvent,
1228
'key' | 'repeat' | 'metaKey' | 'ctrlKey' | 'altKey' | 'shiftKey'

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ import {
9292
getEdgeSelectionContextId,
9393
getNodeSelectionContextId,
9494
getRunFromBlockDependencyState,
95+
getWorkflowCanvasInteractionPolicy,
9596
getWorkflowLockToggleIds,
9697
isBlockProtected,
9798
isEdgeProtected,
@@ -732,6 +733,10 @@ const WorkflowContent = React.memo(
732733
}
733734
return userPermissions
734735
}, [userPermissions, currentWorkflow.isSnapshotView, workflowReadOnly])
736+
const { canDragNodes, canReparentNodes } = getWorkflowCanvasInteractionPolicy({
737+
embedded: embedded === true,
738+
canEdit: effectivePermissions.canEdit === true,
739+
})
735740
const {
736741
collaborativeBatchAddEdges,
737742
collaborativeBatchRemoveEdges,
@@ -2869,7 +2874,7 @@ const WorkflowContent = React.memo(
28692874
parentId: block.data?.parentId,
28702875
extent: block.data?.extent || undefined,
28712876
dragHandle: '.workflow-drag-handle',
2872-
draggable: !workflowReadOnly && !isBlockProtected(block.id, blocks),
2877+
draggable: canDragNodes && !isBlockProtected(block.id, blocks),
28732878
zIndex: depth,
28742879
data: {
28752880
...block.data,
@@ -2914,7 +2919,7 @@ const WorkflowContent = React.memo(
29142919
position,
29152920
parentId: block.data?.parentId,
29162921
dragHandle,
2917-
draggable: !workflowReadOnly && !isBlockProtected(block.id, blocks),
2922+
draggable: canDragNodes && !isBlockProtected(block.id, blocks),
29182923
zIndex: cardZIndex,
29192924
extent: (() => {
29202925
// Clamp children to subflow body (exclude header)
@@ -2968,6 +2973,7 @@ const WorkflowContent = React.memo(
29682973
isDebugging,
29692974
getBlockConfig,
29702975
embedded,
2976+
canDragNodes,
29712977
workflowReadOnly,
29722978
collaborativeSetBlockErrorEnabled,
29732979
collaborativeBatchRemoveEdges,
@@ -3677,7 +3683,7 @@ const WorkflowContent = React.memo(
36773683
// paths bail when potentialParentId still equals the drag-start parent, so
36783684
// positions persist but a block can never be inserted into (or pulled out
36793685
// of) a loop/parallel from the embedded view.
3680-
if (embedded) return
3686+
if (!canReparentNodes) return
36813687

36823688
// Check if this is a starter block - starter blocks should never be in containers
36833689
const isStarterBlock = node.data?.type === 'starter'
@@ -3804,7 +3810,7 @@ const WorkflowContent = React.memo(
38043810
getNodes,
38053811
potentialParentId,
38063812
blocks,
3807-
embedded,
3813+
canReparentNodes,
38083814
getNodeAbsolutePosition,
38093815
getNodeDepth,
38103816
isDescendantOf,
@@ -5172,26 +5178,22 @@ const WorkflowContent = React.memo(
51725178
multiSelectionKeyCode={embedded ? null : ['Meta', 'Control', 'Shift']}
51735179
nodesConnectable={!embedded && effectivePermissions.canEdit}
51745180
connectOnClick={false}
5175-
nodesDraggable={!embedded && effectivePermissions.canEdit}
5181+
nodesDraggable={canDragNodes}
51765182
draggable={false}
51775183
noWheelClassName='allow-scroll'
51785184
edgesFocusable={!embedded}
51795185
edgesUpdatable={!embedded && effectivePermissions.canEdit}
51805186
className={`workflow-container h-full bg-[var(--bg)] transition-opacity duration-150 ${reactFlowStyles} ${canvasOpacityClass} ${isHandMode ? 'canvas-mode-hand' : 'canvas-mode-cursor'}`}
5181-
onNodeDrag={effectivePermissions.canEdit ? onNodeDrag : undefined}
5182-
onNodeDragStop={
5183-
!embedded && effectivePermissions.canEdit ? onNodeDragStop : undefined
5184-
}
5187+
onNodeDrag={canDragNodes ? onNodeDrag : undefined}
5188+
onNodeDragStop={canDragNodes ? onNodeDragStop : undefined}
51855189
onSelectionDragStart={
51865190
effectivePermissions.canEdit ? onSelectionDragStart : undefined
51875191
}
51885192
onSelectionDrag={effectivePermissions.canEdit ? onSelectionDrag : undefined}
51895193
onSelectionDragStop={
51905194
effectivePermissions.canEdit ? onSelectionDragStop : undefined
51915195
}
5192-
onNodeDragStart={
5193-
!embedded && effectivePermissions.canEdit ? onNodeDragStart : undefined
5194-
}
5196+
onNodeDragStart={canDragNodes ? onNodeDragStart : undefined}
51955197
snapToGrid={snapToGrid}
51965198
snapGrid={snapGrid}
51975199
elevateEdgesOnSelect={false}

0 commit comments

Comments
 (0)