waffensachkunde

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

/ app src shared sicherung.ts

4,8 KB Rohdatei
app/src/shared/sicherung.ts — 127 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 readonly profilzahl: number;
76 /**
77 * Das erste Profil der eingespielten Datenbank.
78 *
79 * Die Oberfläche **muss** dorthin wechseln: `useLernstand.ts` hält die
80 * zuletzt gewählte Nummer in einem Ref, das ein Neuladen überlebt. Steht
81 * dort eine Nummer, die es in der eingespielten Datenbank zufällig auch
82 * gibt – bei Nummern ab 1 der Regelfall –, führte sie geradewegs in das
83 * Profil einer anderen Person.
84 */
85 readonly ersteProfilId: number;
86 /**
87 * **Verschiedene** Fragen mit mindestens einem Versuch – nicht Zeilen
88 * im Antwortprotokoll.
89 *
90 * Das Feld hieß bis Fassung 0.19.1 `antworten` und hielt trotzdem
91 * diese Zahl (`uebersicht.beantwortet`, gebildet über `versuche > 0`).
92 * In derselben Karte stand darüber „39 Antworten“ aus der
93 * Gegenüberstellung und darunter „24 bearbeitete Fragen“ – beides
94 * richtig, und trotzdem las es sich wie ein Widerspruch. Der Name war
95 * die Ursache, nicht die Anzeige.
96 *
97 * **Über alle Profile der Datei zusammen**, seit Fassung 0.24.2. Davor
98 * zählte nur das erste – die Meldung nannte „3 Profile“ und daneben die
99 * Zahl eines einzigen.
100 */
101 readonly bearbeiteteFragen: number;
102 /** Blosser Dateiname der selbsttätig angelegten Sicherheitskopie. */
103 readonly sicherheitskopie: string;
104 };
105
106 /**
107 * Ergebnis einer Profilübernahme.
108 *
109 * `profilId` ist die Nummer, die das dazugekommene Profil **hier** bekommen
110 * hat – die Oberfläche wechselt dorthin. `name` kann von dem in der Datei
111 * abweichen: Ein gleichnamiges Profil hier bleibt unberührt und behält
112 * seinen Namen, das neue bekommt einen Zusatz.
113 */
114 export type Uebernahmeergebnis =
115 | { readonly art: 'abgelaufen' }
116 | { readonly art: 'gescheitert'; readonly grund: string }
117 | {
118 readonly art: 'uebernommen';
119 readonly profilId: number;
120 readonly name: string;
121 /** Zeilen im Antwortprotokoll – Wiederholungen mitgezählt. */
122 readonly antworten: number;
123 /** **Verschiedene** Fragen, zu denen ein Stand übernommen wurde. */
124 readonly bearbeiteteFragen: number;
125 /** Blosser Dateiname der selbsttätig angelegten Sicherheitskopie. */
126 readonly sicherheitskopie: string;
127 };