Skip to content

Frontend ​

Dateistruktur ​

Grafische Darstellung
text
frontend-project
├─ src
|  ├─ api
|  ├─ components
|  |  ├─ common
|  |  |  └─ buttons
|  |  |     └─ TheBaseRefreshButton.vue
|  |  └─ wahlvorstand
|  |     └─ TheWahlvorstandAnwesenheitRequirementCard.vue
|  ├─ composables
|  |  ├─ common
|  |  |   └─ formatter.ts
|  |  └─ wahlvorstand
|  |     └─ wahlvorstandService.ts
|  ├─ plugins
|  |     ├─ index.ts
|  |     ├─ pinia.ts
|  |     ├─ router.ts
|  |     └─ vuetify.ts
|  ├─ resources
|  |     └─ openapis
|  |        └─ openapi.broadcast.0.2.0.json
|  ├─ service-worker
|  |     └─ wahl-worker.ts
|  ├─ stores
|  |     └─ wahlvorstandStore.ts
|  ├─ types
|  |     └─ wahlvorstand
|  |        ├─ Wahlvorstand.ts
|  |        └─ WahlvorstandsMitglied.ts
|  └─ views
|     └─ WahlvorstandView.vue
├─ stories
|  └─ components
|     └─ wahlvorstand
|        └─ TheWahlvorstandAnwesenheitRequirementCard.stories.ts
└─ tests
   └─ components
      └─ wahlvorstand
         └─ TheWahlvorstandAnwesenheitRequirementCard.spec.ts

Das Frontend besteht für die Entwicklung aus 3 Komponenten, welche sich jeweils in einem Ordner auf der Rootebene wiederspiegeln.

KomponenteBeschreibung
srcDer Code der Anwendung mit allen Komponenten und Funktionen
testsTests zum Anwendungscode
storiesStories für StorybookJS zu den Komponenten der Anwendung

Anwendungscode ​

Der Anwendungscode besteht auf folgenden Ordnern:

