Beim Hinzufügen eines neuen Widgets via /api/layout/add rief der Server
layout_mod.pack() auf alle Items auf — pack() sortiert nach Fläche
absteigend und platziert scan-line greedy. Ein 1x1 hello konnte dabei
einen 2x1 spotify aus seiner Position drängen, weil die Sort-Reihenfolge
sich ändert sobald ein neues Item im Mix ist.
Reproduktion vor dem Fix:
Bestehende config: c1@(0,0) w1@(2,0) st1@(0,2) sp1@(2,2) sv1@(2,3)
Add hello (1x1) → w1 wurde nach (0,2) verschoben, hello landete bei (2,0).
Siehe RED-Test in tests/test_add_route_no_repack.py.
Fix:
- layout.py: neue Funktion first_fit(item, others) — platziert ein Item in
der ersten freien scan-line-Zelle OHNE andere Items zu verändern.
- admin.py /api/layout/add nutzt first_fit. Wenn kein Platz: HTTP 409 mit
{ok:false, error:'kein Platz für WxH-Item', hint:'use_auto_pack'}.
- templates/index.html addItem(): 409 als 'warn'-Toast mit Auto-Pack-Hinweis.
Akzeptanzkriterien (BUG-04):
- bestehende Items bleiben bei Add unverändert an (x,y)
- neues Item landet in erster freier Zelle
- voller Grid → 409, kein bestehendes Item verschoben
- Auto-Pack bleibt als expliziter User-Wunsch erhalten (BUG-06)
Tests:
- tests/test_layout_firstfit.py: 3 unit tests (empty, gappy, full grid)
- tests/test_add_route_no_repack.py: 2 integration tests gegen /api/layout/add
mit gemocktem dashboard-Modul + Flask test_client
Closes#6
Bei API-Fehler (HTTP 5xx, Timeout, DNS-Fehler, Connection refused) wird
3x retry mit backoff versucht. Bei 3x fail wird ein auffaelliges rotes
"!"-Schild mit Plugin-Name und Fehlermeldung statt leeren Slot gerendert.
base.py: NEU - fetch_url() Helper mit Retry-Logik + Error-Formatting
+ render_error_banner() Funktion fuer Plugin-Slots.
Co-Authored-By: Hermes <noreply@hermes.local>
Aus dem Backup und Live-Pull vom Pi (10.11.3.144):
- dashboard.py: Grid-Linien nur im freien Hintergrund (nicht durch Widgets)
- templates/index.html: komplett redesigned mit Sidebar + Topbar + Toast + Modal
- plugins/clock.py: responsive Layout (1x1 bis 4x4)
- plugins/system.py, weather.py, minimax.py: mit Threshold-Bars und Color-Variants
- plugins/base.py: NEU — fetch_with_retry Helper (3x retry mit backoff)
+ render_error_banner für fehlgeschlagene API-Plugins
(grosses rotes "!" Icon mit Plugin-Name und Fehler statt Crash)
Cleanup: Helfer-Chaos (renderer.py/2/3, design_a/b/c.html, clock_classic.py,
23x clock_*.png, alte test_*.py) wurde bereits im vorherigen Commit entfernt.
Co-Authored-By: Hermes <noreply@hermes.local>
Admin UI: Dark Minimal / Retro Terminal / Warm Editorial via header buttons
Display: Classic White / Dark / Sepia / Nord / Terminal via Settings tab
Both switchers persist via localStorage / config.json