Skip to content

feat(workflow-editor): open block palette on edge drag-release with auto-connect#5586

Open
TheodoreSpeaks wants to merge 6 commits into
stagingfrom
feat/drag-release-command-palatte
Open

feat(workflow-editor): open block palette on edge drag-release with auto-connect#5586
TheodoreSpeaks wants to merge 6 commits into
stagingfrom
feat/drag-release-command-palatte

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • Releasing a connection drag on empty canvas now opens the command palette so you can pick a block to connect to
  • The chosen block lands at the drop position and is auto-wired from the source handle
  • The palette is restricted to connectable sections only (Blocks, Tools, Tool operations) via a new typed sections allowlist on the search-modal store — triggers/pages/workflows/etc. are hidden since you can't connect into them
  • The restriction self-resets, so normal palette opens (toolbar, keyboard, context menu) are unaffected

Type of Change

  • New feature

Testing

Tested manually. Lint and check:api-validation:strict pass.

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

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

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

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

Request Review

@cursor

cursor Bot commented Jul 11, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes core canvas connection and block-add flows (edge creation, container boundaries, collaborative adds) without automated test updates noted in the PR.

Overview
Releasing a connection drag on empty canvas (when onConnect did not already complete) now opens the universal search palette instead of doing nothing. The open call passes pendingConnect (source node/handle + screen drop coordinates) and limits sections to blocks, tools, and tool operations.

The search modal store gains typed SearchSection / PendingConnect state; open(options) can set section allowlists and pending connect, and setOpen / close clear those so normal palette opens stay unchanged. The modal only renders groups whose section key is allowed.

Palette picks dispatch add-block-from-toolbar with pendingConnect copied from the store. The workflow canvas treats that as completing the drag: it routes through handleToolbarDrop at the release point with a forcedSource, using resolveEdge so wiring follows the same container-boundary rules as onConnect (including loop/parallel start handles), with presetOperation still applied on drop paths.

Reviewed by Cursor Bugbot for commit f5443b7. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds edge drag-release block creation in the workflow editor. The main changes are:

  • Opens the search palette when a connection is released on empty canvas.
  • Limits that palette to connectable block and tool sections.
  • Places the selected block at the release point and wires it from the dragged handle.
  • Adds one-shot search modal state for section filtering and pending connection context.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Adds pending connection placement and container-aware forced-source wiring for palette selections.
apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx Filters rendered search sections and includes pending connection context on connectable selection events.
apps/sim/stores/modals/search/store.ts Extends the search modal store with resettable section filtering and pending connection state.
apps/sim/stores/modals/search/types.ts Adds typed search sections and the pending connection payload shape.

Reviews (7): Last reviewed commit: "refactor(workflow-editor): collapse drag..." | Re-trigger Greptile

Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

Thanks — all four findings were legit and are fixed in 8da6b27:

  1. Drop coordinate offset (Greptile P1) — confirmed against reactflow v11 source: screenToFlowPosition subtracts the pane rect internally (the deprecated project warning literally says "no need to subtract the react flow bounds anymore"). Removed the .workflow-container bounds subtraction; now passes raw client coords like handleCanvasPointerMove does for the live cursor.
  2. Unscoped pending consume (Greptile P1) — the pending ref is now consumed only while the restricted connect-palette it opened is actually up (isOpen && sections), so a toolbar/sidebar/command-list add-block-from-toolbar can't inherit its position/source.
  3. Forced edge skips boundary checks (Bugbot) — the source→new-block edge is now forced only when it stays root-to-root (source exists, not inside a container, not a container-start handle), matching onConnect's cross-boundary rejection.
  4. Palette drop ignores container placement (Bugbot) — releases that land inside a loop/parallel container now delegate to the container-aware handleToolbarDrop (parenting, clamping, in-container auto-connect). The cross-boundary forced edge is intentionally dropped there.

Minor known limitation from (4): a tool operation released directly inside a container loses its preset operation (the container path doesn't thread presetOperation) — niche, and the block still adds correctly.

@greptile review

Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/stores/modals/search/store.ts Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

Round 2 addressed in 7a5f66b. Both remaining findings shared one root cause — I was correlating via ambient store state (isOpen && sections) instead of the selection itself. Replaced that with an explicit correlation token:

  • onConnectEnd generates a token, stores it on pendingConnectRef, and passes it to open({ sections, connectToken }).
  • The palette stamps the store's connectToken onto its add-block-from-toolbar event (both block and tool-operation selections).
  • handleAddBlockFromToolbar consumes the pending connect only when the event's token matches the pending token.

This resolves:

  • "Pending add still unscoped" / "Unrelated add-block steals pending" (Greptile + Bugbot) — a toolbar/sidebar/command-list event carries no matching token, so it can never inherit the pending position/source, even while the modal is open.
  • "Sections reset drops connect placement" (Bugbot, store.ts) — a plain open() now also clears connectToken, so a later pick can't force-wire a stale source; worst case the connect intent is safely dropped (no wrong edge), never misapplied.

The two Cursor comments still anchored to 31ae9f8 (forced-edge boundary + container placement) were fixed in the prior commit 8da6b27 and are outdated.

@greptile review

Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

Fixed in 2d5ce1e — the last real item ("Tool preset dropped in container"). Threaded presetOperation through handleToolbarDrop (optional param, additive for existing callers) and pass it in the in-container delegation, so a tool-operation pick released inside a loop/parallel keeps its chosen operation. No more known limitations on this flow.

The other Cursor comments still anchored to 31ae9f8 (forced-edge boundary + container placement) are outdated — fixed in 8da6b27.

@greptile review

@cursor cursor Bot 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 using default effort and found 2 potential issues.

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 2d5ce1e. Configure here.

Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
Comment thread apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

Round 4 in 40347c4.

"In-container connect wrong edge" (Medium, real) — fixed by unifying the edge logic. handleToolbarDrop now takes an optional forcedSource; when present it wires from that exact handle iff it stays within the resolved container context (same-parent, or a container-start handle into its own child — matching onConnect's boundary rules), otherwise no edge. The drag-release path now delegates entirely to handleToolbarDrop({ ..., forcedSource }) for both root and in-container drops, so:

  • edges always come from the handle you actually dragged (no more nearest-child guessing),
  • container placement/clamp/parenting is correct,
  • cross-boundary drags produce no edge,
  • presetOperation is preserved.

This also let me delete the bespoke root-vs-container branching in handleAddBlockFromToolbar (net simpler).

"Pending connect cleared too early" (Low) — acknowledged, leaving as-is: the palette closes itself on any pick and the close subscription clears the pending ref regardless of success, so deferring the clear wouldn't preserve intent across a rejection. The only rejection reachable from this restricted palette is a single-instance-duplicate block (triggers are excluded from it), which is rare and degrades gracefully to re-dragging.

The three Cursor comments anchored to 31ae9f8/7a5f66b (forced-edge boundary, container placement, tool preset) are outdated — fixed in 8da6b27/2d5ce1e.

@greptile review

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

Simplification pass (f5443b7): collapsed the drag-release correlation machinery — the module ref, the generated connectToken, and the subscribe cleanup effect — into a single pendingConnect field on the search-modal store. The palette stamps it onto its selection event, so its presence is the correlation (no token to match); the store's own open/close lifecycle clears it (no cleanup effect). Net −25 lines, behavior unchanged. @greptile review

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