OrdnerBeschreibung
api(generierte) Clients für den Zugriff auf die Backend-Services
componentsKomponenten die zur Verfügung stehen
composablesWiederverwendbarer Code
resources/openapiopenAPI Beschreibung die für die Clients verwendet werden
pluginsKonfiguration der verwendeten Plugins, z.B. Pinia, Router oder Vuetify
storeStores der Anwendung
service-workerInitialisierung und Routeregistrierung
typesEigenen Datentypen der Anwendung (Die Datentypen der Clients sind in api
viewsViews der Anwendung

Sofern es mehrere Elemente gibt, die zu unterschiedlichen fachlichen Domainen gehörten, kann es je Ordner verschiedene Unterordner geben.

common ... Elemente ohne spezifische fachliche Zugehörigkeit

<domain> ... Elemente mit spezifischer fachlicher Zugehörigkeit

Beispiel ​

components/common ... Enthält Komponenten, die überall zum Einsatz kommen können.

components/wahlvorstand ... Enthält Komponenten, die im Kontext vom Wahlvorstand zum Einsatz kommen

Tests und Stories ​

Die Tests und Stories bilden die gleiche Ordnerstruktur ab wie der jeweilige Testgegestand bzw. die Komponente der Stories.

Für die Komponte im Ordner src/components/wahlvorstand/TheWahlvorstandAnwesenheitRequirementCard.vue liegen die Tests in tests/components/wahlvorstand/TheWahlvorstandAnwesenheitRequirementCard.spec.ts und die Stories in stories/components/wahlvorstand/TheWahlvorstandAnwesenheitRequirementCard.stories.ts.

Bei den Tests zu Komponenten gibt es zusätzlich, parallel zu den Testfiles, einen Ordner __snapshots__. Dieser enthält die Referenzen für die Darstellung für Komponententest.

UI-Struktur ​

Das Frontend wird aus diversen Single-File-Components zusammengesetzt. Dabei verwenden wir Typescript und die Composition-API.

Layout ​

Grundlayout der WLS-Gui
Die Grundelemente des Wahllokalsystem UI

Das Wahllokalsystem UI besteht im Wesentlichen aus drei Komponenten.

Die app-bar stellt den Nutzer*innen grundlegende Informationen zu ihrem Wahlbezirk bereit. Die navigation umfasst die Navigationselemente der Seite, und die router-view zeigt den jeweils angeforderten Inhalt an.

router-view ​

Grundlayout der WLS-Gui

Die router-view ist eine Komponente von vueRouter, um die Darstellung je nach URL zu variieren. Meistens wird als dessen Inhalt das component-Element von Vue.js verwendet.

IMPORTANT

Wir verwenden keep-alive, um Daten einer View über den Wechsel hinaus zu behalten.

Im UI kann man zwischen den einzelnen Views relativ frei navigieren. Die Arbeit an einer View muss nicht beendet sein. Kehrt man später zu der View zurück, soll noch der Zustand vorhanden sein, der vorlag, als man die View verlassen hat.

Das lässt sich auf zwei Wegen erreichen. Zum einen kann man mit Stores arbeiten. Stores stellen einen anwendungsweiten Zustand dar.

Alternativ kann man eine View cachen, sodass beim Wechsel der View die alte nicht abgebaut wird. Wird eine View bei mehreren URLs verwendet, muss ein zusätzlicher Key definiert werden, damit unterschiedliche URLs unterschiedliche Views erhalten. Wir verwenden dafür den kompletten Pfad.

NOTE

Der zusätzliche Key wird auf der Komponente innerhalb von keep-alive über das Attribut key realisiert.

Beispiel eines Cachings

Für jede Wahl ist zu erfassen, wie viele Stimmzettel in der Wahlurne vorliegen. Dafür wurde eine View erstellt. Im Router wurde eine Route definiert, die unter anderem als Parameter die wahlID enthält. Nur durch diesen Parameter als Teil des Pfades ist es möglich, dass für die Wahl mit der ID-A eine andere gecachte Komponente verwendet wird als für die Wahl mit ID-B.

Durch die Verwendung der gecachten Komponenten erreichen wir, dass der letzte Bearbeitungszustand erhalten bleibt, können aber im Gegensatz zu Stores die View autonomer und weniger komplex entwickeln.

Aufbau von Views ​

Aufbau einer ViewÜbersicht der Arten von Elementen, die zur Erstellung einer View verwendet werden

Eine View stellt Informationen und Aktionen zu einem Thema bereit.

Dazu werden SingleInstance-Komponenten, also Komponenten, die nur einmal je View vorkommen sollen, verwendet. Diese setzen sich wiederum aus SingleInstance- oder Basis-Komponenten zusammen.

Views und SingleInstance-Komponenten können auf Stores zugreifen. Basis-Komponenten können das nicht. Die Views und die Komponenten können Composables verwenden. Basis-Komponenten können nur Rules- und Formatter-Composables verwenden.

Composable-TypAufgabenbeschreibung
RulesEnthält Validierungsregeln für Felder
FormatterFunktionen zur Anpassung der Darstellung eines Wertes. Dazu gehört auch die Umwandlung von Werten in Icons oder Farben
StoreModuleKapselt Teilfunktionalität eines Stores, um den Store klarer zu strukturieren
StateVerwaltet einen konkreten Zustand (z.B. Daten und ob diese gerade geladen werden), welcher aber im Gegensatz zu einem Store nicht global ist.
UtilsStellt Hilfsfunktionen für Komponenten mit komplexer Logik bereit
FetchServiceStellt Funktionen bereit um Daten aus dem Backend abzurufen. Hierzu zählt auch der Service Worker
ToolsStellt Funktionen für einen bestimmten Datentyp zur Verfügung
MapperStellt Funktionen bereit um von einem Datentyp in einen Anderen zu Mappen
ManagerKapselt weitere Funktionen und entscheidet im Rahmen der Verarbeitung, an wen die Anfrage delegiert wird
ServiceStellt allgemeine Funktionen zur Verfügung, die in keine andere Kategorie passen

Mapper-Composables können nur durch Utils- oder FetchService-Composables verwendet werden. Manager-Composables werden nur durch FetchService-Composables verwendet. StoreModule-Composables werden nur durch Stores verwendet.

Namenskonventionen

Es gibt einen separaten Abschnitt in den Namingkonventions welche beschreibt wie die Dateien zu den einzelnen Typen zu benennen sind.

Kommunikation ​

zwischen Komponenten ​

mit dem Backend ​

Ablauf Initiales Laden von Tasks ​

Das folgende Sequenzdiagramm beschreibt den Ablauf des initialen Ladens und Erstellens von Tasks:

Testkonzept ​

Unittesting ​

Funktionen, die in Composables, Stores und Datentypen enthalten sind, werden mit Unit-Tests abgedeckt. Die Kommunikation mit Funktionen anderer Module wird gemockt. Dabei ist die korrekte Interaktion mit dem Mock zu verifizieren.

Komponententests ​

Bei Komponententest wird die korrekte Darstellung (Rendering) und das Eventhandling verifiziert.

Die korrekte Darstellung wird mit Hilfe von Snapshots verifiziert.