Kritischen poe.sh-Pfadbug beheben + verschachteltes <form> in Wartung fixen

- KRITISCH: usr/local/bin/custom/poe.sh wurde bei der TESM-Umbenennung
  übersehen und zeigte weiterhin komplett auf die alten Pfade
  (/srv/poe_manager/sqlite.db, /srv/poe_manager/generate_ips.py,
  /var/log/poe-manager) -- der Ping-Check/PoE-Neustart-Loop
  (tesm-check.service) lief dadurch seit dem Umzug nur noch auf Fehler
  ("No such file or directory"), das Live-Log stand seit gestern 19 Uhr
  still und automatische PoE-Neustarts bei Geräteausfall liefen die
  ganze Zeit ins Leere. Auf POETEST live behoben und verifiziert: Log
  schreibt wieder frische Einträge, Checks laufen wieder durch.
- Wartung: "Update starten" nahm live IMMER zusätzlich das erste Gerät
  mit, auch ganz ohne angehakte Checkbox. Ursache: der "Neustart"-Button
  jeder Zeile saß in einem eigenen <form>, das INNERHALB des großen
  #updateForm verschachtelt war -- ungültiges HTML, wodurch Browser das
  äußere Formular vorzeitig schließen/aufspalten. Behoben, indem jedes
  Neustart-<form> jetzt außerhalb von #updateForm steht und der Button
  es nur per form="reboot-<mac>" referenziert. Live verifiziert: ein
  gezielt einzeln ausgewähltes Gerät startet jetzt ausschließlich sich
  selbst, keine leere Auswahl mehr möglich.
- Zusätzlich defensiv: Checkboxen werden beim Laden der Wartungsseite
  jetzt explizit zurückgesetzt (manche Browser stellen den
  Checked-Zustand nach einem Redirect/Reload sonst aus dem Verlauf
  wieder her).
- Restliche "poe"-Relikte aus der TESM-Umbenennung bereinigt: Export-
  Dateiname (poe_manager_export_… → tesm_export_…), Kommentare
  (poe_web.service → tesm.service) sowie ein für den Nutzer sichtbarer
  Hinweistext in Systemeinstellungen (rpi-check.service → tesm-check.service).
This commit is contained in:
2026-08-13 15:54:40 +02:00
parent 34d9cdebd6
commit 51d105399b
5 changed files with 46 additions and 16 deletions
+34 -4
View File
@@ -68,10 +68,16 @@
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
{% if can_run %}
<form method="post" action="{{ url_for('maintenance_reboot') }}" data-confirm="{{ d['name'] }} ({{ d['ip'] }}) jetzt per SSH neu starten?">
<input type="hidden" name="macs" value="{{ d['mac'] }}">
<button type="submit" class="btn btn-sm btn-secondary">Neustart</button>
</form>
<!-- Bewusst KEIN <form> hier: das säße dann innerhalb des
äußeren #updateForm (verschachtelte <form>-Elemente sind
ungültiges HTML) -- der Browser hätte das äußere Formular
an dieser Stelle vorzeitig geschlossen bzw. dessen Inhalt
zerrissen. "Update starten" hat dadurch live IMMER
zusätzlich das erste/oberste Gerät mitgeschickt, auch ganz
ohne angehakte Checkbox. Das eigentliche <form> für den
Neustart steht daher unten AUSSERHALB von #updateForm; der
Button hier referenziert es nur über "form=". -->
<button type="submit" form="reboot-{{ d['mac'] }}" class="btn btn-sm btn-secondary">Neustart</button>
{% endif %}
</div>
</td>
@@ -97,12 +103,36 @@
</div>
{% endif %}
</form>
<!-- Ein eigenständiges, NICHT verschachteltes <form> je Gerät für den
einzelnen "Neustart"-Button (siehe Kommentar oben in der Tabelle) --
jedes referenziert nur genau eine MAC, unabhängig vom Checkbox-Zustand
im großen #updateForm. -->
{% if can_run %}
{% for d in devices %}
<form method="post" action="{{ url_for('maintenance_reboot') }}" id="reboot-{{ d['mac'] }}" data-confirm="{{ d['name'] }} ({{ d['ip'] }}) jetzt per SSH neu starten?">
<input type="hidden" name="macs" value="{{ d['mac'] }}">
</form>
{% endfor %}
{% endif %}
{% endif %}
{% endblock %}
{% block scripts %}
<script>
// Checkboxen beim Laden IMMER zurücksetzen: Browser stellen den
// Checked-Zustand von Formularen nach einem Reload/Redirect (z.B. genau der
// Redirect nach "Update starten") gerne aus dem eigenen Verlauf wieder her,
// unabhängig davon, dass das frisch gerenderte HTML gar kein "checked"
// enthält -- ein einmal angehaktes Gerät (z.B. beim ersten Ausprobieren)
// blieb dadurch bei jedem weiteren Aufruf der Seite unsichtbar mitausgewählt
// und lief bei "Update starten" immer zusätzlich mit, ganz gleich was man
// gerade neu ankreuzt (live genau so reproduziert).
document.querySelectorAll(".maint-check").forEach(function (cb) { cb.checked = false; });
const selectAllCb = document.getElementById("selectAll");
if (selectAllCb) selectAllCb.checked = false;
document.getElementById("selectAll")?.addEventListener("change", function () {
document.querySelectorAll(".maint-check").forEach(function (cb) {
if (!cb.disabled) cb.checked = this.checked;