{# docker/rows.html — HTMX fragment for the Docker page (#5298–#5301): a verdict line with only the problem counts that aren't zero; what needs attention (service.needs_attention, the ranking the MCP tools use); hosts whose Docker is not answering; what failed in 24h, each with its logs; then the swarm services and the standalone containers as two tables that share the filter bar's search, filters and sort (overview.py). #} {% from "_macros.html" import stat_tile, status_badge, status_dot, sort_th %} {% from "docker/_usage.html" import cpu, mem, cores %} {% macro th(key, label, cls=none, title=none) -%} {{ sort_th(label, sort_url(key), active=f.sort == key, desc=f.dir == 'desc', cls=cls, title=title) }} {%- endmacro %} {% macro up(row) -%} {%- if row.started_at %}{{ row.started_at|ago|striptags|replace(" ago", "") }} {%- else %}—{% endif -%} {%- endmacro %} {# ── Verdict ──────────────────────────────────────────────────────────────── #} {% set problems = attention|length + failing_services|length %}

{% if problems %}{{ problems }} need{{ "s" if problems == 1 }} attention {% else %}Nothing needs attention{% endif %} {%- if services_total %} · {{ services_healthy }}/{{ services_total }} services healthy{% endif %} {%- if containers_total %} · {{ running }} container{{ "s" if running != 1 }} running{% if stopped %}, {{ stopped }} stopped{% endif %}{% if services_total %} outside services{% endif %}{% endif %} {%- if docker_hosts %} · {{ docker_hosts }} Docker host{{ "s" if docker_hosts != 1 }}{% endif %}

{% if unhealthy or restarting or failures or stale %}
{% if unhealthy %}{{ stat_tile("Unhealthy", unhealthy, state="crit") }}{% endif %} {% if restarting %}{{ stat_tile("Restarting", restarting, state="crit", hint="restarting or crash-looping") }}{% endif %} {% if failures %}{{ stat_tile("Failed (24h)", failures|length, state="warn", hint="listed below, with their logs", href="#failures") }}{% endif %} {% if stale %}{{ stat_tile("Stale", stale, state="stale", hint="no recent report") }}{% endif %}
{% endif %} {# ── Needs attention ──────────────────────────────────────────────────────── #} {% if attention or failing_services %}

Needs attention

{% endif %} {# ── Hosts whose Docker is not answering (agent ≥ 1.9.0) ──────────────────── #} {% if docker_down %}

Docker not answering

{% endif %} {# ── What failed in the last 24h: what the dashboard's "failed (24h)" counts. A plain container's death, or a swarm service's failed tasks; a container someone stopped (exit 137/143) is not a failure. Each links to the logs of what died: a service's to its failed task's lines (#5300). ───────────── #} {% if failures %}

Failed in the last 24h

{% endif %} {# ── Swarm services: one row each, problems first unless a header picked another order; CPU and memory add up the running replicas (#5299). ───── #} {% if services %}

Swarm services {{ services|length }}{% if services|length != services_total %} of {{ services_total }}{% endif %} By node →

{{ th("name", "Service") }} {{ th("status", "Status", title="Problems first: a crash loop, then down, then short of replicas, then failed tasks in 24h") }} {{ th("stack", "Stack", title="The part of the service's name before the first _: the stack it was deployed in") }} {{ th("cpu", "CPU", "num", "Across its running replicas; Docker counts CPU per core") }} {{ th("mem", "Memory", "num", "Across its running replicas") }} {{ th("up", "Up", "num", "Since its newest replica started") }} {% for r in services %} {% endfor %}
NodesFailed 24h
{{ r.name }} {{ status_dot('up' if r.state == 'healthy' else ('warn' if r.state == 'degraded' else 'down')) }} {{ r.running }}/{{ r.desired }} {%- if r.crash_looping %} {{ status_badge('crit', 'Crash-looping') }}{% elif r.unhealthy %} {{ status_badge('crit', 'Unhealthy') }}{% endif %} {%- if r.mode == 'global' %} global{% endif %} {% if r.stack %}{{ r.stack }}{% else %}—{% endif %} {{- r.nodes|join(", ") or ("" if r.ghost_nodes else "—") -}} {%- if r.ghost_nodes %}{{ ", " if r.nodes }}{{ r.ghost_nodes|join(", ") }} (no agent){% endif -%} {% if r.cpu_cores is not none %}{{ cores(r.cpu_cores) }}{% else %}—{% endif %} {% if r.mem_bytes is not none %}{{ r.mem_bytes|bytes }}{% else %}—{% endif %} {{ up(r) }} {%- if r.failures_24h %}{{ r.failures_24h }} {%- else %}—{% endif -%}
{% endif %} {# ── Containers outside any swarm service, every host in one table (#5301); a compose project is its stack. ─────────────────────────────────────── #} {% if containers %}

{{ "Other containers" if services_total else "Containers" }} {{ containers|length }}{% if containers|length != containers_total %} of {{ containers_total }}{% endif %}

{{ th("name", "Container") }} {{ th("status", "Status", title="Problems first: unhealthy or restarting, then died with a failing exit, then stale; then running, then stopped") }} {{ th("stack", "Stack", title="Its compose project") }} {{ th("cpu", "CPU", "num", "Docker counts CPU per core: 1 core = one core fully busy") }} {{ th("mem", "Memory", "num", "Used, and the limit when one is set") }} {{ th("up", "Up", "num", "Since it started") }} {% for r in containers %} {% endfor %}
HostImage
{{ r.name }} {%- if r.ports %}
{% for p in r.ports %}{{ p.host_port }}:{{ p.container_port }}/{{ p.protocol }}{{ " " if not loop.last }}{% endfor %}
{% endif %}
{{ status_dot('stale' if r.stale else ('up' if r.running else ('pending' if r.status == 'paused' else 'down'))) }} {%- if r.health == 'unhealthy' %} {{ status_badge('crit', 'Unhealthy') }} {%- elif r.health == 'starting' %} {{ status_badge('pending', 'Starting') }} {%- else %} {{ r.status }}{% endif %} {%- if not r.running and r.exit_code is not none and r.exit_code != 0 %} exit {{ r.exit_code }}{% if r.oom_killed %} (OOM){% endif %} {%- endif %} {%- if r.restart_count %} ⟳{{ r.restart_count }}{% endif %} {%- if r.stale %} {{ status_badge('stale', title="Last report " ~ (r.scraped_at.strftime('%Y-%m-%d %H:%M UTC') if r.scraped_at else 'never') ~ "; what is shown may no longer be true") }}{% endif %} {{ r.host }} {% if r.stack %}{{ r.stack }}{% else %}—{% endif %} {{ r.image }} {% if r.running %}{{ cpu(r.usage) }}{% else %}—{% endif %} {% if r.running %}{{ mem(r.usage) }}{% else %}—{% endif %} {{ up(r) }}
{% endif %} {% if not services and not containers %}
{% if services_total or containers_total %}

Nothing matches these filters. Show everything

{% else %}

No containers reported yet. Containers are collected by the Steward host agent — deploy the agent to a host running Docker (Hosts → the host → agent panel) and its containers will appear here.

{% endif %}
{% endif %}