Phase 6: Datenanbindung, Ersteinrichtung und Offline-Anzeige

Die App spricht jetzt echt mit Home Assistant. Ein Datenkontext buendelt die
vier Datentoepfe, haengt sich an den WebSocket-Ereignisstrom und reicht
Verbindungszustand und Warteschlange nach aussen; die Screens kennen weder
REST noch WebSocket. Ersteinrichtung prueft die Zugangsdaten, bevor sie sie
speichert, und unterscheidet in der Fehlermeldung zwischen abgelehntem Token
und nicht erreichbarem Server - zwei Faelle, die voellig verschiedene
Reaktionen verlangen.

Zwei echte Fehler, die erst der Test gegen die laufende Instanz zutage
brachte:

1. Die Typen der Datenschicht deklarierten tank_prozent, sicher_abgestellt
   und sicherheit. Das Backend schreibt tankprozent, gesichert und
   sicherheitscheck - die Oberflaeche haette still ueberall undefined
   gelesen, ohne dass irgendetwas fehlgeschlagen waere.
2. Der Profil-Adapter reichte lebende Verweise ins Rohprofil durch. Ein
   Formular haette damit den Rohstand mitveraendert und die Zusage gebrochen,
   den vom Backend fortgeschriebenen Reifen-Kilometerstand nie zu
   ueberschreiben. Abschnitte werden jetzt kopiert.

Ausserdem zwei Parameter-Eigenschaften in der Datenschicht aufgeloest, weil
Node sie im Strip-Modus nicht uebersetzt und genau darueber die Rauchtests
laufen.

Belegt durch neun Pruefungen gegen die laufende Instanz (Lesen, Dienstaufruf,
vollstaendiger Warteschlangenumlauf, WebSocket-Anmeldung) und 21 Unit-Tests.
This commit is contained in:
Paul Nothaft
2026-08-11 11:02:44 +02:00
parent 5c0c2d1898
commit 0103508cea
13 changed files with 1358 additions and 25 deletions
+36
View File
@@ -0,0 +1,36 @@
/**
* Zuordnung Route → Seite. Eine Stelle, an der jede Seite eingetragen ist;
* die Shell weiß nichts über Inhalte, die Seiten nichts über Navigation.
*/
import { useDaten } from "../daten/DatenKontext"
import type { Route, SeitenName } from "../navigation"
import { Platzhalter } from "./Platzhalter"
export interface SeitenProps {
route: Route
geheZu: (name: SeitenName, id?: string) => void
tabBeschriftung: boolean
setzeTabBeschriftung: (an: boolean) => void
beiAbmeldung: () => void
}
export function SeiteFuer(props: SeitenProps) {
const daten = useDaten()
// Erste Ladung: nichts anzeigen außer einem Hinweis. Ein leeres Gerüst
// wäre schlimmer als ein ehrliches „lädt".
if (!daten.bereit) {
if (daten.ladefehler) {
return (
<div className="dm-leer">
<div className="dm-leer__titel">Daten nicht erreichbar</div>
<p className="dm-leer__text">{daten.ladefehler}</p>
</div>
)
}
return <div className="dm-laden">Daten werden geladen </div>
}
return <Platzhalter route={props.route} geheZu={props.geheZu} />
}