{# docker/rows.html — HTMX fragment for the Docker page: what needs attention first (service.needs_attention, the ranking the MCP tools use), the counts, then swarm services and each host's containers. #} {% from "_macros.html" import stat_tile, status_badge, status_dot %} {% from "docker/_usage.html" import cpu, mem, cores %} {# ── 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 %} {# ── Counts ────────────────────────────────────────────────────────────── Swarm services are counted as services (a task's container comes and goes); the container counts are the containers outside any swarm service. ────── #}
{{ stat_tile("Needs attention", attention|length + failing_services|length, state="crit" if attention or failing_services else "inactive") }} {{ stat_tile("Unhealthy", unhealthy, state="crit" if unhealthy else "inactive") }} {{ stat_tile("Restarting", restarting, state="crit" if restarting else "inactive", hint="restarting or crash-looping") }} {{ stat_tile("Failed (24h)", failures|length, state="warn" if failures else "inactive", hint="containers and services; listed below", href="#failures" if failures else none) }} {% if swarm_services %}{{ stat_tile("Swarm services", services_healthy ~ "/" ~ swarm_services|length, state="up" if services_healthy == swarm_services|length else "warn", hint="healthy", href="/plugins/docker/swarm") }}{% endif %} {{ stat_tile("Containers running", running, state="up" if running else "inactive", hint="outside swarm services" if swarm_services else none) }} {{ stat_tile("Containers stopped", stopped, state="inactive") }} {% if stale %}{{ stat_tile("Stale", stale, state="stale", hint="no recent report") }}{% endif %} {{ stat_tile("Docker hosts", docker_hosts) }}
{# ── 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. ───────────────────────── #} {% if failures %}

Failed in the last 24h

{% endif %} {# ── Swarm services: collapsed per-service, each current replica labelled with its host (tasks Swarm replaced are left out). Ghost replicas (tasks on nodes with no Steward agent) come from the managers' placement data so the picture is cluster-complete. A failing service names Swarm's last task error. ───── #} {% if swarm_services %}
Swarm services Topology →
{% for s in swarm_services %}
{{ s.name }} {{ s.mode }} {{ s.running }}/{{ s.desired }} running{% if s.state != 'healthy' and s.trouble_since %} · since {{ s.trouble_since|ago }}{% endif %}
{% with style="padding-left:1.1rem;margin-bottom:0.35rem;" %}{% include "docker/_swarm_failures.html" %}{% endwith %}
{% for r in s.replicas %} {% if r.ghost %}
{{ r.host }} {{ r.count }} · no agent
{% else %}
{{ r.host }} {% if r.cpu_pct is not none %}{{ cores(r.cpu_pct / 100) }}{% endif %}
{% endif %} {% endfor %}
{% endfor %}
{% endif %} {# ── Container tables, one per host ───────────────────────────────────────── #} {% if host_groups %} {% for g in host_groups %}
{% if g.host %} {{ g.host.name }} {% else %} {{ g.host_name }} {% endif %} {{ g.running }} running{% if g.stopped %} · {{ g.stopped }} stopped{% endif %}
{% for sub in g.subgroups %} {% if g.grouped and sub.label %} {% endif %} {% for item in sub.containers %} {% set c = item.container %} {% endfor %} {% endfor %}
Container Image Ports CPU Memory
{{ sub.label }}
{{ status_dot('stale' if item.stale else ('up' if c.status == 'running' else ('pending' if c.status == 'paused' else 'down')), 'Stale' if item.stale else c.status|capitalize) }}
{{ c.name }} {% if c.health == 'unhealthy' %} {{ status_badge('crit', 'Unhealthy') }} {% elif c.health == 'starting' %} {{ status_badge('pending', 'Starting') }}{% endif %} {% if item.stale %} {{ status_badge('stale', title="Last report " ~ (c.scraped_at.strftime('%Y-%m-%d %H:%M UTC') if c.scraped_at else 'never') ~ "; what is shown may no longer be true") }}{% endif %}
{{ c.status }}{% if item.uptime %} · up {{ item.uptime }}{% endif %} {% if c.status != 'running' and c.exit_code is not none and c.exit_code != 0 %} · exit {{ c.exit_code }}{% if c.oom_killed %} (OOM){% endif %} {% endif %} {% if c.restart_count %} · ⟳{{ c.restart_count }}{% endif %}
{% if c.service_name or c.compose_project %}
{{ c.service_name or c.compose_project }}
{% endif %}
{{ c.image }} {% for p in item.ports %}
{{ p.host_port }}:{{ p.container_port }}/{{ p.protocol }}
{% endfor %}
{{ cpu(item.usage) }} {{ mem(item.usage) }}
{% endfor %} {% elif not swarm_services %}
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 under that host.
{% endif %}