- section-head: Button ("+ Neue Zugangsdaten" etc.) rutscht bei langer
Beschreibung nicht mehr in die nächste Zeile — bleibt immer rechts oben,
der Beschreibungstext wickelt stattdessen innerhalb seiner eigenen Spalte.
- Suchfeld-Icon überlappte den Platzhaltertext: eine spätere, generische
Input-Regel mit gleicher Spezifität hat die padding-left-Regel des
Lupe-Icons überschrieben (reine Reihenfolge-im-Stylesheet-Sache) — Selektor
spezifischer gemacht.
- Live-Log: Neustart-bezogene Zeilen (manueller Neustart, automatischer
PoE-Restart bei Ausfall) werden jetzt orange markiert statt farblos.
- Aufgeklappte Nav-Gruppen bleiben über Seitenwechsel hinweg erhalten
(localStorage), zusätzlich zur automatischen Aufklappung der Gruppe der
aktuell aktiven Seite.
- Datei-Auswahl (Import) im Dark Mode gestylt (Text + Button), inkl.
color-scheme-bewusster Browser-Widgets.
- Manueller "Jetzt prüfen"-Trigger (Icon neben dem globalen Timer, nur
Admins): startet rpi-check.service neu -> frisches Logfile + sofortiger
Durchlauf, Countdown synchronisiert sich auf den manuellen Zeitpunkt.
- Dashboard und Live-Log aktualisieren sich jetzt per AJAX im Hintergrund
(kein voller Seiten-Reload mehr): neue Route /dashboard/tiles liefert das
Kachel-Fragment (_dashboard_tiles.html, von index.html eingebunden und vom
Live-Update nachgeladen), get_log() liefert den aktuellen Dateinamen als
Header mit, damit die Anzeige nach einem Service-Neustart aktuell bleibt.
- Root-Cause für "Intervall bleibt immer bei 300s": in der WSL-Testumgebung
lief poe_wrapper.py nur als manuell gestarteter Hintergrundprozess statt
als echter rpi-check.service — "systemctl restart" lief dadurch ins Leere.
Echten systemd-Service in WSL eingerichtet und Intervalländerung end-to-end
verifiziert (Log-Zeilenabstand folgt jetzt dem neu gesetzten Intervall).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
77 lines
2.9 KiB
HTML
77 lines
2.9 KiB
HTML
{% extends "base.html" %}
|
|
{% set active_page = "logs" %}
|
|
{% block page_title %}Live{% endblock %}
|
|
{% block page_sub %}<div class="topbar-sub" data-log-name>{{ log_name or "kein Logfile" }}</div>{% endblock %}
|
|
|
|
{% block content %}
|
|
|
|
<div class="section-head">
|
|
<div>
|
|
<h2 style="font-size:16px;">Live-Log</h2>
|
|
<div class="hint">Laufende Erreichbarkeitsprüfung von poe.sh, farblich markiert (online/offline).</div>
|
|
</div>
|
|
<button id="refresh-btn" class="btn btn-secondary">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 11-3.2-6.9M21 4v5h-5"/></svg>
|
|
Aktualisieren
|
|
</button>
|
|
</div>
|
|
|
|
<div class="log-shell">
|
|
<div class="log-toolbar">
|
|
<div class="log-dots"><span></span><span></span><span></span></div>
|
|
<span class="text-faint mono" style="font-size:11.5px;" data-log-name>{{ log_name or "" }}</span>
|
|
</div>
|
|
<div id="log-box">{{ log_content or "Keine Logfiles gefunden." }}</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function colorizeLine(line) {
|
|
let cls = "";
|
|
if (line.includes(" ist erreichbar!")) cls = "online";
|
|
else if (line.includes(" ist nicht erreichbar!")) cls = "offline";
|
|
else if (line.startsWith("----")) cls = "sep";
|
|
// Neustart-bezogene Zeilen (manueller Neustart, automatischer PoE-Restart
|
|
// bei Ausfall) einheitlich orange markieren.
|
|
else if (line.toLowerCase().includes("manuell") || line.includes("PoE")) cls = "restart";
|
|
const span = document.createElement("span");
|
|
span.className = "log-line" + (cls ? " " + cls : "");
|
|
span.textContent = line;
|
|
return span;
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", () => {
|
|
const intervalMinutes = {{ global_check_interval | int }};
|
|
const intervalMilliseconds = intervalMinutes * 60 * 1000;
|
|
|
|
function renderLog(text, logName) {
|
|
const box = document.getElementById("log-box");
|
|
box.innerHTML = "";
|
|
const lines = text.split("\n");
|
|
lines.forEach((line, i) => {
|
|
box.appendChild(colorizeLine(line));
|
|
if (i < lines.length - 1) box.appendChild(document.createElement("br"));
|
|
});
|
|
box.scrollTop = box.scrollHeight;
|
|
// Dateiname mit anzeigen — ändert sich nach einem Service-Neustart
|
|
// (neues Logfile, z.B. durch "Jetzt prüfen") ohne Seiten-Reload.
|
|
if (logName) {
|
|
document.querySelectorAll("[data-log-name]").forEach((el) => { el.textContent = logName; });
|
|
}
|
|
}
|
|
|
|
function fetchLog() {
|
|
fetch("{{ url_for('get_log') }}")
|
|
.then(r => r.text().then((text) => renderLog(text, r.headers.get("X-Log-Name"))))
|
|
.catch(err => console.error(err));
|
|
}
|
|
|
|
document.getElementById("refresh-btn").addEventListener("click", fetchLog);
|
|
document.addEventListener("poe:check-triggered", fetchLog);
|
|
fetchLog();
|
|
if (intervalMilliseconds) setInterval(fetchLog, intervalMilliseconds);
|
|
});
|
|
</script>
|
|
{% endblock %}
|