Selbst-Update: Ladezustand und echter Neustart-Knopf
Der erste echte Live-Test des Selbst-Updates gegen das private Gitea-Repo lief erfolgreich (mehrfach im Test-Container bestätigt) - deckte aber zwei UX-Lücken auf, die der Owner direkt gemeldet hat: - Prüfen/Installieren gaben während der 15-25 Sekunden dauernden Netzwerkaktion keine sichtbare Rückmeldung - nicht von einem Hänger zu unterscheiden. Jetzt ein Ladeindikator (Panel: wiederverwendetes .lade-spinner; companion-app: neues .dm-spinner-Äquivalent, gab es dort noch gar nicht). - Nach erfolgreicher Installation stand nur ein Hinweistext da, kein Weg zum eigentlich nötigen nächsten Schritt. Der Knopf wechselt jetzt zu "Installation abschließen - Jetzt neu starten" und stößt homeassistant.restart direkt an. Das separat gemeldete "Lädt"-Hängenbleiben war kein Bug: reproduziert durch Live-Test des neuen Neustart-Knopfs - eine echte HA-Verbindungsunterbrechung während eines Neustarts zeigt exakt denselben, bereits bestehenden Bootstrap-Ladebildschirm. Vermutlich derselbe Effekt durch den Docker-Neustart früher in dieser Sitzung. Verifiziert im Test-Container per Browser-Automatisierung: Neustart-Knopf ausgelöst, Verbindungsabbruch beobachtet, per docker logs bestätigt, dass Home Assistant tatsächlich neu gestartet ist und die neue Version aktiv wurde. Details in AGENTS.md, Abschnitt L. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -2337,6 +2337,73 @@ entirely, not replaced with a space) and un-escapes `\,`/`\;`/`\n`/`\\` before u
|
||||
Verified: `tsc --noEmit` clean, all 134 companion-app tests pass (127 + 7 new), panel JS re-checked
|
||||
with `node --check`. Manifest bumped to `2026.8.24.5`, `npm run ota` rerun (both frontends changed).
|
||||
|
||||
### L) Self-update UX: loading feedback and a real restart button (2026-08-24, same day)
|
||||
|
||||
**The self-update feature (section J) got its first genuine live test against the real private
|
||||
Gitea repo this same day**, and it worked — confirmed directly in the test container's log across
|
||||
several real attempts (`Update installiert: Version 2026.8.24.5`, no manual file copying involved).
|
||||
That's the first real end-to-end confirmation beyond the unit tests and structural container-restart
|
||||
checks section J could offer on its own.
|
||||
|
||||
That same live test exposed two real UX gaps, both raised directly by the owner:
|
||||
|
||||
1. **No feedback during or after the ~15–25 second install** (confirmed from the log's own
|
||||
timestamps between a "Prüfung" and the matching "installiert" line). The button just sat there
|
||||
with no state change — indistinguishable from a hang, and after success, the version still read
|
||||
"2026.8.24.4 installiert" because that field only updates after a real restart, which nothing in
|
||||
the UI was telling the user to do next beyond a paragraph of text.
|
||||
2. **A separate, initially confusing "Lädt …" hang the owner saw and asked about.** Traced by
|
||||
reproducing it directly: `.lade-spinner`/"Lädt …" is this project's own **existing** top-level
|
||||
bootstrap loading screen (shown whenever `DATEN_GELADEN` is false — i.e., no live connection to
|
||||
Home Assistant yet), not anything related to the update button specifically. Clicking the new
|
||||
"Jetzt neu starten" button and watching it live in a browser reproduced the *exact* same screen —
|
||||
because a `homeassistant.restart` call genuinely does drop the frontend's connection until HA
|
||||
finishes rebooting, and this is the correct, expected screen for that. The most likely explanation
|
||||
for the owner's *original* sighting (before this button existed): the Docker Desktop restart from
|
||||
earlier in the same session dropped the connection the same way. Not a bug — but the fact that it
|
||||
was indistinguishable from one was the actual, valid complaint: nothing signposted that a restart
|
||||
was in progress versus something being stuck.
|
||||
|
||||
**Fixed with a three-state UI, researched against Apple HIG's guidance on indeterminate progress**
|
||||
(unknown-duration network operations get a running indicator, not just a disabled control; on
|
||||
completion the UI leads straight to the next required action instead of leaving the user to find it
|
||||
themselves):
|
||||
- **Prüfen/Installieren, in progress** — a small spinner + "Prüfe …"/"Installiere …", reusing the
|
||||
panel's own pre-existing `.lade-spinner` (originally built, per its own comment, for the exact same
|
||||
"don't let 'still loading' look like 'stuck'" reason at app bootstrap) and a new equivalent
|
||||
`.dm-spinner`/`.dm-ladezeile` pair added to companion-app's `screens.css` (that side had no spinner
|
||||
at all before, only a button-text swap).
|
||||
- **On success** — the tile switches directly to "Installation abschließen - Jetzt neu starten",
|
||||
which calls `homeassistant.restart` (a core HA service any admin could already trigger via
|
||||
Settings → System → Restart — this button doesn't grant a new capability, it surfaces an existing
|
||||
one at the point it's actually needed). Its own click shows "Home Assistant startet neu …";
|
||||
no `.finally`-style cleanup after that call succeeds, since the connection normally drops before
|
||||
the promise would ever resolve — only a genuine rejection (service refused, etc.) reaches the
|
||||
catch block.
|
||||
- **On a real request-level failure** (not the already-handled "no token"/"bad token" case from
|
||||
section J, which returns normally with `fehler` set — this is Gitea unreachable, the websocket
|
||||
itself failing, or any other exception that never made it back from Home Assistant at all) — this
|
||||
was previously silent in companion-app (a `try/finally` with no `catch` re-throws into an
|
||||
unhandled promise rejection). Added explicit `catch` blocks on all three actions in both frontends,
|
||||
each surfacing its own message rather than one shared silently-stale error field.
|
||||
|
||||
- Panel: `INTEGRATION_UPDATE_LAEUFT` (`"pruefen" | "installieren" | "neustart" | null`), the
|
||||
`data-update` click handler rewritten from `serviceRufen()` (fire-and-forget) to direct
|
||||
`HASS.callService()` promise chains so the loading flag can wrap them; `vEinst()`'s tile rewritten
|
||||
with the three states above.
|
||||
- companion-app: `updateNeustartLaeuft`/`updateAktionFehler` state and `updateNeustartAusloesen()` in
|
||||
`Einstellungen.tsx`; new `homeAssistantNeuStarten()` in `api/index.ts` (`dienstAufrufen("homeassistant",
|
||||
"restart")` — note the domain isn't `DIENST_DOMAIN`, this is a core HA service, not one of this
|
||||
integration's own).
|
||||
|
||||
Verified live end-to-end in the test container via browser automation: triggered the real restart
|
||||
button, watched the connection drop into the bootstrap "Lädt …" screen exactly as reasoned above,
|
||||
confirmed via `docker logs` that Home Assistant actually rebooted
|
||||
(`Audi Dashboard 2026.8.24.6 eingerichtet` after restart, version now genuinely current — not just
|
||||
the pre-restart file swap). companion-app: `tsc --noEmit` clean, full suite still green. Manifest
|
||||
bumped to `2026.8.24.6` and `npm run ota` rerun per the standing rule in `VERSIONIERUNG.md` — both
|
||||
frontends changed (new spinner/restart-button behavior is real, visible UI, not internal-only).
|
||||
|
||||
---
|
||||
|
||||
## Working conventions (observed — keep them)
|
||||
|
||||
Reference in New Issue
Block a user