Versionsvergleich: nur eine neuere Fassung zaehlt
Nach dem Xcode-Lauf lief die App auf 2026.9.4.17, die Instanz auf 2026.9.4.5 - und die App bot an, sich auf .5 zu erneuern. Die Gleichheitspruefung konnte den Rueckschritt nicht sehen. versionOrdnung() sortiert jetzt Stelle fuer Stelle als Zahl, aber nur was dem Format JJJJ.M.T.N entspricht; sonst gibt es eine Abweichung ohne Richtung. Streifen, Startblatt und OTA-Knopf schlagen nur noch an, wenn die App nachweislich aelter ist. Damit ist die frueher dokumentierte Entscheidung "nur auf Gleichheit" umgedreht - Begruendung in VERSIONIERUNG.md und AGENTS.md Abschnitt CL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10477,3 +10477,100 @@ einer anderen Adresse steht, muss prozentkodiert werden - oder er gehoert dort n
|
||||
hin. Die frueheren, erfolgreichen Installationen liefen alle ueber die blanke
|
||||
Manifest-Adresse; der Zusatz kam am 04.09. dazu und ist seither nie durch eine
|
||||
gelungene Installation gegangen.
|
||||
|
||||
## CL. Der Versionsvergleich kennt jetzt eine Richtung (2026.9.4.19)
|
||||
|
||||
Gemeldet nach dem ersten Start der frisch installierten `.17`: „App laeuft auf
|
||||
4.17, bereit liegt 4.5. Sie kann sich direkt hier erneuern." Die reale Instanz
|
||||
stand noch auf `2026.9.4.5` - angeboten wurde also ein **Rueckschritt um zwoelf
|
||||
Fassungen**, der die Oberflaeche still auf den Stand vom Vormittag zurueckgedreht
|
||||
haette (ohne QR-Scanner, ohne Bestaetigungsblatt, ohne Debug-Bereich), waehrend
|
||||
die native Huelle auf `.17` geblieben waere. Danach haetten App und Server
|
||||
uebereingestimmt und die Meldung waere verschwunden - der Verlust also still.
|
||||
|
||||
**Die alte Pruefung konnte das nicht sehen**, und zwar folgerichtig: sie
|
||||
verglich nur auf Gleichheit. Das Buendel (`.5`) passte zur Serverfassung (`.5`)
|
||||
und war ungleich der laufenden (`.17`) - beide Bedingungen erfuellt, Knopf da.
|
||||
Dass `.5` **aelter** ist als `.17`, war ihr per Konstruktion unzugaenglich.
|
||||
|
||||
**Vorgabe des Eigentuemers:** erkannt wird eine neuere Fassung und keine andere.
|
||||
|
||||
### Eine dokumentierte Entscheidung wurde damit umgedreht
|
||||
|
||||
`appVersion.ts` und `VERSIONIERUNG.md` sagten bis hierher ausdruecklich das
|
||||
Gegenteil - „bewusst kein groesser/kleiner-Vergleich: die Version ist eine
|
||||
Kennung, keine Zahl. Ein Sortierversuch waere scheingenau und wuerde bei einem
|
||||
Formatwechsel still falsche Antworten geben." Beide Stellen sind umgeschrieben,
|
||||
nicht ergaenzt (Regel dieses Dokuments: ueberholte Regeln entfernen, nicht
|
||||
stapeln).
|
||||
|
||||
**Der Einwand von damals ist eingebaut, nicht verworfen:** `versionOrdnung()`
|
||||
sortiert ausschliesslich, was dem Format `JJJJ.M.T.N` entspricht - jede Stelle
|
||||
muss eine reine Ziffernfolge sein, geprueft mit einem Muster und **nicht** mit
|
||||
`parseInt`, das `4b` klaglos als 4 gelesen und damit genau die scheingenaue
|
||||
Antwort erzeugt haette. Passt eine Seite nicht ins Schema, kommt `null` zurueck:
|
||||
dann meldet die App eine Abweichung **ohne Richtung** und bietet nichts an.
|
||||
Verglichen wird Stelle fuer Stelle als Zahl - zeichenweise stuende `.17` vor
|
||||
`.5`, also genau der gemeldete Fall.
|
||||
|
||||
### Was sich wo aendert
|
||||
|
||||
| Lage | Streifen | Startblatt | OTA-Knopf |
|
||||
|---|---|---|---|
|
||||
| App aelter | „bitte aktualisieren" | ja | ja |
|
||||
| **App neuer** | **still** | **nein** | **nein** |
|
||||
| verschieden, nicht sortierbar | neutraler Hinweis | nein | nur bei Serveruebereinstimmung |
|
||||
| gleich / nicht vergleichbar | still | nein | nein |
|
||||
|
||||
`Versionsstand` heisst jetzt `gleich | aelter | neuer | abweichend | unbekannt`;
|
||||
`abweichend` bedeutet nur noch „verschieden, aber nicht sortierbar". Der Streifen
|
||||
meldet diesen Fall **neutral** statt zu schweigen - der Grundsatz „nie eine
|
||||
stille Veraltung" gilt auch dort, nur ohne eine Richtung zu behaupten, die nicht
|
||||
belegt ist.
|
||||
|
||||
`buendelPasst()` behaelt seine bisherigen Bedingungen und bekommt eine dritte:
|
||||
das Buendel muss **vorwaerts** gehen. Ist die Reihenfolge nicht bestimmbar, gilt
|
||||
weiter die alte Regel (nur Serveruebereinstimmung) - eine erfundene Reihenfolge
|
||||
waere schlechter als die Regel von vorher.
|
||||
|
||||
### Kein Panel-Gegenstueck, und das ist geprueft
|
||||
|
||||
Das Panel liest `APP_VERSION` an genau drei Stellen und **zeigt** sie nur an
|
||||
(`vEinst()`, Zeile 3417). Es vergleicht nichts und kennt kein OTA-Buendel - es
|
||||
laedt seine Dateien bei jedem Aufruf frisch und kann gar nicht veralten. Echte
|
||||
Ausnahme von der Paritaetsregel, kein stillschweigend ausgelassener Port.
|
||||
|
||||
### Verifiziert
|
||||
|
||||
`tsc --noEmit` sauber, **244 Tests** (von 225; 6 neue fuer `versionOrdnung()`,
|
||||
5 fuer den Rueckschritt in `buendelPasst()`, 2 fuer das Startblatt, dazu zwei
|
||||
geaenderte Erwartungen in `appVersion.test.ts` - die Richtungsangabe ist eine
|
||||
gewollte Verhaltensaenderung, kein Bruch). `vite build` sauber, Panel als Modul
|
||||
geparst, `audi_ha_test` auf `2026.9.4.19` sauber gestartet, kein Traceback.
|
||||
|
||||
**Gegen den alten Stand als fehlschlagend nachgewiesen:** mit ausgehaengter
|
||||
Reihenfolgepruefung fallen drei der neuen Tests um, darunter der gemeldete Fall
|
||||
wortwoertlich (`buendelPasst(.5, laeuft .17, Server .5)` liefert dann `true`).
|
||||
|
||||
**Live in allen drei Lagen**, ohne den Container anzufassen - dafuer bekam nur
|
||||
der Entwicklungsserver voruebergehend eine andere einkompilierte Nummer,
|
||||
waehrend die Instanz durchgehend auf `.19` stand:
|
||||
|
||||
| einkompiliert | Instanz | Streifen | Startblatt | OTA-Knopf |
|
||||
|---|---|---|---|---|
|
||||
| `.99` (App voraus) | `.19` | still | nein | **nicht vorhanden** |
|
||||
| `.18` (App zurueck) | `.19` | „aelter als der Server" | - | - |
|
||||
| `.19` (gleich) | `.19` | still | nein | nein |
|
||||
|
||||
Das Startblatt erscheint im Browser grundsaetzlich nicht (`otaMoeglich()`, nur
|
||||
nativ) - seine Entscheidung ist deshalb ueber `hinweisFaellig()` geprueft, nicht
|
||||
optisch. Das Manifest steht danach wieder auf `2026.9.4.19`, gleichauf mit dem
|
||||
Buendel (sha256 `58969a38…`).
|
||||
|
||||
### Was der Eigentuemer davon merkt
|
||||
|
||||
Die Meldung auf dem Telefon verschwindet nicht durch dieses Update - die App
|
||||
laeuft ja auf `.17` und bekommt `.19` erst, wenn die Instanz sie ausliefert. Der
|
||||
Weg bleibt: **erst die Integration auf der realen Instanz aktualisieren**
|
||||
(Einstellungen -> Version -> pruefen, installieren, neu starten), danach bietet
|
||||
die App den Schritt `.17` -> `.19` an, und der geht vorwaerts.
|
||||
|
||||
+24
-5
@@ -74,11 +74,30 @@ Der Vergleich läuft in eine Richtung: **die Integration sagt, welcher Stand
|
||||
installiert ist; die App sagt, welchen sie hat.** Stimmen sie nicht überein,
|
||||
ist die App zu alt (oder, seltener, die Integration).
|
||||
|
||||
Bewusst **nur auf Gleichheit**, nie größer/kleiner: die Version ist eine
|
||||
Kennung, keine Zahl. Ein Sortierversuch wäre scheingenau und würde bei einem
|
||||
Formatwechsel still falsche Antworten geben. Fehlt eine der beiden Seiten, wird
|
||||
gar nicht verglichen und nichts gemeldet — ein älteres Backend oder ein Start
|
||||
ohne Netz darf keinen Fehlalarm auslösen.
|
||||
**Verglichen wird der Reihe nach, nicht nur auf Gleichheit — geändert am
|
||||
04.09.2026.** Bis dahin galt hier ausdrücklich das Gegenteil (die Version sei
|
||||
eine Kennung und keine Zahl). Der Anlass war ein echter Fall: nach einem
|
||||
Xcode-Lauf lief die App auf `2026.9.4.17`, die Instanz stand noch auf
|
||||
`2026.9.4.5` — und die App bot an, sich auf `.5` zu erneuern. Ein Rückschritt um
|
||||
zwölf Fassungen, den eine Gleichheitsprüfung gar nicht sehen kann. Vorgabe des
|
||||
Eigentümers: **erkannt wird eine neuere Fassung und keine andere.**
|
||||
|
||||
Der damalige Einwand ist nicht verworfen, sondern eingebaut: sortiert wird nur,
|
||||
was dem Format `JJJJ.M.T.N` entspricht, und zwar Stelle für Stelle als Zahl —
|
||||
zeichenweise stünde `.17` vor `.5`. Passt eine Seite nicht ins Schema, gilt sie
|
||||
als **nicht sortierbar**; dann meldet die App eine Abweichung ohne Richtung und
|
||||
bietet nichts an, statt eine Reihenfolge zu erfinden. Fehlt eine der beiden
|
||||
Seiten ganz, wird gar nicht verglichen und nichts gemeldet — ein älteres Backend
|
||||
oder ein Start ohne Netz darf keinen Fehlalarm auslösen.
|
||||
|
||||
Daraus folgen vier Verhaltensweisen, entschieden in `src/daten/appVersion.ts`:
|
||||
|
||||
| Lage | Streifen | Startblatt | Update-Knopf |
|
||||
|---|---|---|---|
|
||||
| App älter als der Server | bitte aktualisieren | ja | ja |
|
||||
| App neuer (frisch signiert) | still | nein | **nein** |
|
||||
| verschieden, nicht sortierbar | neutraler Hinweis | nein | nur bei Serverübereinstimmung |
|
||||
| gleich / nicht vergleichbar | still | nein | nein |
|
||||
|
||||
## Was du tun musst
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
import { versionVergleichen } from "./appVersion"
|
||||
import { versionOrdnung, versionVergleichen } from "./appVersion"
|
||||
|
||||
/* Der Vergleich entscheidet, ob die App dem Nutzer sagt „ich bin älter als der
|
||||
Server". Beide Fehlrichtungen sind teuer: ein Fehlalarm schickt ihn grundlos
|
||||
@@ -12,9 +12,15 @@ describe("versionVergleichen", () => {
|
||||
expect(v.stand).toBe("gleich")
|
||||
})
|
||||
|
||||
it("meldet eine Abweichung, sobald die Zeichenketten sich unterscheiden", () => {
|
||||
expect(versionVergleichen("2026.08.23.1", "2026.08.24.1").stand).toBe("abweichend")
|
||||
expect(versionVergleichen("2026.08.23.2", "2026.08.23.1").stand).toBe("abweichend")
|
||||
it("nennt die Richtung, statt nur eine Abweichung zu melden", () => {
|
||||
expect(versionVergleichen("2026.08.23.1", "2026.08.24.1").stand).toBe("aelter")
|
||||
expect(versionVergleichen("2026.08.23.2", "2026.08.23.1").stand).toBe("neuer")
|
||||
})
|
||||
|
||||
it("meldet ohne erkennbares Format eine Abweichung ohne Richtung", () => {
|
||||
// Der Einwand, der bis zum 04.09.2026 GEGEN jede Sortierung sprach: bei
|
||||
// einem Formatwechsel darf nichts erfunden werden.
|
||||
expect(versionVergleichen("2026.8.23.1", "fruehling-2").stand).toBe("abweichend")
|
||||
})
|
||||
|
||||
it("vergleicht nicht, wenn das Backend nichts meldet", () => {
|
||||
@@ -38,3 +44,47 @@ describe("versionVergleichen", () => {
|
||||
expect(v.server).toBe("2026.08.24.1")
|
||||
})
|
||||
})
|
||||
|
||||
/* versionOrdnung() ist die Stelle, an der aus zwei Kennungen ein Vorher und
|
||||
ein Nachher wird. Sie entscheidet, ob der Update-Knopf erscheint - und ein
|
||||
Vorzeichenfehler hier böte einen Rückschritt an, wie am 04.09.2026 real
|
||||
geschehen (App .17, Instanz .5). */
|
||||
describe("versionOrdnung", () => {
|
||||
it("erkennt die letzte Stelle, auch zweistellig", () => {
|
||||
// Genau der gemeldete Fall: 5 gegen 17. Zeichenweise verglichen stuende
|
||||
// "17" vor "5" - deshalb wird je Stelle als Zahl verglichen.
|
||||
expect(versionOrdnung("2026.9.4.5", "2026.9.4.17")).toBe(-1)
|
||||
expect(versionOrdnung("2026.9.4.17", "2026.9.4.5")).toBe(1)
|
||||
})
|
||||
|
||||
it("vergleicht Stelle für Stelle von links", () => {
|
||||
expect(versionOrdnung("2026.8.31.9", "2026.9.1.1")).toBe(-1)
|
||||
expect(versionOrdnung("2026.9.1.1", "2025.12.31.9")).toBe(1)
|
||||
})
|
||||
|
||||
it("behandelt fehlende Stellen als Null", () => {
|
||||
expect(versionOrdnung("2026.9.4", "2026.9.4.0")).toBe(0)
|
||||
expect(versionOrdnung("2026.9.4", "2026.9.4.1")).toBe(-1)
|
||||
})
|
||||
|
||||
it("stoert sich nicht an fuehrenden Nullen", () => {
|
||||
expect(versionOrdnung("2026.08.23.1", "2026.8.23.1")).toBe(0)
|
||||
})
|
||||
|
||||
it("sortiert nicht, was nicht ins Format passt", () => {
|
||||
// parseInt haette "4b" klaglos als 4 gelesen - genau die scheingenaue
|
||||
// Antwort, die hier nicht entstehen darf.
|
||||
expect(versionOrdnung("2026.9.4b", "2026.9.5")).toBeNull()
|
||||
expect(versionOrdnung("v2026.9.4", "2026.9.5")).toBeNull()
|
||||
expect(versionOrdnung("2026..4", "2026.9.4")).toBeNull()
|
||||
})
|
||||
|
||||
it("nennt zeichengleiche Kennungen gleich, auch ohne lesbares Format", () => {
|
||||
expect(versionOrdnung("fruehling-2", "fruehling-2")).toBe(0)
|
||||
})
|
||||
|
||||
it("entscheidet nichts, wenn eine Seite fehlt", () => {
|
||||
expect(versionOrdnung(null, "2026.9.4.1")).toBeNull()
|
||||
expect(versionOrdnung("2026.9.4.1", "")).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,17 +7,30 @@
|
||||
* gebündelt und bleibt auf dem Stand vom Signieren — unbegrenzt und bisher
|
||||
* unbemerkt. Diese Datei macht daraus ein sichtbares Signal.
|
||||
*
|
||||
* Bewusst kein „größer/kleiner"-Vergleich: die Version ist eine Kennung
|
||||
* (`2026.8.23.2`), keine Zahl. Ein Sortierversuch wäre nur scheingenau und
|
||||
* würde bei einem Formatwechsel still falsche Antworten geben. Verglichen wird
|
||||
* auf Gleichheit — alles andere heißt „stimmt nicht überein", und was davon
|
||||
* älter ist, entscheidet der Mensch.
|
||||
* ENTSCHEIDUNG GEÄNDERT AM 04.09.2026 — vorher stand hier ausdrücklich
|
||||
* „bewusst kein größer/kleiner-Vergleich: die Version ist eine Kennung, keine
|
||||
* Zahl". Der Anlass war ein echter Fall: nach einem Xcode-Lauf lief die App
|
||||
* auf `2026.9.4.17`, die Instanz stand noch auf `2026.9.4.5` — und die App bot
|
||||
* an, sich auf `.5` zu „erneuern". Ein Rückschritt, den die Gleichheitsprüfung
|
||||
* gar nicht sehen konnte. Vorgabe des Eigentümers: erkannt werden soll eine
|
||||
* NEUERE Fassung und keine andere.
|
||||
*
|
||||
* Der damalige Einwand bleibt gültig und ist deshalb eingebaut, statt
|
||||
* verworfen: sortiert wird nur, was dem Format `JJJJ.M.T.N` entspricht. Passt
|
||||
* eine der beiden Zeichenketten nicht ins Schema (Formatwechsel), liefert der
|
||||
* Vergleich „abweichend" statt einer erfundenen Reihenfolge — dann sagt die
|
||||
* App, dass etwas nicht übereinstimmt, aber nicht, in welche Richtung.
|
||||
*/
|
||||
|
||||
export type Versionsstand =
|
||||
/** App und Backend melden denselben Stand. */
|
||||
| "gleich"
|
||||
/** Sie weichen ab — die App ist mit hoher Wahrscheinlichkeit älter. */
|
||||
/** Die App ist nachweislich älter — nur hier gibt es etwas zu holen. */
|
||||
| "aelter"
|
||||
/** Die App ist nachweislich neuer, etwa direkt nach einem Xcode-Lauf,
|
||||
solange die Instanz noch nicht nachgezogen hat. Kein Handlungsbedarf. */
|
||||
| "neuer"
|
||||
/** Verschieden, aber nicht in eine Reihenfolge zu bringen (Formatwechsel). */
|
||||
| "abweichend"
|
||||
/** Kein Vergleich möglich (Backend meldet nichts, offline, altes Backend). */
|
||||
| "unbekannt"
|
||||
@@ -36,10 +49,51 @@ export function eigeneVersion(): string | null {
|
||||
return typeof __APP_VERSION__ === "string" && __APP_VERSION__ ? __APP_VERSION__ : null
|
||||
}
|
||||
|
||||
/** Zerlegt `2026.9.4.17` in [2026, 9, 4, 17]. `null`, sobald ein Teil keine
|
||||
reine Ziffernfolge ist — dann wird nicht sortiert (siehe Modulkopf). */
|
||||
function teile(version: string): number[] | null {
|
||||
const stuecke = version.split(".")
|
||||
if (stuecke.length === 0) return null
|
||||
const zahlen: number[] = []
|
||||
for (const stueck of stuecke) {
|
||||
// Bewusst kein parseInt: das würde "4b" klaglos als 4 lesen und damit
|
||||
// genau die scheingenaue Sortierung erzeugen, vor der der Modulkopf warnt.
|
||||
if (!/^[0-9]+$/.test(stueck)) return null
|
||||
zahlen.push(Number(stueck))
|
||||
}
|
||||
return zahlen
|
||||
}
|
||||
|
||||
/**
|
||||
* `-1` wenn `a` älter ist als `b`, `0` bei Gleichstand, `+1` wenn `a` neuer
|
||||
* ist — und `null`, wenn sich das nicht entscheiden lässt.
|
||||
*
|
||||
* Fehlende Stellen zählen als 0, damit `2026.9.4` und `2026.9.4.0` denselben
|
||||
* Stand bezeichnen.
|
||||
*/
|
||||
export function versionOrdnung(a: string | null, b: string | null): number | null {
|
||||
if (!a || !b) return null
|
||||
// Zeichengleich ist gleich, auch wenn das Format unbekannt ist.
|
||||
if (a === b) return 0
|
||||
const links = teile(a)
|
||||
const rechts = teile(b)
|
||||
if (!links || !rechts) return null
|
||||
const laenge = Math.max(links.length, rechts.length)
|
||||
for (let i = 0; i < laenge; i++) {
|
||||
const l = links[i] ?? 0
|
||||
const r = rechts[i] ?? 0
|
||||
if (l !== r) return l < r ? -1 : 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
export function versionVergleichen(
|
||||
app: string | null,
|
||||
server: string | null,
|
||||
): Versionsvergleich {
|
||||
if (!app || !server) return { stand: "unbekannt", app, server }
|
||||
return { stand: app === server ? "gleich" : "abweichend", app, server }
|
||||
const ordnung = versionOrdnung(app, server)
|
||||
if (ordnung === null) return { stand: "abweichend", app, server }
|
||||
if (ordnung === 0) return { stand: "gleich", app, server }
|
||||
return { stand: ordnung < 0 ? "aelter" : "neuer", app, server }
|
||||
}
|
||||
|
||||
@@ -63,3 +63,42 @@ describe("buendelPasst", () => {
|
||||
expect(buendelPasst(buendel({ version: "2026.9.3.11" }), "2026.9.3.10", null)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
/* Der gemeldete Fall vom 04.09.2026: nach einem Xcode-Lauf lief die App auf
|
||||
2026.9.4.17, die Instanz stand noch auf 2026.9.4.5 - und bot an, sich auf
|
||||
.5 zu "erneuern". Das Bündel passte zur Serverfassung, war also nach der
|
||||
damaligen Prüfung in Ordnung; dass es ein Rückschritt ist, konnte sie nicht
|
||||
sehen. Vorgabe des Eigentümers: erkannt wird eine NEUERE Fassung, sonst
|
||||
keine. */
|
||||
describe("buendelPasst geht nur vorwaerts", () => {
|
||||
it("lehnt den gemeldeten Rueckschritt ab, obwohl das Buendel zum Server passt", () => {
|
||||
expect(
|
||||
buendelPasst(buendel({ version: "2026.9.4.5" }), "2026.9.4.17", "2026.9.4.5"),
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it("nimmt dieselbe Lage nach dem Nachziehen der Instanz an", () => {
|
||||
// Sobald die Integration auf .18 steht, geht es wieder vorwaerts.
|
||||
expect(
|
||||
buendelPasst(buendel({ version: "2026.9.4.18" }), "2026.9.4.17", "2026.9.4.18"),
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it("lehnt einen Rueckschritt auch ohne bekannte Serverfassung ab", () => {
|
||||
expect(buendelPasst(buendel({ version: "2026.9.4.5" }), "2026.9.4.17", null)).toBe(false)
|
||||
})
|
||||
|
||||
it("vergleicht die letzte Stelle als Zahl, nicht zeichenweise", () => {
|
||||
// "9" gegen "10": zeichenweise stuende "10" davor.
|
||||
expect(buendelPasst(buendel({ version: "2026.9.4.10" }), "2026.9.4.9", null)).toBe(true)
|
||||
expect(buendelPasst(buendel({ version: "2026.9.4.9" }), "2026.9.4.10", null)).toBe(false)
|
||||
})
|
||||
|
||||
it("bleibt beim alten Verhalten, wenn sich die Reihenfolge nicht bestimmen laesst", () => {
|
||||
// Formatwechsel: dann entscheidet weiterhin allein die Serverfassung -
|
||||
// eine Reihenfolge zu erfinden waere schlechter als die alte Regel.
|
||||
expect(buendelPasst(buendel({ version: "fruehling-3" }), "2026.9.4.17", "fruehling-3")).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -39,6 +39,7 @@ import { Capacitor } from "@capacitor/core"
|
||||
import { CapacitorUpdater } from "@capgo/capacitor-updater"
|
||||
|
||||
import type { Buendelangabe } from "../api"
|
||||
import { versionOrdnung } from "./appVersion"
|
||||
|
||||
/** Läuft die App in der nativen Hülle? Nur dort gibt es etwas auszutauschen —
|
||||
im Browser und im HA-Panel lädt ohnehin jeder Seitenaufruf den aktuellen
|
||||
@@ -83,12 +84,16 @@ export function buendelPasst(
|
||||
// Es muss etwas ANDERES sein als das, was gerade läuft - sonst gibt es
|
||||
// nichts zu holen.
|
||||
if (buendel.version === eigene) return false
|
||||
// Und es muss die Fassung sein, die diese Installation ausliefert. Der
|
||||
// Kommentar hier versprach das schon ("läge dort ein älteres, wäre ein
|
||||
// Update ein Rückschritt"), geprüft wurde es nie: ein blosses !== laesst
|
||||
// ein aelteres Buendel genauso durch wie ein neueres. Ohne bekannte
|
||||
// Serverfassung bleibt es beim alten Verhalten - ein Vergleich, den man
|
||||
// nicht anstellen kann, darf den Knopf nicht wegnehmen.
|
||||
// Und es muss VORWAERTS gehen. Am 04.09.2026 lief die App nach einem
|
||||
// Xcode-Lauf auf 2026.9.4.17, während die Instanz noch 2026.9.4.5
|
||||
// auslieferte - angeboten wurde ein Rückschritt auf .5, der die
|
||||
// Oberfläche still um zwölf Fassungen zurückgedreht hätte. Die
|
||||
// Gleichheitsprüfung konnte das nicht sehen; siehe appVersion.ts.
|
||||
const ordnung = versionOrdnung(buendel.version, eigene)
|
||||
if (ordnung !== null && ordnung <= 0) return false
|
||||
// Und es muss die Fassung sein, die diese Installation ausliefert. Ohne
|
||||
// bekannte Serverfassung bleibt es beim alten Verhalten - ein Vergleich,
|
||||
// den man nicht anstellen kann, darf den Knopf nicht wegnehmen.
|
||||
if (serverVersion == null) return true
|
||||
return buendel.version === serverVersion
|
||||
}
|
||||
|
||||
@@ -26,12 +26,21 @@ export function Hinweisleiste({
|
||||
// Derselbe Grundsatz wie beim Offline-Hinweis oben: keine stille Veraltung.
|
||||
// Nur hier veraltet nicht die Anzeige, sondern die App selbst — sie trägt
|
||||
// ihre Dateien fest gebündelt und merkt eine neuere Fassung sonst nie.
|
||||
const veraltet = versionsstand === "abweichend"
|
||||
//
|
||||
// "neuer" schlägt bewusst NICHT an: direkt nach einem Xcode-Lauf ist die
|
||||
// App der Instanz voraus, und daraus einen Handlungsbedarf zu machen
|
||||
// hiesse, den Nutzer zu einem Rückschritt zu drängen (siehe
|
||||
// daten/appVersion.ts). Nur bei einer nicht sortierbaren Abweichung wird
|
||||
// neutral gemeldet, statt eine Richtung zu behaupten - der Grundsatz
|
||||
// 'keine stille Veraltung' gilt auch dann.
|
||||
const veraltet = versionsstand === "aelter"
|
||||
const unklar = versionsstand === "abweichend"
|
||||
const versionshinweis = veraltet || unklar
|
||||
|
||||
// "verbindet" gleich beim Start nicht als Offline melden — das würde bei
|
||||
// jedem App-Start kurz aufblitzen.
|
||||
if (!offline && wartend === 0 && !veraltet) return null
|
||||
if (verbindung === "verbindet" && wartend === 0 && !veraltet) return null
|
||||
if (!offline && wartend === 0 && !versionshinweis) return null
|
||||
if (verbindung === "verbindet" && wartend === 0 && !versionshinweis) return null
|
||||
|
||||
const gescheitert = warteschlange.filter((a) => a.fehlversuche > 0).length
|
||||
|
||||
@@ -51,8 +60,9 @@ export function Hinweisleiste({
|
||||
: `${wartend} Änderungen warten auf Übertragung.`
|
||||
: null}
|
||||
{gescheitert > 0 ? ` ${gescheitert} davon mit Fehlversuchen.` : null}
|
||||
{veraltet && (offline || wartend > 0) ? " " : null}
|
||||
{versionshinweis && (offline || wartend > 0) ? " " : null}
|
||||
{veraltet ? "Diese App ist älter als der Server — bitte aktualisieren." : null}
|
||||
{unklar ? "App und Server melden verschiedene Fassungen." : null}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import { hinweisFaellig } from "./Versionshinweis"
|
||||
nie jemand erfährt. */
|
||||
describe("hinweisFaellig", () => {
|
||||
it("meldet, wenn App und Server auseinanderlaufen", () => {
|
||||
expect(hinweisFaellig("abweichend", "2026.9.3.3", null)).toBe(true)
|
||||
expect(hinweisFaellig("aelter", "2026.9.3.3", null)).toBe(true)
|
||||
})
|
||||
|
||||
it("schweigt bei gleichem Stand", () => {
|
||||
@@ -23,16 +23,31 @@ describe("hinweisFaellig", () => {
|
||||
})
|
||||
|
||||
it("schweigt ohne Serverfassung, auch wenn abweichend gemeldet wird", () => {
|
||||
expect(hinweisFaellig("abweichend", null, null)).toBe(false)
|
||||
expect(hinweisFaellig("aelter", null, null)).toBe(false)
|
||||
})
|
||||
|
||||
it("schweigt zur bereits weggetippten Fassung", () => {
|
||||
expect(hinweisFaellig("abweichend", "2026.9.3.3", "2026.9.3.3")).toBe(false)
|
||||
expect(hinweisFaellig("aelter", "2026.9.3.3", "2026.9.3.3")).toBe(false)
|
||||
})
|
||||
|
||||
it("meldet erneut, sobald eine andere Fassung bereitliegt", () => {
|
||||
// Der Kern der Merkfunktion: weggetippt gilt für genau eine Fassung,
|
||||
// nicht für "Updates" im Allgemeinen.
|
||||
expect(hinweisFaellig("abweichend", "2026.9.4.1", "2026.9.3.3")).toBe(true)
|
||||
expect(hinweisFaellig("aelter", "2026.9.4.1", "2026.9.3.3")).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
/* Nachgetragen am 04.09.2026: die App lief nach einem Xcode-Lauf auf
|
||||
2026.9.4.17, die Instanz stand auf 2026.9.4.5 - und das Blatt bot an, sich
|
||||
auf .5 zu "erneuern". Seither meldet nur noch "aelter". */
|
||||
describe("hinweisFaellig, wenn die App der Instanz voraus ist", () => {
|
||||
it("schweigt, wenn die App neuer ist als der Server", () => {
|
||||
expect(hinweisFaellig("neuer", "2026.9.4.5", null)).toBe(false)
|
||||
})
|
||||
|
||||
it("schweigt bei einer Abweichung ohne erkennbare Richtung", () => {
|
||||
// Formatwechsel: der Streifen meldet das neutral, ein eigenes Blatt waere
|
||||
// dafuer zu viel - und "bitte aktualisieren" waere nicht belegbar.
|
||||
expect(hinweisFaellig("abweichend", "gestern-3", null)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -56,7 +56,13 @@ export function hinweisFaellig(
|
||||
): boolean {
|
||||
// "unbekannt" heißt: kein Vergleich möglich (offline, altes Backend). Das
|
||||
// ist kein Grund für eine Meldung — genauso wenig wie "gleich".
|
||||
if (versionsstand !== "abweichend") return false
|
||||
//
|
||||
// Seit dem 04.09.2026 zählt nur noch "aelter". "neuer" tritt nach jedem
|
||||
// Xcode-Lauf auf, solange die Instanz noch nicht nachgezogen hat - dort
|
||||
// gibt es nichts zu holen, und die Meldung hätte zu einem Rückschritt
|
||||
// eingeladen. "abweichend" (nicht sortierbar) meldet der Streifen neutral,
|
||||
// ein eigenes Blatt wäre dafür zu viel.
|
||||
if (versionsstand !== "aelter") return false
|
||||
if (!serverVersion) return false
|
||||
return serverVersion !== gesehen
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":"2026.9.4.18","sha256":"d8b50e70f23ee796ac1618a94ee49893c202bed6139863e840fa76456b2694ca","bytes":322373,"gebaut":"2026-09-04T12:14:55Z"}
|
||||
{"version":"2026.9.4.19","sha256":"58969a387bfa72c3d452c04b689e8ec01440c9a2a89b7a097d43fe0418092ae6","bytes":322568,"gebaut":"2026-09-04T14:06:53Z"}
|
||||
Binary file not shown.
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "audi_dashboard",
|
||||
"name": "Audi Dashboard",
|
||||
"version": "2026.9.4.18",
|
||||
"version": "2026.9.4.19",
|
||||
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
|
||||
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
|
||||
"codeowners": [
|
||||
|
||||
Reference in New Issue
Block a user