unlock duplicates of locked blocks

This commit is contained in:
waleed
2026-01-31 17:33:02 -08:00
parent d533ea27e1
commit 6907c88736
5 changed files with 22 additions and 20 deletions

View File

@@ -2980,11 +2980,12 @@ const WorkflowContent = React.memo(() => {
// Don't process parent changes if the node hasn't actually changed parent or is being moved within same parent
if (potentialParentId === dragStartParentId) return
// Prevent moving blocks out of locked containers
if (dragStartParentId && blocks[dragStartParentId]?.locked) {
// Prevent moving locked blocks out of locked containers
// Unlocked blocks (e.g., duplicates) can be moved out freely
if (dragStartParentId && blocks[dragStartParentId]?.locked && blocks[node.id]?.locked) {
addNotification({
level: 'info',
message: 'Cannot move blocks out of locked containers',
message: 'Cannot move locked blocks out of locked containers',
workflowId: activeWorkflowId || undefined,
})
setPotentialParentId(dragStartParentId) // Reset to original parent

View File

@@ -433,7 +433,7 @@ describe('regenerateBlockIds', () => {
expect(duplicatedBlock.data?.parentId).toBe(loopId)
})
it('should preserve locked state when pasting a locked block', () => {
it('should unlock pasted block when source is locked', () => {
const blockId = 'block-1'
const blocksToCopy = {
@@ -459,11 +459,12 @@ describe('regenerateBlockIds', () => {
const newBlocks = Object.values(result.blocks)
expect(newBlocks).toHaveLength(1)
// Pasted blocks are always unlocked so users can edit them
const pastedBlock = newBlocks[0]
expect(pastedBlock.locked).toBe(true)
expect(pastedBlock.locked).toBe(false)
})
it('should preserve unlocked state when pasting an unlocked block', () => {
it('should keep pasted block unlocked when source is unlocked', () => {
const blockId = 'block-1'
const blocksToCopy = {
@@ -493,20 +494,20 @@ describe('regenerateBlockIds', () => {
expect(pastedBlock.locked).toBe(false)
})
it('should preserve mixed locked states when pasting multiple blocks', () => {
it('should unlock all pasted blocks regardless of source locked state', () => {
const lockedId = 'locked-1'
const unlockedId = 'unlocked-1'
const blocksToCopy = {
[lockedId]: createAgentBlock({
id: lockedId,
name: 'Locked Agent',
name: 'Originally Locked Agent',
position: { x: 100, y: 50 },
locked: true,
}),
[unlockedId]: createFunctionBlock({
id: unlockedId,
name: 'Unlocked Function',
name: 'Originally Unlocked Function',
position: { x: 200, y: 50 },
locked: false,
}),
@@ -526,10 +527,9 @@ describe('regenerateBlockIds', () => {
const newBlocks = Object.values(result.blocks)
expect(newBlocks).toHaveLength(2)
const lockedBlock = newBlocks.find((b) => b.name.includes('Locked'))
const unlockedBlock = newBlocks.find((b) => b.name.includes('Unlocked'))
expect(lockedBlock?.locked).toBe(true)
expect(unlockedBlock?.locked).toBe(false)
// All pasted blocks should be unlocked so users can edit them
for (const block of newBlocks) {
expect(block.locked).toBe(false)
}
})
})

View File

@@ -482,7 +482,8 @@ export function regenerateBlockIds(
position: newPosition,
// Temporarily keep data as-is, we'll fix parentId in second pass
data: block.data ? { ...block.data } : block.data,
// locked state is preserved via spread (same as Figma)
// Duplicated blocks are always unlocked so users can edit them
locked: false,
}
newBlocks[newId] = newBlock

View File

@@ -888,7 +888,7 @@ describe('workflow store', () => {
})
describe('duplicateBlock with locked', () => {
it('should preserve locked state when duplicating a locked block', () => {
it('should unlock duplicate when duplicating a locked block', () => {
const { addBlock, setBlockLocked, duplicateBlock } = useWorkflowStore.getState()
addBlock('original', 'agent', 'Original Agent', { x: 0, y: 0 })
@@ -909,12 +909,12 @@ describe('workflow store', () => {
if (duplicatedId) {
// Original should still be locked
expect(blocks.original.locked).toBe(true)
// Duplicate should also be locked (preserves state like Figma)
expect(blocks[duplicatedId].locked).toBe(true)
// Duplicate should be unlocked so users can edit it
expect(blocks[duplicatedId].locked).toBe(false)
}
})
it('should preserve unlocked state when duplicating an unlocked block', () => {
it('should create unlocked duplicate when duplicating an unlocked block', () => {
const { addBlock, duplicateBlock } = useWorkflowStore.getState()
addBlock('original', 'agent', 'Original Agent', { x: 0, y: 0 })

View File

@@ -709,7 +709,7 @@ export const useWorkflowStore = create<WorkflowStore>()(
name: newName,
position: offsetPosition,
subBlocks: newSubBlocks,
// locked state is preserved via spread (same as Figma)
locked: false,
},
},
edges: [...get().edges],