{% import 'partials/components/ui_macros.html' as ui %} {% import 'partials/components/mobile_card_macros.html' as mc %} {% from 'partials/components/ui_macros.html' import btn, btn_save %} {# Gauge-Karte für die 2x2-Kachelreihe. style='ring' (Default, CPU/RAM): Desktop linearer Balken + caller()-Subtext (ausführlich, viel Platz), Mobile Ring (iOS/Android-Systemeinstellungen- Stil) + eigener, kompakter mobile_sub-Text -- zwei Ringe nebeneinander in schmalen Kacheln haben keinen Platz für den ausführlichen Desktop-Text (siehe .sysinfo-gauge-card--ring). style='bar' (DISK/Extra-Disks): auf Mobile UND Desktop derselbe lineare Balken + caller()-Subtext -- volle Breite, eigene Grid-Zeile (.sysinfo-gauge-card--wide). r=42 -> Umfang 2*pi*42 ≈ 263.9. #} {% macro gauge_card(label, percent, color, style='ring', mobile_sub=none) %}
{{ label }}
{% if style == 'ring' %}
{{ percent }}%
{{ caller() }}
{{ percent }}%
{% if mobile_sub %}
{{ mobile_sub }}
{% endif %} {% else %}
{{ percent }}%
{{ caller() }}
{% endif %}
{# /padding #}
{% endmacro %} {% if not info.ok %}
Systeminfo nicht verfügbar
{{ info.error }}
{% else %}
{# ── Haupt-Layout: linke Info-Karte + rechte 2×2-Gauges ───────────── #}
{# ── Linke Karte: Anwendungen + System-Info ───────────────────────── #} {# Paketnamen aus dem Updater sammeln (für Deduplizierung) #} {% set ns = namespace(updater_names=[]) %} {% if info.updater %}{% for p in info.updater.packages %}{% set ns.updater_names = ns.updater_names + [p.name] %}{% endfor %}{% endif %} {# ── Karte 1: Anwendungen ────────────────────────────────────────── #}
Anwendungen {% if info.updater %} {% if info.updater.last_checked %} Geprüft: {{ info.updater.last_checked }} {% endif %} {% if info.updater.status in ('running', 'checking') %} {{ 'Update läuft…' if info.updater.status == 'running' else 'Prüfung läuft…' }} {% else %} {{ btn('Auf Updates prüfen', variant='primary', busy_label='Prüfe…', icon='refresh', attrs='hx-post="/ui/system/check" hx-target="#system-metrics" hx-swap="outerHTML"') }} {% endif %} {% endif %}
{% if info.updater and info.updater.error %} {% set _warn = info.updater.status == 'warning' %}
{{ info.updater.error }}
{% endif %}
{% if info.updater %} {% for pkg in info.updater.packages %} {% endfor %} {% endif %} {% for key, val in info.software.items() %} {% if key not in ('psutil', 'Datenbank') and key not in ns.updater_names and key.startswith('python') %} {% endif %} {% endfor %} {% for key, val in info.software.items() %} {% if key not in ('psutil', 'Datenbank') and key not in ns.updater_names and not key.startswith('python') %} {% endif %} {% endfor %}
{{ pkg.name }} {{ pkg.installed }} {% if pkg.update_available %} → {{ pkg.latest }} {% elif pkg.latest and pkg.latest != '—' %} aktuell {% endif %} {% if pkg.update_available and info.updater.status not in ('running', 'checking') %} {{ btn('Update', variant='primary', size='', busy_label='Starte…', attrs='style="white-space:nowrap; font-size:11px; padding:3px 10px;" hx-post="/ui/system/update" hx-target="#system-metrics" hx-swap="outerHTML"') }} {% endif %}
{{ key }} {{ val }}
{{ key }} {{ val }}
{# Eine einzige Liste für alle Pakete (getrackte Apps + reine Abhängigkeiten aus info.software), Reihenfolge unverändert -- Pakete mit Update werden nicht mehr herausgezogen, sondern zeigen nur inline den Versionssprung + Update-Button in ihrer eigenen Zeile. #} {% set ns_all = namespace(items=[]) %} {% if info.updater %} {% for pkg in info.updater.packages %} {% set ns_all.items = ns_all.items + [pkg] %} {% endfor %} {% endif %} {% for key, val in info.software.items() %} {% if key not in ('psutil', 'Datenbank') and key not in ns.updater_names %} {% set ns_all.items = ns_all.items + [{'name': key, 'installed': val, 'update_available': False}] %} {% endif %} {% endfor %} {% for pkg in ns_all.items %}
{{ pkg.name }} {% if pkg.update_available %}{{ pkg.installed }} → {{ pkg.latest }}{% else %}{{ pkg.installed }}{% endif %}
{% endfor %}
{# ── Rechte Spalte: System-Karte + Gauges ────────────────────────── #}
{# ── Karte 2: System ─────────────────────────────────────────────── #}
System
{% if info.software.get('Datenbank') %} {% endif %}
OS {{ info.system.os_pretty }}
User {{ info.system.user }}
Datenbank {{ info.software['Datenbank'] }}
{# kein mc.m_card()-Wrapper: der Titel "System" kommt schon von .sysinfo-card-header oberhalb, ein zweiter waere doppelt. #} {{ mc.m_card_row('OS', info.system.os_pretty) }} {{ mc.m_card_row('User', info.system.user) }} {% if info.software.get('Datenbank') %}{{ mc.m_card_row('Datenbank', info.software['Datenbank']) }}{% endif %}
{# ── Gauges: CPU, RAM, DISK, SWAP ─────────────────────────────────── #}
{# CPU: Desktop hat Platz für Kerne+Freq+Modell, die schmale Mobile-Ring- Kachel bekommt nur "N Kerne" -- Freq/Modell würden dort nur umbrechen oder mitten im Wort abgeschnitten werden. #} {% call gauge_card('CPU', info.cpu.percent, 'var(--r)' if info.cpu.percent > 85 else ('var(--b)' if info.cpu.percent > 50 else 'var(--g)'), mobile_sub=(info.cpu.cores ~ ' Kerne')) %} {{ info.cpu.cores }} Kerne · {{ info.cpu.freq }} {% if info.cpu.model %}
{{ info.cpu.model }}
{% endif %} {% endcall %} {# RAM: Desktop zeigt belegt/frei/gesamt einzeln, mobile kompakt als "belegt / gesamt" -- passt in eine Zeile statt umzubrechen. #} {% call gauge_card('RAM', info.mem.percent, 'var(--r)' if info.mem.percent > 85 else ('var(--b)' if info.mem.percent > 60 else 'var(--g)'), mobile_sub=(info.mem.used ~ ' / ' ~ info.mem.total)) %} {{ info.mem.used }} belegt{{ info.mem.free }} frei{{ info.mem.total }} gesamt {% endcall %} {# DISK (/) #} {% if info.root_disk %} {% call gauge_card('DISK', info.root_disk.percent, 'var(--r)' if info.root_disk.percent > 90 else ('var(--b)' if info.root_disk.percent > 70 else 'var(--g)'), style='bar') %} {{ info.root_disk.used_fmt }} belegt{{ info.root_disk.free_fmt }} frei{{ info.root_disk.total_fmt }} gesamt {% endcall %} {% else %}
{% endif %} {# Extra-Disks (aus Einstellungen oder configure()) #} {% for ed in info.extra_disks %} {% call gauge_card(ed.label, ed.percent, 'var(--r)' if ed.percent > 90 else ('var(--b)' if ed.percent > 70 else 'var(--g)'), style='bar') %} {{ ed.used_fmt }} belegt{{ ed.free_fmt }} frei{{ ed.total_fmt }} gesamt {% endcall %} {% endfor %} {% if not info.extra_disks %}
{% endif %}
{# /sysinfo-gauges-grid #}
{# /rechte Spalte #}
{# /content-columns #} {# ──────────────────────────────────────────────────────────────────── #} {# LEGACY-ABSCHNITT ENTFERNT (gauges + app-grid) – neues Layout oben #} {# Dummy-Elemente damit ältere HTMX-Targets nicht brechen #}
{# /data-collected-at #} {# ── Update-Fortschritt ────────────────────────────────────────────────── Bewusst kein Log-Modal: die pip-Ausgabe kommt blockweise gepuffert und taugt nicht als Fortschrittsanzeige. Hier nur der Zustand, danach Neustart abwarten und Seite neu laden. Das Skript ist idempotent – content.html wird bei jeder Prüfung neu eingetauscht. #} {% endif %}