{% extends "base.html" %} {% block title %}Timeline - Hermes{% endblock %} {% block content %}

🕐 Full Task Timeline

Summary

Total: {{ stats.total }} | Done: {{ stats.done }} | Blocked: {{ stats.blocked }} | Running: {{ stats.running }} | Ready: {{ stats.ready }} | Failed: {{ stats.failed }}

{% for pname, tasks in by_project.items() %} {% if tasks %}

{% if pname != 'unassigned' %} 📦 {{ pname }} {% else %} 📦 {{ pname }} {% endif %} ({{ tasks|length }} tasks)

{% set ns = namespace(min_ts=99999999999, max_ts=0) %} {% for t in tasks %} {% if t.created_at and t.created_at < ns.min_ts %}{% set ns.min_ts = t.created_at %}{% endif %} {% if t.completed_at and t.completed_at > ns.max_ts %}{% set ns.max_ts = t.completed_at %}{% endif %} {% if t.created_at and not t.completed_at and t.created_at > ns.max_ts %}{% set ns.max_ts = t.created_at %}{% endif %} {% endfor %} {% set span = (ns.max_ts - ns.min_ts) if ns.max_ts > ns.min_ts else 1 %} {% set status_color = {'done': '#4aff4a', 'blocked': '#ff4a4a', 'running': '#4a9eff', 'ready': '#aaaaaa', 'failed': '#ff9e4a'} %}
{% for t in tasks[:20] %} {% if t.created_at %} {% set left = ((t.created_at - ns.min_ts) / span * 100)|round(2) %} {% set width = (((t.completed_at or t.created_at) - t.created_at) / span * 100)|round(2) %} {% if width < 0.5 %}{% set width = 0.5 %}{% endif %} {% set bar_color = status_color.get(t.status, '#888') %}
{% endif %} {% endfor %}
{% if ns.min_ts < 99999999999 %}{{ ns.min_ts|int|dt }} → {{ ns.max_ts|int|dt }}{% endif %}
{% for t in tasks %} {% endfor %}
ID Title Status Created Duration Outcome
{{ t.task_id }} {{ t.title[:80] }} {{ t.status }} {% if t.created_at %}{{ t.created_at|int|dt }}{% endif %} {% if t.duration_s %} {% if t.duration_s < 60 %}{{ t.duration_s }}s {% elif t.duration_s < 3600 %}{{ (t.duration_s / 60)|round(1) }}m {% else %}{{ (t.duration_s / 3600)|round(1) }}h{% endif %} {% else %}-{% endif %} {{ t.outcome_summary[:80] }}
{% endif %} {% endfor %}

← Back to Dashboard

{% endblock %}