morca · API · ui

orca.ui.viz

Two views orca ui draws in the browser: a run's Dista timeline, and the pipelines over time on the home page. Both are plain scripts in the page (nothing is fetched from elsewhere) over JSON the UI serves, and both load that JSON only when they're looked at, so the pages stay as fast as they were.

A run's timeline (timeline_section): the run's timeline.json (Chrome's trace format, as dista writes it) drawn on a canvas, a track per process (the driver or head first, then each worker) and a lane per slot its spans overlap on, X and B/E events alike. Spans are coloured by their function's name; "inputs" (a task waiting for what it reads) are thin bars under them. A wheel zooms around the pointer, a drag zooms to what it covers, and Reset zoom goes back; spans narrower than a pixel are drawn as one pixel per lane, so a few hundred thousand events stay quick. Hovering says the span's name, process and slot, start, duration and arguments. The file is fetched when the section scrolls into view; Perfetto and the raw file are linked beside it.

The pipelines over time (gantt_tabs, gantt_panel, gantt_json): "List" and "Timeline" tabs over the home page's table, the choice kept in localStorage; the list is the default and is all there is without scripts. The timeline is a row per pipeline in the order of their datasets (a pipeline that reads what another writes comes after it, indented by its depth), its runs over the last hour, 6 hours, day or week as bars coloured by status, fill runs thinner, a line at now, and a thin connector from a run to each run its commits started (orca.sensed joined to orca.commits). Datasets between pipelines are drawn at the left. Bars narrower than two pixels are merged, and the JSON holds the newest MAX_RUNS runs of the window.

GET /api/gantt?window=24h      # 1h, 6h, 24h or 7d

Functions

window_seconds

def window_seconds(window: String) -> Int

The seconds of a window /api/gantt takes: 1h, 6h, 24h (the default, and what anything else means) or 7d.

gantt_json

def gantt_json(mut db: State, window: String) -> String

/api/gantt: the pipelines in dataset order, with their runs in the window and the runs each started.

gantt_tabs

def gantt_tabs(mut h: Html)

The tabs over the home page's pipelines, hidden until the script shows them, then the list's panel opening.

gantt_panel

def gantt_panel(mut h: Html)

Closes the list's panel, then the timeline's, empty until it's shown, and its script.

timeline_section

def timeline_section(mut h: Html, run: Int)

The run's timeline viewer, which fetches /runs/<run>/timeline.json once it's in view, with Perfetto and the file linked beside it.

Aliases

comptime MAX_RUNS = 20000

Runs /api/gantt answers at most: the newest of the window.

comptime MAX_TRIGGERS = 5000

Connectors between runs /api/gantt answers at most.

comptime VIZ_STYLE = "\n/* The views drawn in the browser (orca.ui.viz). */\n.vtabs { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: center;\n  justify-content: space-between; margin: 1.25rem 0 -0.5rem; }\n.vtabs [role=tablist], .vtabs__win { display: inline-flex; border: 1px solid var(--border);\n  border-radius: var(--radius-sm); overflow: hidden; background: var(--surface); }\n.vtabs__tab, .vtabs__w { font: inherit; font-size: 0.8125rem; color: var(--muted); background: none;\n  border: 0; padding: 0.3rem 0.8rem; cursor: pointer; }\n.vtabs__tab + .vtabs__tab, .vtabs__w + .vtabs__w { border-left: 1px solid var(--border); }\n.vtabs__tab[aria-selected=true], .vtabs__w[aria-pressed=true] { color: var(--text); font-weight: 600;\n  background: var(--surface-2); box-shadow: inset 0 -2px 0 var(--ember); }\n.vtabs__tab:focus-visible, .vtabs__w:focus-visible { outline: 2px solid var(--lake); outline-offset: -2px; }\n.vtabs__w { font-family: var(--mono); font-size: 0.75rem; }\n.gantt__wrap, .tlv__wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; position: relative; }\n.gantt__msg, .tlv__msg { padding: 0.8rem 1.1rem; margin: 0; }\n.gantt svg { display: block; font-family: var(--mono); }\n.gantt__row { fill: transparent; }\n.gantt__row--alt { fill: color-mix(in srgb, var(--text) 2.5%, transparent); }\n.gantt__name { font-size: 12px; fill: var(--text); }\na:hover .gantt__name { fill: var(--lake); text-decoration: underline; }\n.gantt__sub { font-size: 10px; fill: var(--faint); }\n.gantt__chip { fill: none; stroke: var(--muted); stroke-dasharray: 3 2; }\n.gantt__chiptext { font-size: 9.5px; fill: var(--muted); }\n.gantt__tick { stroke: var(--border); }\n.gantt__time { font-size: 10px; fill: var(--faint); }\n.gantt__edge { fill: none; stroke: var(--border-strong); stroke-width: 1.2; }\n.gantt__link { fill: none; stroke: var(--muted); stroke-width: 1; opacity: 0.7; }\n.gantt__now { stroke: var(--ember-soft); stroke-width: 1.5; }\n.gantt__nowtext { font-size: 10px; fill: var(--ember-soft); }\n.gantt a:hover rect { opacity: 0.8; }\n.g--succeeded { fill: var(--lake); background: var(--lake); }\n.g--running { fill: var(--live); background: var(--live); }\n.g--retrying { fill: var(--warn); background: var(--warn); }\n.g--failed { fill: var(--ember); background: var(--ember); }\n.g--queued { fill: color-mix(in srgb, var(--warn) 35%, transparent); stroke: var(--warn);\n  stroke-dasharray: 2 2; background: color-mix(in srgb, var(--warn) 35%, transparent); }\n.g--cancelled { fill: var(--border-strong); background: var(--border-strong); }\n.g--many { stroke: var(--text); stroke-width: 0.6; stroke-opacity: 0.35; }\n.gantt__legend { display: flex; flex-wrap: wrap; gap: 0.4rem 1rem; padding: 0.6rem 1.1rem;\n  border-top: 1px solid var(--border); font-size: 0.75rem; color: var(--muted); }\n.gantt__legend span { display: inline-flex; align-items: center; gap: 0.35rem; }\n.gantt__key { display: inline-block; width: 1.1rem; height: 0.6rem; border-radius: 2px; }\n.gantt__key--fill { height: 0.25rem; }\n.gantt__key--now { width: 2px; height: 0.9rem; background: var(--ember-soft); }\n.gantt__key--link { width: 0.8rem; height: 0.55rem; border-left: 1px solid var(--muted);\n  border-bottom: 1px solid var(--muted); border-radius: 0; }\n.tlv__bar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.9rem;\n  padding: 0.6rem 1.1rem; border-bottom: 1px solid var(--border); font-size: 0.8125rem; }\n.tlv__info { font-size: 0.75rem; margin-left: auto; }\n.tlv__canvas { display: block; cursor: crosshair; touch-action: pan-x pan-y; }\n.tlv__help { font-size: 0.75rem; padding: 0.4rem 1.1rem 0.7rem; margin: 0; }\n.tlv__tip, .gantt__tip { position: absolute; z-index: 2; pointer-events: none; max-width: 22rem;\n  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm);\n  box-shadow: var(--shadow); padding: 0.45rem 0.6rem; font-size: 0.75rem; line-height: 1.4; }\n.tlv__tip b { display: block; font-family: var(--mono); font-weight: 600; word-break: break-all; }\n.tlv__tip dl { display: grid; grid-template-columns: auto 1fr; gap: 0 0.6rem; margin: 0.25rem 0 0; }\n.tlv__tip dt { color: var(--faint); }\n.tlv__tip dd { margin: 0; font-family: var(--mono); word-break: break-all; }\n"

The views' rules, served after orca.ui.style.STYLE in /static/orca.css.