Uh oh!
There was an error while loading. Please reload this page.
feat(workflows): IDE-style reference viewer for workflows - #5854
Conversation
Adds a "Show references" viewer so you can see how workflows connect:
which workflows call a given workflow ("Used by") and which workflows it
calls ("Uses"), rendered as recursive, clickable trees.
- Opened via Cmd/Ctrl+click on a sidebar workflow row and a "Show
references" context-menu item.
- Resolves references through both the workflow / workflow_input blocks
(reusing isWorkflowBlockType) and published custom blocks
(custom_block_* -> source workflow), scoped to the workspace.
- Builds the whole workspace reference graph once from live workflow_blocks
state; cycle-safe DFS marks A->B->A loops as (cycle) leaves.
- Contract-bound GET /api/workflows/[id]/references with workspace-level
authz; React Query hook gated to fetch only when the modal opens.
- Unit tests for the pure graph/tree logic (cycles, self-refs, dangling
drop, custom-block + workflow_input resolution) and route tests
(401/400/403/200).… cache, and graph size Addresses review findings on the reference viewer: - Resolve the workflow-block child via resolveActiveCanonicalValue (the shared SOT) instead of basic-first `||`, so an advanced-mode block whose old basic workflowId value lingers resolves to the active manual value. - Keep self-references (A -> A) and render them as a cycle leaf instead of dropping the edge, matching the cycle-safe viewer's purpose. - Set the references query staleTime to 0 so reopening the always-mounted modal refetches live editor state instead of serving a stale cached graph. - Bound converging paths: a node already expanded elsewhere in the tree is emitted once more as a plain leaf (edge stays visible) rather than re-expanded, so a densely reconverging graph can't grow exponentially.
… with platform conventions - authorize via authorizeWorkflowByWorkspacePermission and derive the workspace server-side (404/403 semantics; drops the client-supplied workspaceId query param from the contract, hook, and modal) - add workflow-tool call edges: workflow_input tools inside tool-input sub-blocks now appear in both trees; non-call selector shapes stay deliberately excluded (documented against remap-internal-ids) - restore native cmd/ctrl+click open-in-new-tab on sidebar workflow rows; references stay reachable from the context menu - mount ReferencesModal on demand per row, deleting the prevIsOpen reset, the enabled knob, and the staleTime-0 workaround (now 30s) - align the tree with design tokens (--text-icon, --surface-hover, px-4 text gutter) and drop the hardcoded brand hex - escape LIKE wildcards in the custom_block_ prefix match; import MAX_CALL_CHAIN_DEPTH instead of mirroring it; remove dead fallbacks, the duplicate not-found scan, and the redundant custom-block row map
- drop the vestigial isOpen prop (conditional mount owns visibility) - unify on the emcn Workflow icon in tree rows - inline the static className and derive nodes without an annotation - remove one restating test comment
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Introduces GET New Reviewed by Cursor Bugbot for commit 809971b. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.
Greptile SummaryThis PR adds an IDE-style reference viewer for workflows. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (3): Last reviewed commit: "fix(workflows): cover legacy workflow-ty..." | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
…keep the reference cache live - workflow_input tools inside tool-input now resolve basic/advanced via the index-scoped canonicalModes override, mirroring execution (Cursor finding) - staleTime back to 0: no mutation invalidates this key, so a reopen must background-refetch; on-demand mounting keeps the cached tree painting instantly (Greptile P1) - modal header uses the em-dash label-entity convention; tree items carry aria-level instead of a static aria-selected
waleedlatif1
commented
Jul 22, 2026
waleedlatif1
commented
Jul 22, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
…ncated expansions - toolInputCallees matches both workflow tool type spellings via isWorkflowBlockType and passes the tool's own type as the legacy canonicalModes fallback, matching providers/utils resolution - a depth-capped expansion no longer poisons the expanded set, so a shallower path re-expands the node in full (Cursor finding) - the allowed-but-workspaceless auth branch now returns 403, not the authz result's 200 - tests: legacy tool type + per-tool index-scope isolation, diamond re-expansion with a real subtree, depth ceiling, shallow-path retry
waleedlatif1
commented
Jul 22, 2026
waleedlatif1
commented
Jul 22, 2026
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 809971b. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
Supersedes #5852 — builds directly on @mzxchandra's branch (both original commits preserved) and layers a cleanup/alignment pass on top. Huge thanks to Chandra for the feature itself: the recursive caller/callee resolver, the cycle/diamond handling, and the modal UI all originate there.
What the feature does
Right-click a workflow in the sidebar → Show references opens a modal with two tabs: Used by (workflows that call it) and Uses (workflows it calls), each a recursive tree whose rows navigate to the referenced workflow. Resolution reads live editor state (draft
workflow_blocks), resolves the ACTIVE canonical mode so a dormant basic/advanced value can't mask the live one, marks cycles as leaves, and bounds diamond re-expansion.Changes on top of #5852
Coverage
workflow_inputtools insidetool-inputsub-blocks (an agent invoking another workflow as a tool) now appear in both trees, with array and JSON-stringified values handled via the sharedcoerceObjectArrayhelper. Non-call selector shapes (workflowSelector, triggerworkflowIds) are deliberately excluded and documented againstremapWorkflowReferencesInSubBlocks.Auth
/api/workflows/[id]/*siblings viaauthorizeWorkflowByWorkspacePermissionand derives the workspace server-side — proper 404/403 semantics, and the client-suppliedworkspaceIdquery param is gone from the contract, hook, and modal.UX
ReferencesModalmounts on demand per row instead of always-mounted-per-row — removes N idle React Query observers in large workspaces and deletes theprevIsOpenreset machinery, theenabledknob, and thestaleTime: 0workaround (now a named 30s constant).Design system
--text-icon/--surface-hovertokens and the emcnWorkflowicon instead of a hardcoded brand hex.Hardening / hygiene
custom_block_prefix match; importedMAX_CALL_CHAIN_DEPTHinstead of mirroring it; un-exported the internal graph builder; removed dead fallbacks, a duplicate not-found scan, and a redundant row-narrowing map.Verification
bunx vitest runon both test files: 18/18 passingbun run check:api-validationand:strict: pass (baseline 966→967 for the new route)biome checkclean;tscclean on all touched files