Skip to content

Conversation

@waleedlatif1
Copy link
Collaborator

Summary

  • added the ability to lock blocks

Type of Change

  • Bug fix

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link

vercel bot commented Feb 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Feb 4, 2026 3:06am

Request Review

Resolved conflicts:
- Removed addBlock from store (now using batchAddBlocks)
- Updated lock tests to use test helper addBlock function
- Kept both staging's optimization tests and lock feature tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
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 <[email protected]>
- Server-side workflow duplication now sets locked: false for all blocks
- regenerateWorkflowStateIds also unlocks blocks for templates
- Client-side regenerateBlockIds already handled this (for paste/import)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@waleedlatif1 waleedlatif1 marked this pull request as ready for review February 1, 2026 02:46
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 1, 2026

Greptile Overview

Greptile Summary

This PR implements a comprehensive block locking feature that prevents editing, deletion, and movement of workflow blocks. The implementation includes:

  • Database schema change adding a locked boolean column to workflow_blocks
  • Frontend lock/unlock UI in block menus and action bars (admin-only)
  • Protection enforcement throughout the workflow editor:
    • Locked blocks cannot be dragged, deleted, renamed, or have edges modified
    • Blocks inside locked containers (loops/parallels) inherit protection
    • Duplicate blocks from locked containers are placed outside and unlocked
  • Server-side validation prevents lock bypass via direct API calls
  • Full collaborative editing support with real-time sync and undo/redo
  • Comprehensive test coverage for lock behavior and edge cases

The lock feature cascades to children when locking loop/parallel containers, and provides clear user notifications when operations are blocked due to lock status.

Confidence Score: 4/5

  • Safe to merge with one minor consideration about PR classification
  • The implementation is comprehensive with strong test coverage and defense-in-depth validation on both frontend and backend. The logic is consistent across components, and edge cases are well-handled. Score is 4 instead of 5 due to the PR being labeled as a "Bug fix" when it's clearly a feature addition, though this doesn't affect code quality.
  • No files require special attention - the implementation is solid across all modified files

Important Files Changed

Filename Overview
apps/sim/stores/workflows/workflow/store.ts Implemented lock logic in store actions: batchToggleEnabled/Handles skip locked blocks, duplicateBlock handles locked containers, added setBlockLocked and batchToggleLocked
apps/sim/socket/database/operations.ts Added server-side lock enforcement: rename, add, remove, toggle, and parent updates check for locked blocks and locked parents
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/block-protection-utils.ts New utility module with isBlockProtected, isEdgeProtected, and filterProtectedBlocks functions
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Integrated lock protection throughout workflow UI: draggable state, edge connections, deletion with user notifications, and lock toggle handler
apps/sim/hooks/use-collaborative-workflow.ts Added collaborative lock operations with undo/redo support, filters locked blocks from enabled/handles toggles
apps/sim/hooks/use-undo-redo.ts Implemented undo/redo for batch lock toggle, fixed toggle operations to use target state instead of negating previous states

Sequence Diagram

sequenceDiagram
    participant User
    participant UI as Workflow UI
    participant Store as Workflow Store
    participant Hook as Collaborative Hook
    participant Socket as Socket Server
    participant DB as Database
    
    Note over User,DB: Lock/Unlock Block Flow
    
    User->>UI: Right-click block(s) → Lock
    UI->>Hook: collaborativeBatchToggleLocked(blockIds)
    Hook->>Store: batchToggleLocked(blockIds)
    
    Note over Store: Collect blocks + children<br/>(if loop/parallel)
    Note over Store: Determine target: !firstBlock.locked
    
    Store->>Store: Update locked state for all blocks
    Hook->>Hook: Record undo/redo operation
    Hook->>Socket: Emit BATCH_TOGGLE_LOCKED operation
    Socket->>DB: Update workflow_blocks.locked
    Socket-->>Hook: Broadcast to collaborators
    Hook->>Store: Apply remote lock changes
    
    Note over User,DB: Protection Enforcement
    
    User->>UI: Try to delete locked block
    UI->>UI: filterProtectedBlocks()
    alt All blocks protected
        UI->>User: Show notification: Cannot delete locked blocks
    else Some protected
        UI->>User: Show notification: Skipped N protected blocks
        UI->>Hook: collaborativeBatchRemoveBlocks(deletableIds)
    end
    
    User->>UI: Try to drag locked block
    Note over UI: draggable={!isBlockProtected(id)}
    UI-->>User: Drag prevented (React Flow)
    
    User->>UI: Try to connect to locked block
    UI->>UI: isEdgeProtected(connection)
    UI->>User: Show notification: Cannot connect to locked blocks
    
    User->>UI: Try to rename locked block
    UI->>Hook: collaborativeUpdateBlockName()
    Hook->>Hook: Check if block.locked || parent.locked
    Hook->>User: Show notification: Cannot rename locked blocks
    
    Note over User,DB: Duplicate with Locked Parent
    
    User->>UI: Duplicate block inside locked loop
    UI->>Store: duplicateBlock(blockId)
    Store->>Store: Check if parent.locked
    Note over Store: Place outside container<br/>Remove parentId
    Store->>Store: Create unlocked duplicate
    Store->>UI: New block outside locked container
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

