Skip to content

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

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

feat(workflows): lock/duplicate improvements for workflows#4387
icecrasher321 merged 11 commits into
stagingfrom
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

vercelBot commented May 1, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
docsSkippedSkippedMay 2, 2026 3:06am

Request Review

@cursor

cursorBot commented May 1, 2026

Copy link
Copy Markdown

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 threadapps/sim/app/api/workflows/[id]/deploy/route.ts Outdated
Comment threadapps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment threadapps/sim/app/api/folders/[id]/duplicate/route.ts
@greptile-apps

greptile-appsBot commented May 1, 2026

Copy link
Copy Markdown
Contributor

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.

  • P1POST /api/workflows (workflow creation) is missing assertFolderMutable(folderId), so members can create new workflows inside locked folders despite all other write paths being guarded.
  • P1POST /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

FilenameOverview
packages/workflow-authz/src/index.tsNew 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.tsGET response correctly exposes locked field; however POST (workflow creation) lacks assertFolderMutable, allowing creation of workflows inside locked folders.
apps/sim/app/api/folders/route.tsNot 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.tsSignificant 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.tsAdds 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.tsMoves 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.sqlAdds 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.tsNew client-side utilities (isFolderOrAncestorLocked, isWorkflowEffectivelyLocked, findLockedAncestorFolder, getFolderPath) mirror server lock logic using cached store data.
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsxAdds 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.tsAdds 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)

    P1Missing 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)

    P1Missing 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 threadapps/sim/app/api/workflows/[id]/deploy/route.ts Outdated
Comment threadapps/sim/lib/workflows/persistence/duplicate.ts
Comment threadapps/sim/lib/workflows/persistence/duplicate.ts
Comment threadapps/sim/app/api/workflows/reorder/route.ts
@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

bugbot run

@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

@greptile

@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

bugbot run

@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

@greptile

Comment threadapps/sim/lib/workflows/persistence/duplicate.ts
Comment threadapps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

bugbot run

@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

@greptile

@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

bugbot run

Comment threadapps/sim/hooks/queries/workflows.ts Outdated
@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

bugbot run

@icecrasher321

Copy link
Copy Markdown
CollaboratorAuthor

bugbot run

@cursorcursorBot left a comment

Copy link
Copy Markdown

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 threadapps/sim/app/api/workflows/reorder/route.ts
Sign up for freeto 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

@icecrasher321