companion-app: Datensatz sichern/laden portiert (Item 9 Paritaet)

- "Daten ausgeben" zu "Fahrzeugprofil" umgebaut, gleiche zwei Knoepfe wie
  im Panel: Datensatz sichern/laden, popup mit vier Aktionen
- CSV-Spaltennamen jetzt byte-identisch zum Panel-Export (gemeinsamer
  Backend-Parser, csv_import.py) - vorher eigene, abweichende Kopfzeilen
  ohne Reimport-Moeglichkeit
- neue api.csvImportieren(), Fahrzeugprofil-Import ueber das bestehende
  api.profilSchreiben() (volles Profil, nicht die teilweise
  zusammenfuehrende profilSpeichern()-Bequemlichkeitsfunktion)
- Blinden Fleck geprueft: importStatusLesen()/zustandLesen() lesen per
  REST, nicht aus lokalem Cache - dieselbe Racebedingung wie im Panel kann
  hier strukturell nicht auftreten
- Toten dateiwahl-Scaffolding entfernt (nie verdrahtet)

Beim Bauen echten, vorbestehenden Fehler gefunden: companion-app und Panel
verwenden unterschiedliche Feldnamen fuer Wartungsplan-Eintraege
(betrieb/notiz vs. werkstatt/kosten) - als eigene Aufgabe geflaggt statt
hier mitgefixt.

tsc --noEmit sauber, 146/146 Tests, vite build erfolgreich. Nicht live
getestet (kein laufender companion-app-Dev-Server mit Backend-Zugang in
dieser Sitzung).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-08-28 10:31:10 +02:00
co-authored by Claude Sonnet 5
parent bfb7dec1e9
commit 2be6b99667
5 changed files with 368 additions and 43 deletions
+19
View File
@@ -16,6 +16,7 @@ export * from "./ablageNativ.ts";
import { DIENST_DOMAIN, ENTITAETEN } from "./types.ts";
import type {
AppVersionAngabe,
CsvImportErgebnis,
Fahrt,
Fahrzeugstatus,
ImportErgebnis,
@@ -304,4 +305,22 @@ export class DataMetricApi {
);
return { zustand: zustand.state, daten: zustand.attributes?.daten ?? {} };
}
/* --------------------------------------------------- CSV-Import
Wie historieImportieren() bewusst NICHT über die Warteschlange: eine
bewusste, einmalige Aktion, deren Ergebnis der eigentliche Zweck des
Aufrufs ist, kein Formularfeld, das man auch offline abschicken würde.
Anders als dort aber synchron im Backend (csv_import.py) - der
Dienstaufruf kehrt erst zurück, wenn sensor.audi_dashboard_import_status
den neuen Stand schon trägt, keine Wartezeit nötig. */
async csvImportieren(
art: "fahrten" | "tanken" | "service",
inhalt: string,
): Promise<CsvImportErgebnis> {
await this.rest.dienstAufrufen(DIENST_DOMAIN, "csv_importieren", { art, inhalt });
const zustand = await this.rest.zustandLesen<{ daten: CsvImportErgebnis }>(
ENTITAETEN.importStatus,
);
return { art, ...(zustand.attributes?.daten ?? {}) };
}
}
+11
View File
@@ -163,6 +163,17 @@ export interface ImportErgebnis {
meldung?: string;
}
/** Ergebnis eines CSV-Imports (custom_components/audi_dashboard/csv_import.py) -
dieselbe Entität wie ImportErgebnis (sensor.audi_dashboard_import_status),
aber eine andere Kennzahlform: Zeilenabgleich statt Fahrten/Tankvorgänge/
Batterie getrennt. */
export interface CsvImportErgebnis {
art?: string;
angelegt?: number;
aktualisiert?: number;
uebersprungen?: number;
}
/** Das OTA-Bündel, das die Integration mit ausliefert (siehe
custom_components/audi_dashboard/koordinator.py `_buendel_lesen()` und
companion-app/scripts/ota-paket.ps1). `null`, solange keine