b0d3e83bdd
Realizes the chosen host-summary layout: a thin live vitals bar at the very top, separate from the agent management panel (no more duplicated CPU/MEM/DISK/LOAD). - New fragment _host_vitals.html + route /plugins/host_agent/vitals/<id>: compact CPU / Memory / Disk(/) / Load-per-core (threshold-coloured + sparkline) + Pressure + live/stale·version·last-seen. Polled every 15s; renders nothing until the agent reports. - The metric computation (latest snapshot + 6h sparkline query + load/core + PSI) moves from host_panel into host_vitals. host_panel slims to management only (reg/target/reporting/stale/ansible) and no longer queries metrics; panel.html drops the gauge row + pressure block, keeping status + lifecycle actions. - hosts/detail.html: vitals strip on top (full width, live), then a 2-col [Monitors | Agent] grid, Ansible full width below, docker fragment last. UI only. Templates parse; plugin-template parse test covers the new fragment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Jg27rgypiW2efULXJDtMC
36 lines
2.3 KiB
HTML
36 lines
2.3 KiB
HTML
{# Host vitals strip — compact CPU/MEM/DISK/LOAD + pressure, live-polled into the
|
|
host hub. Renders nothing until the agent reports (the Agent panel below then
|
|
shows provisioning). #}
|
|
{% if reporting %}
|
|
{% set lbl = "font-size:0.68rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:0.04em;" %}
|
|
{% macro vital(label, value, text, kind, spark) %}
|
|
<div style="min-width:88px;">
|
|
<div style="{{ lbl }}">{{ label }}</div>
|
|
<div style="font-size:1.5rem;font-weight:700;line-height:1.1;{{ threshold_style(value, kind) }}">{{ text }}</div>
|
|
<div style="margin-top:0.2rem;">{{ spark | safe }}</div>
|
|
</div>
|
|
{% endmacro %}
|
|
<div class="card" style="display:flex;flex-wrap:wrap;align-items:flex-start;gap:1rem 2rem;margin-bottom:1rem;">
|
|
{{ vital("CPU", cpu, ('%.0f%%'|format(cpu) if cpu is not none else '—'), 'cpu', sparks.cpu) }}
|
|
{{ vital("Memory", mem, ('%.0f%%'|format(mem) if mem is not none else '—'), 'mem', sparks.mem) }}
|
|
{{ vital("Disk /", disk_root, ('%.0f%%'|format(disk_root) if disk_root is not none else '—'), 'disk', sparks.disk) }}
|
|
{{ vital("Load /core", load_per_core, ('%d%%'|format(load_per_core) if load_per_core is not none else '—'), 'load', sparks.load) }}
|
|
|
|
<div style="margin-left:auto;display:flex;flex-direction:column;align-items:flex-end;gap:0.3rem;font-size:0.75rem;color:var(--text-muted);text-align:right;">
|
|
<span>
|
|
{% if stale %}<span class="badge badge-red">stale</span>{% else %}<span class="badge badge-green">live</span>{% endif %}
|
|
{% if reg and reg.agent_version %}<span style="margin-left:0.3rem;">v{{ reg.agent_version }}</span>{% endif %}
|
|
</span>
|
|
{% if psi.cpu is not none or psi.mem is not none or psi.io is not none %}
|
|
<span title="Pressure stall — % of the last 10s tasks waited for the resource">
|
|
<span style="color:var(--text-dim);text-transform:uppercase;font-size:0.66rem;letter-spacing:0.04em;">Pressure 10s</span>
|
|
cpu {{ '%.0f%%'|format(psi.cpu) if psi.cpu is not none else '—' }}
|
|
· mem {{ '%.0f%%'|format(psi.mem) if psi.mem is not none else '—' }}
|
|
· io {{ '%.0f%%'|format(psi.io) if psi.io is not none else '—' }}
|
|
</span>
|
|
{% endif %}
|
|
{% if reg and reg.last_seen_at %}<span>seen {{ reg.last_seen_at.strftime("%H:%M:%S") }} UTC</span>{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|