{% extends "base.html" %} {% from "fragments/_chips.html" import chip, needs_review_chip %} {% block title %}Voxint — runs{% endblock %} {% block cb_breadcrumb %}runs /{% if show_archived %} archived{% endif %}{% endblock %} {% block cb_summary %} {%- if show_archived -%} Archived runs. Back to active {%- else -%} {{ pipeline_summary }} · Pipeline status {%- endif -%} {% endblock %} {% block cb_actions %} {% if shell.media_enabled %} + Add media {% else %} + Add media {% endif %} {% endblock %} {% block body %} {% if not shell.media_enabled %}

ADD MEDIA

{% if ytdlp_enabled %}

Fetching a URL lets the downloader contact other sites, including ones a link redirects to. If you fetch links you don't fully trust, run the restricted URL-download overlay (compose.ytdlp-egress.yaml) — see the operations guide, “URL ingestion & egress security”.

{% else %}

URL ingestion is disabled.

{% endif %}
{% endif %} {% for d in degraded %} {% endfor %}

RUNS

{# Collapsible filter bar: closed by default, auto-opens when any filter is active. #} {% set has_active_filters = status or review or filters.q or filters.speaker_id or filters.source or filters.created_from or filters.created_to or filters.language %}
Filter{% if has_active_filters %} (active){% endif %}
{% if show_archived %}{% endif %} {% if active_view != LifecycleView.ALL %}{% endif %} {% if has_active_filters %} Clear {% endif %} {% set has_more_filters = filters.q or filters.speaker_id or filters.source or filters.created_from or filters.created_to or filters.language %}
More filters{% if has_more_filters %} (active){% endif %}
{# Macro: one standard run row (reused by both grouped and ungrouped paths). #} {% macro run_row(it) %}
{{ friendly_media_label(it.title, it.source_path) }} {% if it.folder_path %}
{{ it.folder_path }}{% endif %}
{{ it.run_id.hex[:8] }}
{{ humanize_status(it.status) }} {% if it.archived %}archived{% endif %} {% if it.status == "completed" %} {% if it.label_count == 0 %}no speakers {% elif it.unresolved_count > 0 %}{{ needs_review_chip(it.unresolved_count) }} {% else %}{{ chip("reviewed") }}{% endif %} {% elif it.status == "failed" and it.error %} {{ humanize_error(it.error) or "—" }} {% else %}{% endif %} {% if it.claim_live %}claimed{% if it.claimed_by %} · {{ it.claimed_by }}{% endif %}{% endif %} {% if it.language %}{{ language_label(it.language) }}{% else %}{% endif %} {{ format_age(it.created_at, now=now) }} {% if it.status == "completed" and it.unresolved_count > 0 %} Review → {% elif it.status == "failed" %} Retry → {% else %} View → {% endif %}
{% if it.snippet %}
⏱ {{ "%d:%02d" | format(it.snippet.start_seconds // 60, it.snippet.start_seconds % 60) }} — {{ it.snippet.html }}
{% endif %} {% endmacro %} {% if not page.items %}

No runs match{% if has_active_filters %} these filters{% endif %}{% if active_view != LifecycleView.ALL %} in this view{% endif %}.

{% else %}
MEDIA STATUS REVIEW LANGUAGE CREATED
{% if grouped_items is not none %} {# Failed tab: grouped rendering with bulk-retry forms. #} {% for entry in grouped_items %} {% if entry.error_label is defined %} {# FailedRunGroup: summary row with bulk retry form. #}
{{ entry.error_label }}
{{ entry.items|length }} failed runs
Failed × {{ entry.items|length }} {{ format_age(entry.items[0].created_at, now=now) }} {% set batch = entry.items[:100] %}
{% for it in batch %} {% endfor %}
{% else %} {# Singleton failed run: normal row. #} {{ run_row(entry) }} {% endif %} {% endfor %} {% else %} {# Non-Failed tabs: standard row rendering. #} {% for it in page.items %} {{ run_row(it) }} {% endfor %} {% endif %}
{% endif %} {% if next_url %}

Older →

{% endif %}
{% if aux_jobs %}
OTHER TASKS ({{ aux_jobs|length }})

Recent asset, translation, voice sample, and research jobs. These run alongside the pipeline and never block it.

KIND DETAIL STATUS TARGET CREATED
{% for job in aux_jobs %}
{{ job.family }} {{ job.detail or "—" }} {{ chip(job.status) }} {% if job.family == "research" and job.speaker_id %}speaker {{ job.speaker_id.hex[:8] }} {% elif job.pipeline_run_id %}run {{ job.pipeline_run_id.hex[:8] }} {% elif job.speaker_id %}speaker {{ job.speaker_id.hex[:8] }} {% else %}—{% endif %} {{ format_age(job.created_at, now=now) }}
{% endfor %}
{% endif %} {% endblock %}