Skip to content

Execution tracking UI: playground tab, record toggle, run history and canvas overlay #256

Description

@07prajwal2000

Why

record_execution cannot be set from apps/portal at all — every route ships
with it off and no way to turn it on outside SQL or a raw API call. And once
#254/#255 land there is still nothing that displays a recording.

The natural home is the canvas playground. A user turns recording on, fires a
request from the playground they already have open, and watches the run appear —
without leaving the canvas the run is about to be drawn on.

This is the viewer half of #208 and the recording half of #207.

What

A tab strip in the playground modal header: API Playground | Track Execution. PlaygroundModal is already a size="cover" shell whose body is a
single slot, so the tabs go in the header next to the heading.

Track Execution tab.

  • A record button with a live blip while recording is on, wired to
    PATCH /v1/:projectId/routes/:id. Toggling it triggers a recompile, so the
    button must show that it is applying rather than flipping instantly.
  • Recording on with no runs yet → tell the user to switch to the playground tab
    and fire a request. The empty state is an instruction, not a shrug.
  • Poll the run list for the route while the tab is open — new runs appear
    without a manual refresh — and stop polling when it closes.
  • Run list, newest first. A run that dropped spans or was truncated is labelled
    incomplete.
  • Clicking a run opens a draggable split pane, 30/70: the route graph on one
    side, span detail on the other.

Graph overlay. Nodes tint green or red from each span's outcome. Blocks
that never ran stay neutral — "did not run" and "ran and passed" are different
states and must not look alike. Condition blocks record which edge they took
(branch), so the taken edge is highlighted. Selecting a node shows that span's
input, output, duration and error.

Custom blocks. Spans recorded inside a custom block carry the nested
graph's node ids, not the route's — that is what nullable customBlockId marks.
Overlaid on the route canvas they highlight nothing, so they are excluded from
the tint and surfaced grouped under their invoking block instead.

Async runs. A run forked by an async custom block outlives the request and is
its own root, linked back by parentRunId/parentSeq. Link to it from the
invoking span rather than trying to draw it inside the parent.

Notes

  • apps/portal only. apps/web is legacy — leave it.
  • No hardcoded colors. Green/red come from the success/danger tokens, not
    literals, or the overlay breaks in light theme. See AGENT.md.
  • The canvas already has a readonly mode that keeps elements selectable so panels
    can be opened without editing — reuse it rather than adding a second one.
  • routeVersion is on the run header. Route versioning is not here yet, so the
    viewer draws the current graph; a span whose blockId is no longer on the
    canvas is skipped rather than treated as an error.
  • The project-wide /:projectId/executions page is still a ComingSoon stub. It
    is a reasonable second entry point into the same run detail later, but it is
    not needed for this issue.
  • This is demoable before real traffic produces spans. Publishing synthetic
    runs with scripts/publishTraceRun.ts for a real route id lights up the whole
    UI. Recording from actual playground requests needs the producer, which is
    separate work on the compiled runtime.

Depends on #254 and #255.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions