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. |
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 |
…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
|
@cursor review |
…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
|
@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.
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