Skip to content

Commit 6907c88

Browse files
committed
unlock duplicates of locked blocks
1 parent d533ea2 commit 6907c88

File tree

5 files changed

+22
-20
lines changed

5 files changed

+22
-20
lines changed

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2980,11 +2980,12 @@ const WorkflowContent = React.memo(() => {
29802980
// Don't process parent changes if the node hasn't actually changed parent or is being moved within same parent
29812981
if (potentialParentId === dragStartParentId) return
29822982

2983-
// Prevent moving blocks out of locked containers
2984-
if (dragStartParentId && blocks[dragStartParentId]?.locked) {
2983+
// Prevent moving locked blocks out of locked containers
2984+
// Unlocked blocks (e.g., duplicates) can be moved out freely
2985+
if (dragStartParentId && blocks[dragStartParentId]?.locked && blocks[node.id]?.locked) {
29852986
addNotification({
29862987
level: 'info',
2987-
message: 'Cannot move blocks out of locked containers',
2988+
message: 'Cannot move locked blocks out of locked containers',
29882989
workflowId: activeWorkflowId || undefined,
29892990
})
29902991
setPotentialParentId(dragStartParentId) // Reset to original parent

apps/sim/stores/workflows/utils.test.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ describe('regenerateBlockIds', () => {
433433
expect(duplicatedBlock.data?.parentId).toBe(loopId)
434434
})
435435

436-
it('should preserve locked state when pasting a locked block', () => {
436+
it('should unlock pasted block when source is locked', () => {
437437
const blockId = 'block-1'
438438

439439
const blocksToCopy = {
@@ -459,11 +459,12 @@ describe('regenerateBlockIds', () => {
459459
const newBlocks = Object.values(result.blocks)
460460
expect(newBlocks).toHaveLength(1)
461461

462+
// Pasted blocks are always unlocked so users can edit them
462463
const pastedBlock = newBlocks[0]
463-
expect(pastedBlock.locked).toBe(true)
464+
expect(pastedBlock.locked).toBe(false)
464465
})
465466

466-
it('should preserve unlocked state when pasting an unlocked block', () => {
467+
it('should keep pasted block unlocked when source is unlocked', () => {
467468
const blockId = 'block-1'
468469

469470
const blocksToCopy = {
@@ -493,20 +494,20 @@ describe('regenerateBlockIds', () => {
493494
expect(pastedBlock.locked).toBe(false)
494495
})
495496

496-
it('should preserve mixed locked states when pasting multiple blocks', () => {
497+
it('should unlock all pasted blocks regardless of source locked state', () => {
497498
const lockedId = 'locked-1'
498499
const unlockedId = 'unlocked-1'
499500

500501
const blocksToCopy = {
501502
[lockedId]: createAgentBlock({
502503
id: lockedId,
503-
name: 'Locked Agent',
504+
name: 'Originally Locked Agent',
504505
position: { x: 100, y: 50 },
505506
locked: true,
506507
}),
507508
[unlockedId]: createFunctionBlock({
508509
id: unlockedId,
509-
name: 'Unlocked Function',
510+
name: 'Originally Unlocked Function',
510511
position: { x: 200, y: 50 },
511512
locked: false,
512513
}),
@@ -526,10 +527,9 @@ describe('regenerateBlockIds', () => {
526527
const newBlocks = Object.values(result.blocks)
527528
expect(newBlocks).toHaveLength(2)
528529

529-
const lockedBlock = newBlocks.find((b) => b.name.includes('Locked'))
530-
const unlockedBlock = newBlocks.find((b) => b.name.includes('Unlocked'))
531-
532-
expect(lockedBlock?.locked).toBe(true)
533-
expect(unlockedBlock?.locked).toBe(false)
530+
// All pasted blocks should be unlocked so users can edit them
531+
for (const block of newBlocks) {
532+
expect(block.locked).toBe(false)
533+
}
534534
})
535535
})

apps/sim/stores/workflows/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,7 +482,8 @@ export function regenerateBlockIds(
482482
position: newPosition,
483483
// Temporarily keep data as-is, we'll fix parentId in second pass
484484
data: block.data ? { ...block.data } : block.data,
485-
// locked state is preserved via spread (same as Figma)
485+
// Duplicated blocks are always unlocked so users can edit them
486+
locked: false,
486487
}
487488

488489
newBlocks[newId] = newBlock

apps/sim/stores/workflows/workflow/store.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,7 @@ describe('workflow store', () => {
888888
})
889889

890890
describe('duplicateBlock with locked', () => {
891-
it('should preserve locked state when duplicating a locked block', () => {
891+
it('should unlock duplicate when duplicating a locked block', () => {
892892
const { addBlock, setBlockLocked, duplicateBlock } = useWorkflowStore.getState()
893893

894894
addBlock('original', 'agent', 'Original Agent', { x: 0, y: 0 })
@@ -909,12 +909,12 @@ describe('workflow store', () => {
909909
if (duplicatedId) {
910910
// Original should still be locked
911911
expect(blocks.original.locked).toBe(true)
912-
// Duplicate should also be locked (preserves state like Figma)
913-
expect(blocks[duplicatedId].locked).toBe(true)
912+
// Duplicate should be unlocked so users can edit it
913+
expect(blocks[duplicatedId].locked).toBe(false)
914914
}
915915
})
916916

917-
it('should preserve unlocked state when duplicating an unlocked block', () => {
917+
it('should create unlocked duplicate when duplicating an unlocked block', () => {
918918
const { addBlock, duplicateBlock } = useWorkflowStore.getState()
919919

920920
addBlock('original', 'agent', 'Original Agent', { x: 0, y: 0 })

apps/sim/stores/workflows/workflow/store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
709709
name: newName,
710710
position: offsetPosition,
711711
subBlocks: newSubBlocks,
712-
// locked state is preserved via spread (same as Figma)
712+
locked: false,
713713
},
714714
},
715715
edges: [...get().edges],

0 commit comments

Comments
 (0)