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:
@@ -4096,6 +4096,57 @@ bumped `2026.8.28.1` → `.2` (initial popup) → `.3` (the race-condition fix -
|
||||
specifically to see this fix, since the panel JS is cache-busted by manifest version, not by content hash).
|
||||
`audi_ha_test` restarted at each step, confirmed clean via log every time.
|
||||
|
||||
## AD. Item 9 ported to companion-app (2026.8.28)
|
||||
|
||||
companion-app's starting layout differed from the panel's: no standalone "Fahrzeugprofil" tile existed at
|
||||
all (its "Sicherung" tile already bundled profile export together with the server-side backup trigger -
|
||||
`profilExportieren()` there actually downloads the combined `{profil, fahrten, tankvorgaenge}` bundle, the
|
||||
companion-app equivalent of the panel's separate, untouched "Backup" tile, not of "Fahrzeugprofil" - so
|
||||
"Sicherung" was correctly left alone). "Daten ausgeben" only exported Fahrten/Tankvorgänge (no Wartungsplan,
|
||||
no CSV import at all, no ID columns). Ported by turning "Daten ausgeben" into the same "Fahrzeugprofil" tile
|
||||
+ "Datensatz sichern"/"laden" popup the panel now has, reaching the same end state as the panel through a
|
||||
different starting layout - exactly what the parity rule asks for.
|
||||
|
||||
**The CSV column names had to be made byte-identical to the panel's** (`"ID"`, `"Start"`, `"Ende"`, `"km"`,
|
||||
etc.), not merely similar - the backend CSV parser (`csv_import.py`) is shared by both frontends and looks
|
||||
columns up by exact name. companion-app's own prior CSV export used different header text entirely
|
||||
("Beginn"/"Strecke km"/"Dauer s") - harmless before, since nothing ever read it back, but would have broken
|
||||
cross-frontend round-tripping (export from the panel, import into companion-app, or vice versa) had it been
|
||||
left as-is under a shared backend parser.
|
||||
|
||||
**Found a second real, pre-existing bug while doing this**: companion-app's `ServicebuchEintrag` type
|
||||
(`Service.tsx`) declares `betrieb`/`notiz`, but the actual backend list the panel writes to
|
||||
(`profil["service"]["buch"]`) uses `werkstatt`/`kosten`/`arbeiten` - no translation layer exists anywhere
|
||||
(`profilAdapter.ts` passes `service` through as an untyped `Record<string, unknown>`), so a Wartungsplan
|
||||
entry created in one codebase genuinely doesn't display correctly in the other (shows "Betrieb: —", no
|
||||
cost). Out of scope for this feature to fix properly - `DatensatzPopup.tsx`'s Wartungsplan CSV export reads
|
||||
the real field names via a documented `as Record<string, unknown>` cast (with an inline comment explaining
|
||||
why) rather than trusting the local, apparently-wrong type. Flagged as a separate background task
|
||||
(`task_7105e44c`) for a dedicated fix - decide the canonical field names (almost certainly the panel's, the
|
||||
older and more established convention), fix `ServicebuchEintrag` and `Service.tsx`'s read/write code, and
|
||||
simplify the CSV export's workaround cast once the type itself is correct.
|
||||
|
||||
New `src/screens/DatensatzPopup.tsx` (own file, mirrors `HistorienImport.tsx`'s shape/idiom: `Popup
|
||||
variant="form"`, own open/close/error/result state, an `aktiv` ref guarding against a state update after
|
||||
unmount). New `api.csvImportieren(art, inhalt)` (`api/index.ts`) - not queued, same reasoning as
|
||||
`historieImportieren()` (a deliberate one-off action, not a form field that should tolerate being offline).
|
||||
Fahrzeugprofil import reuses the existing `api.profilSchreiben(profil)` directly (NOT the `DatenKontext`
|
||||
convenience `profilSpeichern()`, which only merges partial `einstellungen`/`fahrzeug` fields - a loaded file
|
||||
needs to replace the whole profile, matching the panel's `profil_schreiben` semantics exactly), followed by
|
||||
`neuLaden()` to refresh derived state. `importStatusLesen()`/`zustandLesen()` fetch over REST, not a locally
|
||||
cached reactive object - so companion-app was never exposed to the race-condition class of bug the panel
|
||||
needed a dedicated fix for (see section AC) - confirmed structurally, not just assumed.
|
||||
|
||||
Also removed: a dead `dateiwahl` file-input ref in `Einstellungen.tsx` (declared, rendered, never wired to
|
||||
an `onChange` or `.click()` anywhere) - pre-existing, unrelated scaffolding, but sitting directly next to
|
||||
the new, functionally-equivalent file-input mechanism this change adds made it actively confusing to leave,
|
||||
so removed rather than merely noted.
|
||||
|
||||
Verified: `tsc --noEmit` clean, full suite green at 146/146 (including the "every page renders with sample
|
||||
data" smoke test, which covers `Einstellungen.tsx`), `vite build` succeeds. **Not live-verified** - no
|
||||
running companion-app session with backend auth this round, the same structural limitation noted repeatedly
|
||||
elsewhere in this file for companion-app-only changes.
|
||||
|
||||
---
|
||||
|
||||
## Working conventions (observed — keep them)
|
||||
|
||||
Reference in New Issue
Block a user