dr-sandbox/app/web/templates/_runs.html
Michael Pilosov 44de8deeeb viz: extract N-panel-agnostic module; homepage modal reuses it for single-run view
- panel-grid.js (new): exports mountPanels({host, controls, stems}) → {destroy}.
  Moved createPanel + shared control wiring + linked-hover + pad-to-match
  time mapping out of compare.js. Stem-count-agnostic; works for 1, 2, or N.
- Panel DOM is cloned from <template id=compare-panel-tpl> on each page.
- compare.js is now a ~10-line shim: parse ?a=&b=, call mountPanels.
- Per-panel color is viridis-sampled by index/N (middle viridis for N=1,
  ends-of-palette for N=2, linear lerp for N≤8, cycle at N≥9). Set as
  --panel-color on the panel element; CSS reads it for tag/time-seg.
- Homepage <dialog id=run-modal> + run-modal.js hijack the 'embedding' link
  (plain click → modal; meta/ctrl/middle-click still opens plotly HTML).
  Dialog close disposes every panel's renderer/geometry/material.
- .compare-grid → repeat(auto-fit, minmax(360px, 1fr)) handles N=1..many,
  replaces the <900px one-column media rule.
- Runs list: relabel Prefect's 'Late' state as 'Queued' — more honest
  description of what the runner is doing at the concurrency cap.
2026-04-22 16:17:01 -06:00

77 lines
3.3 KiB
HTML

{#
Partial: runs list (right column).
Expects: runs (list of normalised view dicts), optional just_submitted (id)
#}
{% if not runs %}
<div class="empty">No runs yet. Dispatch one from the form on the left.</div>
{% else %}
<ul class="runs">
{% for r in runs %}
<li class="run {% if just_submitted is defined and r.id == just_submitted %}just-submitted{% endif %}{% if r.stale %} stale{% endif %}">
{% if r.emb_exists and not r.stale %}
<input type="checkbox" class="compare-cb" data-stem="{{ r.emb_file[:-5] }}" aria-label="select run for comparison" />
{% else %}
<span class="compare-cb-slot" aria-hidden="true"></span>
{% endif %}
<div class="stamp">
{% if r.runtime %}<span class="rt">{{ r.runtime }}</span>{% endif %}
{% if r.start %}{{ r.start[:10] }}<br/>{{ r.start[11:19] }}{% else %}&nbsp;{% endif %}
<span class="id">#{{ r.short_id }}</span>
</div>
<div class="body">
<div class="line1">
<span class="badge {{ r.state_type|lower }}">{{ r.state_name }}</span>
<span class="recipe">
<span class="embedder">{{ r.embedder_short or "?" }}</span>
<em>on</em>
<span class="generator">{{ r.generator_short or "?" }}</span>
</span>
</div>
{% if r.params %}
<div class="paramline">
<span><span class="k">N</span>&nbsp;{{ r.params.get('num_points', '?') }}</span>
<span><span class="k">T</span>&nbsp;{{ r.params.get('num_timesteps', r.params.get('num_snapshots', '?')) }}</span>
<span><span class="k">J</span>&nbsp;{{ r.params.get('jitter_scale', '?') }}</span>
<span><span class="k">s</span>&nbsp;{{ r.params.get('seed', '?') }}</span>
{% set ea = r.params.get('embed_args') or {} %}
{% if ea %}
{% for k, v in ea.items() %}
{% if k not in ('n_components','n_dims','random_state') %}
<span><span class="k">{{ k }}</span>&nbsp;{{ v }}</span>
{% endif %}
{% endfor %}
{% endif %}
</div>
{% endif %}
<div class="outputs">
<span class="tag">fig</span>
{% if r.stale %}<span class="stale-note" title="a newer run with identical params overwrote this output">overwritten</span>{% endif %}
{% if r.ref_file %}
{% if r.ref_exists %}
<a href="/figs/{{ r.ref_file }}" target="_blank" rel="noopener">reference</a>
{% else %}
<a aria-disabled="true">reference</a>
{% endif %}
{% else %}
<span style="color:var(--faint);font-style:italic">reference: n/a</span>
{% endif %}
{% if r.emb_file %}
{% if r.emb_exists %}
<a href="/figs/{{ r.emb_file }}" data-role="embedding-link"
data-stem="{{ r.emb_file[:-5] }}" target="_blank" rel="noopener">embedding</a>
{% else %}
<a aria-disabled="true">embedding</a>
{% endif %}
{% else %}
<span style="color:var(--faint);font-style:italic">embedding: n/a</span>
{% endif %}
</div>
</div>
</li>
{% endfor %}
</ul>
{% endif %}