Skip to content

feat(workflows): lock/duplicate improvements for workflows#4387

Merged
icecrasher321 merged 11 commits intostagingfrom
feat/lock-workflow-folder
May 2, 2026
Merged

feat(workflows): lock/duplicate improvements for workflows#4387
icecrasher321 merged 11 commits intostagingfrom
feat/lock-workflow-folder

Conversation

@icecrasher321
Copy link
Copy Markdown
Collaborator

Summary

Lock/Duplicate Workflows, Folders.

Type of Change

  • New feature

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
Copy Markdown

vercel Bot commented May 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 May 2, 2026 3:06am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 1, 2026

PR Summary

Medium Risk
Broadly enforces new workflow/folder lock semantics across realtime handlers, many workflow/folder API routes, and client UI; mistakes could block legitimate writes or break duplication flows. Transaction/duplication refactors also change ID mapping behavior and failure handling, increasing regression risk.

Overview
Adds first-class workflow/folder locking enforcement end-to-end. Realtime mutation handlers (operations, variables, subblocks) and multiple workflow-affecting API routes (state/variables updates, deploy/undeploy, revert, autolayout, schedules, webhooks, delete/restore) now call assertWorkflowMutable and return 423-style locked errors when locked.

Introduces folder/workflow row-level locking controls and inherited lock behavior in the UI. Folder/workflow list items and the editor/panel now compute an effective lock (row lock or locked ancestor folder) via new folder-tree utilities, disable dragging/editing/variable edits/deploy, and show lock notifications with clearer messaging and unlock behavior (row-lock unlock triggers useUpdateWorkflow).

Tightens and refactors duplication. Folder duplication now runs fully in a single transaction, blocks cross-workspace duplication, skips archived items, prevents duplicating into self/descendants, enforces parent-folder mutability, deduplicates target names, resets locked on new folders/workflows, and passes deterministic newWorkflowId/workflowIdMap through duplicateWorkflow.

Also removes workspace duplicate/export/import UI + API endpoint, and updates contracts/query mapping to include locked fields; selector labels now disambiguate duplicate workflow names by appending folder paths.

Reviewed by Cursor Bugbot for commit 2f3f6dc. Configure here.

Comment thread apps/sim/app/api/workflows/[id]/deploy/route.ts Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/api/folders/[id]/duplicate/route.ts
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 1, 2026

Greptile Summary

This PR adds workflow and folder lock/duplicate improvements: a new locked DB column on both tables, server-side assertWorkflowMutable/assertFolderMutable guards across all mutating API routes and realtime handlers, client-side lock state derived from the folder cache, and a refactored folder-duplicate path that runs entirely inside a single transaction with cross-workflow ID remapping.

  • P1 POST /api/workflows (workflow creation) is missing assertFolderMutable(folderId), so members can create new workflows inside locked folders despite all other write paths being guarded.
  • P1 POST /api/folders (folder creation) is also unmodified and missing assertFolderMutable(parentId), allowing sub-folder creation inside locked folders.

Confidence Score: 3/5

Two gaps in lock enforcement allow item creation inside locked folders — safe to merge only after those are fixed.

Two P1 findings (missing assertFolderMutable on workflow and folder creation) leave real holes in the lock invariant. All other mutation paths are correctly guarded, the DB migration is clean, and the duplicate refactor is solid.

apps/sim/app/api/workflows/route.ts (POST handler) and apps/sim/app/api/folders/route.ts (POST handler) both need assertFolderMutable added before the insert.

Important Files Changed

