Files
sim/scripts
WaleedandMarcus Chandra 6f33a9485b feat(workflows): IDE-style reference viewer for workflows (#5854)
* feat(workflows): add IDE-style reference viewer for workflows

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

* fix(workflows): correct reference resolution for active mode, cycles, 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.

* improvement(workflows): align reference viewer auth, coverage, and UI 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

* improvement(workflows): final polish on the reference viewer

- 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

* fix(workflows): resolve tool references by active canonical mode and 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

* fix(workflows): cover legacy workflow-typed tools and retry depth-truncated 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

---------

Co-authored-by: Marcus Chandra <mzxchandra@gmail.com>
2026-07-22 14:03:07 -07:00
..

Integration documentation generator

generate-docs.ts compiles the per-service integration pages under apps/docs/content/docs/en/integrations/ from the block/tool/trigger registry in apps/sim. The ontology it encodes: everything is a block, and an integration is one block that has Actions and, optionally, a Trigger.

Golden rule: the generated .mdx files are derived artifacts, not the source of truth. Do not hand-edit them — your changes are overwritten on the next run. The only editable region is the MANUAL-CONTENT block (see below). To change what a page says, edit the TypeScript in apps/sim and regenerate.

Where an integration lives canonically

For a service like Gmail, three TS sources define it:

Source What it is What it feeds in the page
apps/sim/blocks/blocks/<service>.ts The block: type, name, category (tools for integrations), bgColor, config sub-blocks, tools.access (which actions it exposes), an optional triggers capability, outputs Header / BlockInfoCard, Usage Instructions, and which actions + trigger appear
apps/sim/tools/<service>/*.ts Each action's params + outputs Every ### <action> → #### Input / #### Output under ## Actions
apps/sim/triggers/<provider>/ The trigger's config fields + outputs The ## Triggers section
apps/sim/components/icons.tsx The brand glyph The page icon

The block references actions by id in tools.access; the generator looks each one up in apps/sim/tools/.

What the generator does

Run with cd apps/sim && bun run generate-docs (or bun run scripts/generate-docs.ts from the repo root). One pass (generateAllBlockDocs):

  1. Copies icons apps/sim/components/icons.tsx → apps/docs/components/icons.tsx and builds apps/docs/components/ui/icon-mapping.ts.
  2. Block pass — for each integration block (category: 'tools', plus the memory / knowledge / table exceptions), writes integrations/<service>.mdx: BlockInfoCard + Usage Instructions + ## Actions.
  3. Trigger pass (generateAllTriggerDocs) — reads apps/sim/triggers/<provider>/ and appends a ## Triggers section to that service's page, or writes a standalone page for trigger-only services.
  4. Writes integrations/meta.json and regenerates the landing page's integrations.json.

Hand-written pages it never touches

Core block pages (blocks/*), the native trigger pages (triggers/{start,schedule,webhook,rss,table}), the integrations overview (integrations/index.mdx), and the service-account pages are fully hand-written. The generator skips them via HANDWRITTEN_INTEGRATION_DOCS, HANDWRITTEN_TRIGGER_DOCS, and SKIP_TRIGGER_PROVIDERS. Add a page name to those sets if you hand-author a page the generator would otherwise produce.

Manual content (the one editable region)

Each generated page may carry hand-written prose inside marker comments. The generator preserves anything between the markers and overwrites everything else, so this survives every regeneration:

{/* MANUAL-CONTENT-START:intro */}
[AgentMail](https://agentmail.to/) is an API-first email platform…
{/* MANUAL-CONTENT-END */}

Supported section names: intro (after the BlockInfoCard — the most common), usage, configuration, outputs, notes. The merge is by marker name (extractManualContent + mergeWithManualContent), so a section is re-inserted at the matching spot in the freshly generated structure.

If you move the output folder, reseed manual content from the old location first — the generator only preserves markers it finds in the existing output file, so a fresh folder starts with none.

Practical: to change…

  • An action's params/outputs, a trigger, or to add a service → edit apps/sim/{blocks,tools,triggers} and re-run the generator.
  • A page's prose intro → edit its MANUAL-CONTENT:intro block directly; it survives regen.
  • The overview / service-account / core-block / native-trigger pages → hand-edit freely.

Gotchas

  • Never hand-edit apps/docs/components/icons.tsx — step 1 overwrites it from the sim app. Components that need an icon the sim app lacks should define it locally or use lucide-react (see components/workflow-preview/block-icons.tsx).
  • The generator is the source of truth for integrations/ and its meta.json; manual edits there are transient.

CI

The generator runs in CI on pushes to the main branch and commits the regenerated docs back. Keep block/tool/trigger metadata accurate in apps/sim and the docs follow.