aufträge und „Alle aktualisieren“: beendete lassen sich ausblenden

User 25.09.: Die Karten waren „immer da“ und ließen sich weder bestätigen noch
wegklicken. Beendete Aufträge der KI-Box und das letzte „Alle aktualisieren“
im Homelab haben jetzt einen Knopf „Ausblenden“ (quittiert wird auf dem Server,
gilt also auf allen Geräten; das Protokoll behält alles).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-09-25 12:54:21 +02:00
co-authored by Claude Opus 5.5
parent 0df593c05a
commit 54a3649d5e
39 changed files with 172 additions and 42 deletions
+7
View File
@@ -126,6 +126,13 @@ def sammellauf_stand() -> dict:
return {"sammellauf": sammellauf.aktueller()}
@router.post("/sammellauf/{sl_id}/quittieren")
def sammellauf_quittieren(sl_id: str) -> dict:
"""Beendetes „Alle aktualisieren“ als gesehen markieren (die Update-Seite blendet es aus)."""
from services.homelab import sammellauf
return {"ok": sammellauf.quittieren(sl_id)}
@router.get("/protokoll")
def protokoll_lesen(grenze: int = 200, berichte: bool = False) -> dict:
from services.homelab import protokoll
+6
View File
@@ -155,6 +155,12 @@ def cancel(job_id: str) -> dict:
return {"ok": jobengine.cancel_job(job_id)}
@router.post("/jobs/{job_id}/quittieren")
def quittieren(job_id: str) -> dict:
"""Beendeten Auftrag als gesehen markieren (die Oberfläche blendet ihn aus)."""
return {"ok": jobengine.quittieren(job_id)}
class RoleReq(BaseModel):
role: str | None = None
+17 -2
View File
@@ -89,9 +89,24 @@ def liste() -> list[dict]:
def aktueller() -> dict | None:
"""Der laufende oder, wenn keiner läuft, der letzte Sammellauf."""
"""Der laufende oder, wenn keiner läuft, der letzte Sammellauf — solange ihn niemand quittiert hat (seit
25.09.2026: vorher stand der letzte für immer auf der Update-Seite)."""
alle = _alle()
return oeffentlich(next((x for x in reversed(alle) if x.get("status") == "laeuft"), alle[-1] if alle else None))
if laufend := next((x for x in reversed(alle) if x.get("status") == "laeuft"), None):
return oeffentlich(laufend)
letzter = alle[-1] if alle else None
return None if not letzter or letzter.get("quittiert") else oeffentlich(letzter)
def quittieren(sl_id: str) -> bool:
"""Einen beendeten Sammellauf als gesehen markieren; das Protokoll behält ihn."""
with _lock:
sl = next((x for x in _alle() if x["id"] == sl_id), None)
if not sl or sl.get("status") == "laeuft":
return False
sl["quittiert"] = True
_merken(sl)
return True
def laeuft() -> bool:
+13
View File
@@ -567,6 +567,19 @@ def cancel_job(job_id: str) -> bool:
return True
def quittieren(job_id: str) -> bool:
"""Einen beendeten Auftrag als gesehen markieren — die Oberfläche blendet ihn dann aus (seit 25.09.2026;
vorher blieben beendete Aufträge 24 Stunden stehen, ohne dass man sie wegklicken konnte)."""
with _LOCK:
_laden()
job = JOBS.get(job_id)
if not job or job["state"] not in _ENDE:
return False
job["quittiert"] = True
_speichern(job)
return True
def public_jobs(mit_log: bool = True) -> list[dict]:
"""Aufträge ohne interne Felder für die API; das Protokoll kommt aus der Datei (Ende)."""
with _LOCK:
+11
View File
@@ -386,3 +386,14 @@ def test_schnittstellen(homelab):
fertig = c.get("/api/homelab/sammellauf").json()["sammellauf"]
assert fertig["status"] == "fertig" and fertig["id"] == antwort.json()["sammellauf"]["id"]
assert "meldung" not in fertig and "dringend" not in fertig
def test_quittiert_verschwindet_von_der_update_seite(homelab):
"""25.09.2026: Das fertige „Alle aktualisieren“ ließ sich nicht wegklicken."""
antwort = sammellauf.starten()
assert sammellauf.quittieren(antwort["sammellauf"]["id"]) is False # läuft noch
sl = _auf_ende()
assert sammellauf.aktueller()["id"] == sl["id"]
assert sammellauf.quittieren(sl["id"]) is True
assert sammellauf.aktueller() is None
assert sammellauf.liste()[0]["quittiert"] is True # das Protokoll behält ihn
+13
View File
@@ -194,3 +194,16 @@ def test_systemd_start_scheitert_sauber(motor, monkeypatch):
def test_zeilen_aus_ueberschreibt_mit_wagenruecklauf():
assert jobengine.zeilen_aus("a\n 1%\r 50%\r100%\nb\r\n") == ["a", "100%", "b"]
assert jobengine.zeilen_aus("läuft\r 7%") == [" 7%"]
def test_quittieren_nur_wenn_beendet(motor):
"""25.09.2026: Beendete Aufträge standen 24 Stunden auf der Update-Seite, ohne dass man sie wegklicken konnte."""
job_id = jobengine.start_job([PY, "-c", "import time; time.sleep(30)"], "Lang")
time.sleep(0.2)
assert jobengine.quittieren(job_id) is False # läuft noch
jobengine.cancel_job(job_id)
_warte(job_id)
assert jobengine.quittieren(job_id) is True and _oeffentlich(job_id)["quittiert"] is True
akte = json.loads((motor / f"{job_id}.json").read_text(encoding="utf-8"))
assert akte["quittiert"] is True
assert jobengine.quittieren("gibt-es-nicht") is False