{% from "_status.html" import status_color %}
{% if run and gantt_items %}
Timeline
{{ gantt_items|length }} tasks
{% for m in markers %}
{{ m.label }}
{% endfor %}
{% set ns = namespace(current_group='') %}
{% for gi in gantt_items %}
{% set item = run.items[loop.index0] %}
{% set group = item.task.id.rsplit('.', 1)[0] if '.' in item.task.id else '' %}
{# Group header #}
{% if group != ns.current_group and group != '' %}
{% set ns.current_group = group %}
{{ group }}
{% elif group == '' and ns.current_group != '' %}
{% set ns.current_group = '' %}
{% endif %}
{# Task bar row -- click anywhere on the row to open the task detail view #}
{# Label #}
{% if '.' in item.task.id %}{{ item.task.id.rsplit('.', 1)[1] }}{% else %}{{ item.task.id }}{% endif %}
{# Bar area #}
{# Vertical grid lines #}
{% for m in markers %}
{% if m.pct > 0 %}
{% endif %}
{% endfor %}
{% if gi.has_bar %}
{# Wait segment (submitted -> started) #}
{% if gi.wait_width > 0.1 %}
{% endif %}
{% if gi.run_width > 0 %}
{# Run segment -- colored by state, canonical palette (see _status.html).
min-width keeps very short runs from shrinking to nothing. #}
{% else %}
{# Has timestamps but never ran (still queued, or ended while
waiting). Cap the wait bar with the current/terminal state so
it never reads as a bare amber "still waiting" bar. #}
{% endif %}
{% else %}
{# No timestamps yet (pending / dep_failed / not-yet-submitted).
Always show a colored marker so no state is ever invisible. #}
{% endif %}