Filename Overview
packages/workflow-authz/src/index.ts New lock primitives: WorkflowLockedError, FolderLockedError, getWorkflowLockStatus, getFolderLockStatus, assertWorkflowMutable, assertFolderMutable. Ancestor-chain traversal is correct with cycle detection; correctly returns unlocked for missing/archived items.
apps/sim/app/api/workflows/route.ts GET response correctly exposes locked field; however POST (workflow creation) lacks assertFolderMutable, allowing creation of workflows inside locked folders.
apps/sim/app/api/folders/route.ts Not modified in this PR — POST (folder creation) has no assertFolderMutable(parentId), so sub-folders can be created inside locked folders.
apps/sim/lib/workflows/persistence/duplicate.ts Significant refactor: adds tx-passthrough, workflowIdMap for cross-workflow ID remapping, sanitizeSubBlocksForDuplicate, and best-effort edge/subflow-node remapping with warn-and-skip instead of throw. Folder duplicate now runs fully inside one transaction.
apps/sim/app/api/workflows/[id]/duplicate/route.ts Adds FolderLockedError handling; contains dead code — the string-equality 'Folder is locked' check (line 121) is unreachable after the instanceof guard above it.
apps/sim/app/api/folders/[id]/duplicate/route.ts Moves duplicateWorkflowsInFolderTree inside the transaction, adds workflowIdMap for remapping, adds deduplicateFolderName, and correctly guards against locked/archived target folders.
packages/db/migrations/0200_workflow_folder_locks.sql Adds locked boolean DEFAULT false NOT NULL to both workflow and workflow_folder tables; schema migration is clean and non-destructive.
apps/sim/hooks/queries/utils/folder-tree.ts New client-side utilities (isFolderOrAncestorLocked, isWorkflowEffectivelyLocked, findLockedAncestorFolder, getFolderPath) mirror server lock logic using cached store data.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Adds effective lock computation (row + folder-inherited), read-only canvas overlay, and notification for locked workflow; effectivePermissions correctly preserves canAdmin for locked (non-snapshot) workflows.
apps/realtime/src/handlers/operations.ts Adds assertWorkflowMutable check before persisting collaborative operations; emits WORKFLOW_LOCKED operation-forbidden event with retryable:false on lock failure.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Client mutation request] --> B{Route type}
    B -->|PUT/DELETE workflow| C[assertWorkflowMutable]
    B -->|POST workflow CREATE| X[❌ No lock check]
    B -->|PUT/DELETE folder| D[assertFolderMutable on folder]
    B -->|POST folder CREATE| Y[❌ No lock check]
    B -->|reorder workflows| E[assertWorkflowMutable per item]
    B -->|reorder folders| F[assertFolderMutable per item]
    B -->|state/variables/autolayout| G[assertWorkflowMutable]
    B -->|deploy/undeploy/revert| H[assertWorkflowMutable]
    B -->|duplicate workflow| I[assertTargetFolderMutable in tx]
    B -->|duplicate folder| J[assertTargetParentFolderMutable in tx]
    B -->|realtime ops/subblocks/variables| K[assertWorkflowMutable]
    C --> L{Locked?}
    D --> L
    E --> L
    F --> L
    G --> L
    H --> L
    I --> L
    J --> L
    K --> L
    L -->|Yes| M[HTTP 423 WorkflowLockedError / FolderLockedError]
    L -->|No| N[Proceed with DB write]
    X --> N
    Y --> N
Loading

Comments Outside Diff (2)

  1. apps/sim/app/api/workflows/route.ts, line 139-184 (link)

    P1 Missing lock check on workflow creation

    POST /api/workflows never calls assertFolderMutable(folderId), so a member with write access can create a new workflow inside a locked folder. Every other mutating path (PUT, DELETE, reorder, state save, duplicate) guards the target folder, but this creation path was left unguarded. The fix is to add await assertFolderMutable(folderId) (guarded by if (folderId)) and handle FolderLockedError in the catch block, consistent with the pattern used in the other routes.

  2. apps/sim/app/api/folders/route.ts, line 59-90 (link)

    P1 Missing lock check on subfolder creation

    POST /api/folders never calls assertFolderMutable(parentId), so a member with write access can create a new sub-folder inside a locked folder. The PUT/DELETE handlers in /api/folders/[id] both enforce folder mutability, but this creation handler was not updated as part of this PR. await assertFolderMutable(parentId) should be added after the workspace permission check (guarded by if (parentId)), with a FolderLockedError catch block consistent with the existing pattern.

Reviews (4): Last reviewed commit: "address comments" | Re-trigger Greptile

Comment thread apps/sim/app/api/workflows/[id]/deploy/route.ts Outdated
Comment thread apps/sim/lib/workflows/persistence/duplicate.ts
Comment thread apps/sim/lib/workflows/persistence/duplicate.ts
Comment thread apps/sim/app/api/workflows/reorder/route.ts
@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

@icecrasher321
Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

@icecrasher321
Copy link
Copy Markdown
Collaborator Author

@greptile

Comment thread apps/sim/lib/workflows/persistence/duplicate.ts
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

@icecrasher321
Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

Comment thread apps/sim/hooks/queries/workflows.ts Outdated
@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx
@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

Copy link
Copy Markdown

@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 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 2f3f6dc. Configure here.

Comment thread apps/sim/app/api/workflows/reorder/route.ts
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.

1 participant