waffensachkunde

Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.

/ app src shared sicherung.ts

6,0 KB Rohdatei
app/src/shared/sicherung.ts — 150 Zeilen
1 /**
2 * Was Anwendungskern und Oberfläche über eine Lernstandssicherung austauschen.
3 *
4 * Reine Typen, plattformfrei wie alles unter `shared/`. Die Arbeit selbst
5 * steht in `main/sicherung.ts` (Datei und Datenbank) und
6 * `main/sicherung-dialoge.ts` (Reihenfolge und Dialoge).
7 */
8
9 /**
10 * Was in einem einzelnen Profil steht.
11 *
12 * Nötig für die Verlustanzeige: Ein Vergleich der Gesamtzahlen sagt nichts.
13 * Wer hier zwei Profile mit zusammen 1.000 Antworten hat und die Datei eines
14 * enthält mit 1.200, sieht „mehr“ – und verliert trotzdem eines seiner beiden.
15 */
16 export interface Profilkennzahlen {
17 readonly name: string;
18 readonly antworten: number;
19 readonly gemerkt: number;
20 readonly pruefungslaeufe: number;
21 /** Zeitpunkt der jüngsten Antwort dieses Profils, oder `null`. */
22 readonly letzteAntwort: string | null;
23 }
24
25 /** Was in einer Datenbank steht – für die Rückfrage vor dem Ersetzen. */
26 export interface Kennzahlen {
27 readonly profilnamen: readonly string[];
28 /** Dieselben Profile, einzeln beziffert – Grundlage der Verlustanzeige. */
29 readonly jeProfil: readonly Profilkennzahlen[];
30 readonly antworten: number;
31 /** Zeitpunkt der jüngsten Antwort als ISO-Zeichenkette, oder `null`. */
32 readonly letzteAntwort: string | null;
33 readonly gemerkt: number;
34 readonly pruefungslaeufe: number;
35 /**
36 * Ein unterbrochener Prüfungsbogen liegt vor.
37 *
38 * Er wird beim Einspielen ersetzt wie alles andere – aber er ist das
39 * einzige, was sich nicht in einer Zahl ausdrücken lässt, und muss deshalb
40 * in der Rückfrage als Verlust benannt werden.
41 */
42 readonly offenerBogen: boolean;
43 readonly schemafassung: number;
44 }
45
46 export interface Sicherungsergebnis {
47 readonly gespeichert: boolean;
48 readonly pfad: string | null;
49 readonly bytes: number;
50 /**
51 * Kennung, unter der sich die Datei öffnen oder im Ordner zeigen lässt.
52 * Einzelheiten am gleichnamigen Feld in `shared/ipc.ts`.
53 */
54 readonly dateiKennung?: string;
55 }
56
57 export type Pruefergebnis =
58 | { readonly art: 'abgebrochen' }
59 | { readonly art: 'abgelehnt'; readonly grund: string }
60 | {
61 readonly art: 'brauchbar';
62 /** Kennung des Vorgangs; nur damit lässt sich einspielen. */
63 readonly vorgang: string;
64 /** Nur der blosse Dateiname, nie ein Pfad. */
65 readonly dateiname: string;
66 readonly ausDatei: Kennzahlen;
67 readonly jetzt: Kennzahlen;
68 };
69
70 export type Einspielergebnis =
71 | { readonly art: 'abgelaufen' }
72 | { readonly art: 'gescheitert'; readonly grund: string }
73 | {
74 readonly art: 'eingespielt';
75 /**
76 * Ob die Anzeige- und Vorleseeinstellungen mitgereist sind.
77 *
78 * `false` bei Sicherungen aus Fassung 0.26.7 und davor – die enthalten
79 * keine. Das ist kein Fehler, sondern der Normalfall der Vergangenheit,
80 * und die Karte sagt dann schlicht nichts dazu.
81 */
82 readonly einstellungenUebernommen: boolean;
83 readonly profilzahl: number;
84 /**
85 * Das erste Profil der eingespielten Datenbank.
86 *
87 * Die Oberfläche **muss** dorthin wechseln: `useLernstand.ts` hält die
88 * zuletzt gewählte Nummer in einem Ref, das ein Neuladen überlebt. Steht
89 * dort eine Nummer, die es in der eingespielten Datenbank zufällig auch
90 * gibt – bei Nummern ab 1 der Regelfall –, führte sie geradewegs in das
91 * Profil einer anderen Person.
92 */
93 readonly ersteProfilId: number;
94 /**
95 * **Verschiedene** Fragen mit mindestens einem Versuch – nicht Zeilen
96 * im Antwortprotokoll.
97 *
98 * Das Feld hieß bis Fassung 0.19.1 `antworten` und hielt trotzdem
99 * diese Zahl (`uebersicht.beantwortet`, gebildet über `versuche > 0`).
100 * In derselben Karte stand darüber „39 Antworten“ aus der
101 * Gegenüberstellung und darunter „24 bearbeitete Fragen“ – beides
102 * richtig, und trotzdem las es sich wie ein Widerspruch. Der Name war
103 * die Ursache, nicht die Anzeige.
104 *
105 * **Über alle Profile der Datei zusammen**, seit Fassung 0.24.2. Davor
106 * zählte nur das erste – die Meldung nannte „3 Profile“ und daneben die
107 * Zahl eines einzigen.
108 */
109 readonly bearbeiteteFragen: number;
110 /** Blosser Dateiname der selbsttätig angelegten Sicherheitskopie. */
111 readonly sicherheitskopie: string;
112 };
113
114 /**
115 * Ergebnis einer Profilübernahme.
116 *
117 * `profilId` ist die Nummer, die das dazugekommene Profil **hier** bekommen
118 * hat – die Oberfläche wechselt dorthin. `name` kann von dem in der Datei
119 * abweichen: Ein gleichnamiges Profil hier bleibt unberührt und behält
120 * seinen Namen, das neue bekommt einen Zusatz.
121 */
122 export type Uebernahmeergebnis =
123 | { readonly art: 'abgelaufen' }
124 | { readonly art: 'gescheitert'; readonly grund: string }
125 | {
126 readonly art: 'uebernommen';
127 readonly profilId: number;
128 readonly name: string;
129 /** Zeilen im Antwortprotokoll – Wiederholungen mitgezählt. */
130 readonly antworten: number;
131 /** **Verschiedene** Fragen, zu denen ein Stand übernommen wurde. */
132 readonly bearbeiteteFragen: number;
133 /** Blosser Dateiname der selbsttätig angelegten Sicherheitskopie. */
134 readonly sicherheitskopie: string;
135 /**
136 * Warnung, falls das Profil unter einem anderen Katalogstand gelernt
137 * wurde. `null`, wenn die Stände übereinstimmen oder die Quelle keinen
138 * führt (Sicherungen vor Schemafassung 9).
139 *
140 * **Warum das gemeldet und nicht verhindert wird.** Ein Lernstand aus
141 * einer älteren Fassung ist nicht wertlos: Die allermeisten Fragen gibt
142 * es weiterhin, und ihr Stand stimmt. Verwaist sind nur die Zeilen zu
143 * Fragen, die der neue Katalog nicht mehr kennt – dieselbe Lage, die
144 * der Lernstand beim Katalogwechsel auf diesem Rechner ohnehin behandelt
145 * (`Katalogwechsel`). Die Übernahme zu verweigern nähme dem Nutzer
146 * mehr, als sie ihm ersparte; ihm nichts zu sagen wäre die andere
147 * Unehrlichkeit.
148 */
149 readonly katalogstandDerQuelle: string | null;
150 };