7 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

- Fix toggle enabled using first toggleable block, not first block
- Delete button now checks isParentLocked
- Lock button now has disabled state
- Editor lock icon distinguishes block vs parent lock state

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Editor: can't unlock block if parent container is locked
- Action bar: can't unlock block if parent container is locked
- Shows "Parent container is locked" tooltip in both cases

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Block Menu, Editor, Action Bar now all have identical behavior:
- Enable/Disable: disabled when locked OR parent locked
- Flip Handles: disabled when locked OR parent locked
- Delete: disabled when locked OR parent locked
- Remove from Subflow: disabled when locked OR parent locked
- Lock: always available for admins
- Unlock: disabled when parent is locked (unlock parent first)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
waleedlatif1 and others added 2 commits January 31, 2026 19:05
Same pattern as lock: must enable parent container first before
enabling children inside it.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Added documentation for the lock/unlock block feature (admin only).
Note: Image placeholder added, pending actual screenshot.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Paste creates new blocks, doesn't modify selected ones. Changed from
disableEdit (includes lock state) to !userCanEdit (permission only),
matching the Duplicate action behavior.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Based on audit findings, adds lock validation to multiple operations:

1. BATCH_TOGGLE_HANDLES - now skips locked/protected blocks at:
   - Store layer (batchToggleHandles)
   - Collaborative hook (collaborativeBatchToggleBlockHandles)
   - Server socket handler

2. BATCH_ADD_BLOCKS - server now filters blocks being added to
   locked parent containers

3. BATCH_UPDATE_PARENT - server now:
   - Skips protected blocks (locked or inside locked container)
   - Prevents moving blocks into locked containers

All validations use consistent isProtected() helper that checks both
direct lock and parent container lock.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
contextMenuBlocks already has locked and isParentLocked properties
computed in use-canvas-context-menu.ts, so there's no need to look
up blocks again via hasProtectedBlocks.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Resolved merge conflict in editor.tsx (kept lock checking logic)
- Removed unused hasProtectedBlocks function from block-protection-utils.ts

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Defense-in-depth: although the UI disables rename for locked blocks,
the collaborative layer and server now also validate locks.

- collaborativeUpdateBlockName: checks if block is locked or inside
  locked container before attempting rename
- UPDATE_NAME server handler: checks lock status and parent lock
  before performing database update

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@waleedlatif1
Copy link
Collaborator Author

@greptile

Defense-in-depth: adds lock checks to server-side handlers that were
previously relying only on client-side validation.

Edge operations (ADD, REMOVE, BATCH_ADD, BATCH_REMOVE):
- Check if source or target blocks are protected before modifying edges

Subblock updates:
- Check if parent block is protected before updating subblock values

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

…ent tooltip

- Fixed edge operations to fetch parent blocks before checking lock status
  - Previously, isBlockProtected checked if parent was locked, but the parent
    wasn't in blocksById because only source/target blocks were fetched
  - Now fetches parent blocks for all four edge operations: ADD, REMOVE,
    BATCH_ADD_EDGES, BATCH_REMOVE_EDGES
- Fixed tooltip inconsistency: changed "Run previous blocks first" to
  "Run upstream blocks first" in action-bar to match workflow.tsx

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

- Added lock check to duplicate button in action bar to prevent
  duplicating locked blocks (consistent with other edit operations)
- Removed ineffective early return in onNodeDragStart since the
  `draggable` property on nodes already prevents dragging protected
  blocks - the early return was misleading as it couldn't actually
  stop a drag operation

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Changed duplicate menu item to use disableEdit (which includes lock
check) instead of !userCanEdit for consistency with action bar and
other edit operations.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@waleedlatif1 waleedlatif1 merged commit 4db6e55 into staging Feb 4, 2026
11 checks passed
@waleedlatif1 waleedlatif1 deleted the feat/lock branch February 4, 2026 03:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants