mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-01 02:05:18 -05:00
fix(duplicate): place duplicate outside locked container
When duplicating a block that's inside a locked loop/parallel, the duplicate is now placed outside the container since nothing should be added to a locked container. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1291,6 +1291,74 @@ describe('workflow store', () => {
|
||||
expect(blocks[duplicatedId].locked).toBeFalsy()
|
||||
}
|
||||
})
|
||||
|
||||
it('should place duplicate outside locked container when duplicating block inside locked loop', () => {
|
||||
const { batchToggleLocked, duplicateBlock } = useWorkflowStore.getState()
|
||||
|
||||
// Create a loop with a child block
|
||||
addBlock('loop-1', 'loop', 'My Loop', { x: 0, y: 0 }, { loopType: 'for', count: 3 })
|
||||
addBlock(
|
||||
'child-1',
|
||||
'function',
|
||||
'Child',
|
||||
{ x: 50, y: 50 },
|
||||
{ parentId: 'loop-1' },
|
||||
'loop-1',
|
||||
'parent'
|
||||
)
|
||||
|
||||
// Lock the loop (which cascades to the child)
|
||||
batchToggleLocked(['loop-1'])
|
||||
expect(useWorkflowStore.getState().blocks['child-1'].locked).toBe(true)
|
||||
|
||||
// Duplicate the child block
|
||||
duplicateBlock('child-1')
|
||||
|
||||
const { blocks } = useWorkflowStore.getState()
|
||||
const blockIds = Object.keys(blocks)
|
||||
|
||||
expect(blockIds.length).toBe(3) // loop, original child, duplicate
|
||||
|
||||
const duplicatedId = blockIds.find((id) => id !== 'loop-1' && id !== 'child-1')
|
||||
expect(duplicatedId).toBeDefined()
|
||||
|
||||
if (duplicatedId) {
|
||||
// Duplicate should be unlocked
|
||||
expect(blocks[duplicatedId].locked).toBe(false)
|
||||
// Duplicate should NOT have a parentId (placed outside the locked container)
|
||||
expect(blocks[duplicatedId].data?.parentId).toBeUndefined()
|
||||
// Original should still be inside the loop
|
||||
expect(blocks['child-1'].data?.parentId).toBe('loop-1')
|
||||
}
|
||||
})
|
||||
|
||||
it('should keep duplicate inside unlocked container when duplicating block inside unlocked loop', () => {
|
||||
const { duplicateBlock } = useWorkflowStore.getState()
|
||||
|
||||
// Create a loop with a child block (not locked)
|
||||
addBlock('loop-1', 'loop', 'My Loop', { x: 0, y: 0 }, { loopType: 'for', count: 3 })
|
||||
addBlock(
|
||||
'child-1',
|
||||
'function',
|
||||
'Child',
|
||||
{ x: 50, y: 50 },
|
||||
{ parentId: 'loop-1' },
|
||||
'loop-1',
|
||||
'parent'
|
||||
)
|
||||
|
||||
// Duplicate the child block (loop is NOT locked)
|
||||
duplicateBlock('child-1')
|
||||
|
||||
const { blocks } = useWorkflowStore.getState()
|
||||
const blockIds = Object.keys(blocks)
|
||||
const duplicatedId = blockIds.find((id) => id !== 'loop-1' && id !== 'child-1')
|
||||
|
||||
if (duplicatedId) {
|
||||
// Duplicate should still be inside the loop since it's not locked
|
||||
expect(blocks[duplicatedId].data?.parentId).toBe('loop-1')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateBlockName', () => {
|
||||
|
||||
@@ -563,9 +563,33 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
||||
if (!block) return
|
||||
|
||||
const newId = crypto.randomUUID()
|
||||
const offsetPosition = {
|
||||
x: block.position.x + DEFAULT_DUPLICATE_OFFSET.x,
|
||||
y: block.position.y + DEFAULT_DUPLICATE_OFFSET.y,
|
||||
|
||||
// Check if block is inside a locked container - if so, place duplicate outside
|
||||
const parentId = block.data?.parentId
|
||||
const parentBlock = parentId ? get().blocks[parentId] : undefined
|
||||
const isParentLocked = parentBlock?.locked ?? false
|
||||
|
||||
// If parent is locked, calculate position outside the container
|
||||
let offsetPosition: Position
|
||||
const newData = block.data ? { ...block.data } : undefined
|
||||
|
||||
if (isParentLocked && parentBlock) {
|
||||
// Place duplicate outside the locked container (to the right of it)
|
||||
const containerWidth = parentBlock.data?.width ?? 400
|
||||
offsetPosition = {
|
||||
x: parentBlock.position.x + containerWidth + 50,
|
||||
y: parentBlock.position.y,
|
||||
}
|
||||
// Remove parent relationship since we're placing outside
|
||||
if (newData) {
|
||||
newData.parentId = undefined
|
||||
newData.extent = undefined
|
||||
}
|
||||
} else {
|
||||
offsetPosition = {
|
||||
x: block.position.x + DEFAULT_DUPLICATE_OFFSET.x,
|
||||
y: block.position.y + DEFAULT_DUPLICATE_OFFSET.y,
|
||||
}
|
||||
}
|
||||
|
||||
const newName = getUniqueBlockName(block.name, get().blocks)
|
||||
@@ -594,6 +618,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
|
||||
position: offsetPosition,
|
||||
subBlocks: newSubBlocks,
|
||||
locked: false,
|
||||
data: newData,
|
||||
},
|
||||
},
|
||||
edges: [...get().edges],
|
||||
|
||||
Reference in New Issue
Block a user