# Documentation
Explication du fonctionnement, des bouts de codes clés, des concepts et de l'architecture de l'application Angular frontend.
## Architecture
Le projet est à un stade primitif mais certains choix d'architectures ont déjà été faits pour simplifier le développement et faciliter l'extension de l'application.
### Structure de page
Les pages sont stockées de manière statique dans une structure de pages.
Une page est un objet tel que présenté ci dessous.
```typescript=
import { SettingsTree } from "./settingstree";
export class Page
{
// Node above this page
parent: Page;
// Nodes below this page
children: Page[];
// Name of the page
name: string;
// Tag displayed in the infobar to easily identidy the page
tag: string;
// Dashboard menu, details of a machine, selection of a program,
// this property determines the global look and utility of a page
// by category
type: string;
// What machine is this page about (pavix, stemix etc)
data: string;
// What is the target level of this page, home page, islands etc
target: string;
// The id of the item that was selected in this page, so we
// know what to dynamically display in the children when
// its displayed (pavix X among pavix islands Y)
selected: number;
// Dynamically set depending on the parent's selected
// item to display in the navigation bar
displayName: string;
// Wether the edit button is visible
isEditable: boolean;
// The settings tree corresponding to this page
settings: SettingsTree;
constructor(parent: Page, name: string, tag: string,
type: string, data: string, target: string,
isEditable: boolean, settings: SettingsTree)
{
this.parent = parent;
this.children = [];
this.name = name;
this.tag = tag;
this.type = type;
this.data = data;
this.target = target;
this.isEditable = isEditable;
this.settings = settings;
this.selected = null;
this.displayName = "";
}
}
```
A noter que certaines propriétés comme isEditable ne sont pas encore implémentées dans le code.
La structure de pages est définie une seule fois au début du cycle de vie de l'application et restera statique. L'application naviguera dans l'arborescence grâce à un pointeur présent dans le service global ```globalService.ts``` de type ```Page```.

Lorsque un enfant est séléctionné dans le menu principal, on enregistre l'id de cet enfant dans la propriété "selected" et on change le pointeur de page pour le descendre d'un cran dans l'arborescence (vers cet enfant).
Lorsque la page affichera l'enfant, elle ira chercher dans les propriétés de son parent, quelle donnée était séléctionnée et pourra ainsi afficher du contenu en conséquence.
Par exemple si on click depuis "home" sur "Parc pavix" on s'attend à ne voir que des ilots pavix. Donc on stock "parc pavix" et on fait pointer l'application sur le premier enfant de "home", "parc", qui ira chercher dans son parent quel parc il doit afficher, entre autres pavix.
Les propritétés "type" "data" et "target" ne sont pas super claires rien qu'au niveau de leur nomenclature. Comme tout est fait dans une seule classe c'est facile de changer ça mais au niveua de la structure même, il est possible que les données stockées de soient pas totalement utiles ou qu'il faille changer ou optimiser ce bout de code.
La proprité "tag" est vitale et une des raisons principales du passages à la structure semi dynamique. Cependant il faudra l'implémenter aussi dans "settingsTree" afin d'afficher les tags à tout moment.
Le constructeur est gros mais il prend en compte tout le nécessaire à la création de la partie statique de la structure.
### Arbres à paramètres
Structure très similaire à "page" mais pour les settings. Légèrement simplifié car les settings n'ont pas encore été entièrement développés.
La propriété "link" sera utile pour rediriger l'utilisateur vers la bonne route. Le but étant de ne pas inclure les page sde settings dans l'arborescence de pages (pour ne pas faire un serpent qui se mord la queue) et d'avoir des routes individuelles pour ces pages, qui ne seront pas dans le dashboard du coup.
### Service global
En angular, un service permet de récupérer des données et de les transmettre facilement entre composants.
Comme nos pages sont composés de plusieurs composants et qu'ils n'ont pas tous de liens de parenté directs (comme par exemple le dashboard et la navbar qui sont frères et non parent/fille), il est plus simple de communiquer les informations à l'aide de services.
Cela permet aussi l'atomicité des informations comme chaque fois qu'une variable d'un service est changée, son changement et propagé à touts les membres observateurs.
Le service global sert de recueil de variables qui n'ont pas vraiment leur place ailleurs. Il permet d'avoir des repères globaux et gère la navigation sur toute l'application, ce qui est essentiel comme plusieurs composants en dépendent.
```typescript=
// Id of the currently targeted data
private targetId = new BehaviorSubject<number>(-1);
// Currently displayed page (always from the global page structure)
private page = new BehaviorSubject<Page>(null);
// Wether the navigation is in settings mode or not
private isInOption = new BehaviorSubject<boolean>(false);
// The location of the navigation in settings mode, represented
// by an array of index, each corresponding to the chosen
// child for each layer (array[0] is root layer)
private settingsLocation = new BehaviorSubject<number[]>([]);
// Not used yet, time at which we recieved the last poll from database
private lastPoll = new BehaviorSubject<Date>(null);
// Current langage (not implemented yet either)
private langage = new BehaviorSubject<string>("french");
```
Si un composant veut accéder aux variables d'un service il doit y être abonné comme ceci:
```typescript=
targetId: number;
ngOnInit()
{
this.globalService.currentTargetId.subscribe(targetId => this.targetId = targetId);
}
```
Et si le composant a besoin de faire quelque chose lorsque la variable du service change (a été changée depuis un autre composant) il doit implémenter la méthode next() et appeler une méthode de la classe avec \_this ou alors directement faire quelque chose dans la méthode next.
```typescript=
ngOnInit()
{
const _this = this;
const isInOption = this.globalService.currentIsInOption.subscribe(
{
next(isInOption)
{
_this.currentIsInOption = isInOption;
_this.doStuf();
// do stuff
}
});
}
doStuff(): void
{
// also doing stuff
}
```
Et enfin, pour changer la valeur d'une variable d'un service, il faut appeler la méthode du service comme ceci:
```typescript=
this.globalService.changePage(this.otherPage);
```
Le changement sera propagé par le service et toutes les méthodes next() liées à globalService.page seront appelées.
Ceci était un résumé de l'implémentation du service global, hors d'autres services du même type sont utilisés dans l'application comme le service de tri, qui garde en mémoire les valeurs par lesquelles ont souhaite trier les données. Il est très similaire donc je ne passerai pas en détails là dessus. Il est juste bon à savoir qu'il prend ses données dpeuis la toolbar component afin de déterminer comment trier quoi, puis le dashboard s'update automatiquement pour trier les données qu'il affiche.
### Services spécifiques à la base de donnée
L'autre utilisationd es services est l'abstraction de la relation avec la base de données. Toute l'application utilise le service de park pour aller chercher des données relatives aux parcs. L'implémentation de celui ci est indépendant de l'application et il fait office d'interface. Pour le moment il va lui même chercher ses données dans une tableau bidon écrit en dur. Lorsque la base de donnée et le backend seront disponibles, il suffira de modifier l'implémentations des fonctions de fetch de données dans les services respectifs et le reste de l'application ne sera pas à modifier du tout (à part pour l'ajout de champs éventuellement, les donnés bidons ont été simplifiés pour les tests).
### Structure de l'application
Chaque page se ressemble. Il ne s'agit en fait que de cacher et afficher les bon éléments aux bons moments. En temps normal la barre d'outils de tri est affichée en haut de l'écran, mais en mode settings elle disparait car on ne peut pas trier les settings.
Son affichage est géré par le service global et il en sera de même pour les autres composants. Certains auront leur visibilité dictée par la page actuelle qui peut par exemple avoir ou non une option "editable" ou encore "settings". Pour d'autres il serait peut être nécessaire de rajouter des variables au service global.
## Composants
L'application est découpée en composants ayant chacun un but précis. Je vais ici détailler les fonctionnalités de chacuns d'entre eux afin de documenter leurs développement.
### Dashboard
C'est en quelque sorte le composante principal. Il est au entre de la page et propose les menus d'options et la sélection de machines, parcs et autres composants à l'utilisateur. Il intéragit étroitement avec d'autres composants comme la barre d'outils pour le tri ou encore la bar de navigation, au travers les services respectifs.
Chaque changement de propriété de tri requiert un rafraichissement du dashboard, qui ira re-chercher ses données et les triera/filtrera en conséquence.
Le dashboard est capable d'afficher des composants tels que des machines, des parcs ou des ilots mais il peut aussi passer en mode settings. Dès lors il affichera les menus d'options et sera en lien avec la bar de navigation d'options pour mettre à jour son contenu.
En fait, il serait plus exact de dire que le dashboard est toujours en lien avec tous ces composants, mais il n'affiche que le nécessaire.
La fonction "refreshDashboard" s'occupe de cela et elle est rappellée à chaque fois que quelque chose change (souvent dans d'autres composants) afin de garder l'affichage à jour.
La fonction "sortData" permet de trier les données. Elle est un peu brut pour le moment puisque elle trie tout et pas seulement le nécessaire.
Les fonctions "clickOption" et "clickComponent" sont les fonctions appelées lorsque l'utilisateur click sur un menu respectivement soit dans un settings soit dans les composants eux-mêmes.
### Info bar
Ce composant permet d'afficher quelques informations qui sont toujours utiles à l'utilisateur, un peu à la manière d'une barre des tâches sur un smartphone. La barre d'info du terminal LINKiX a été légèrement modifiée pour mieux répondre aux besoins d'une application web en temps réel. Par exemple au lieu d'avoir indicateur de qualité de connexion on a un indicateur de durée depuis la dernière transmission de la base de données.
Cet indicateur n'est pas encore fonctionnel, pour le moment l'heure à laquelle la page à été créée est affichée, par la suite on comparera cette heure avec celle de la dernière mise à jour de la db pour évaluer la validité des données (si c'est quelques secondes c'est bien, si c'est quelques heures c'est pas bien).
L'affichage contient aussi le code unique de la page qui aide le SAV à situer le client lors d'un appel (par exemple WL003 qui est la page d'accueil).
La version de l'application est aussi affichée. Cette version est définie dans une fonction read only dans le service global.
On peut choisir la langue depuis la barre d'info. Pour le moment la variable est simplement updatée dans le service global mais aucune traduction n'a été faite pour le moment.
Il y a aussi un placeholder pour le nom de la personne connectée à l'application. Il faudra implémenter cette fonctionnalité lorsque le backend sera fonctionnel.
Finalement le dernier élément est un placeholder pour le logo VOH SA.
### Edit bar
Barre de boutons d'édition présente suivant les pages.
Pas encore implémenté.
### Edit panel
Fenêtre d'édition.
Pas encore implémenté.
### Machine detail
Page de détails de la machine.
Pour le moment à moitié implémenté.
### Navigation
Le composant de navigation est le conteneur de tout ce qui se rapporte à l'affichage de la localisation et de la navigation, que e soit dans l'application ou ses settings.
Le composant ne compte pour le moment que la barre de navigation et la barre de settings mais comprendra encore le bouton d'édition quand celui ci sera nécessaire (determiné par la structure de page).
#### Navigation bar
Affiche la localisation actuelle dans l'application et permet de naviguer en arrière (pour la navigation en avant il faut utiliser le dashboard).
Lors de changements de page il y a deux cas possibles, soit on descend dans l'arbre, soit on remonte vers la racine. Dans les deux cas la barre de navigation travaille.
Si on descend dans l'arbre, cela signifie que l'utilisateur a clické sur une carte dans le dashboard. le signal de changement de page sera transmis a la navbar et elle se mettra a jour en ajoutant la dernière page au stack de pages.
Dans le cas ou on remonte vers la racine, on peut remonter de 0 (c'est un inutile mais le bouton est là pour indiquer où on est) ou de 1 étage ou de plusieurs étage. Au maximum on remonte jusqu'à la racine.
Dans tous les cas, on commence par vérifier qu'on remonte de plus que 0, puis pour chaque étage on vérifie si on est à l'étage demandé, si ce n'est pas le cas on continue à remonter, tant que l'on est pas à la racine (ces deux conditions seront de toute manières remplies au même temps au plus tard).
#### Settings bar
La barre de navigation des paramètres joue exactement le même role que la barre de navigation, mais pour les paramètres.
C'est un peu différent car les paramètres sont propres à chaque page et sont régis par un object "settingsTree" mais le principe est exactement le même.
Comme l'implémentation des paramètres est légèrement différente de celle des pages de dashboard, l'implémentation de la barre de paramètre diffère également, mais le fonctionnement final est similaire.
A noter que la barre de settings à été implémentée en premier et qu'une fois certains concepts Angular intégrés, le développeur a refactorisé les pages afin de faire ressembler leur structure à celle des settings. Une dernière passe pour unifier ces deux concept peut être envisagée mais c'est deja du code relativement itérable sans difficulté.
### Tool bar
La barre d'outil n'est affichée que lorsqu'il y a des données à trier. (Donc pas lorsqu'on est dans le settings par exemple).
Elle communique en write only avec le service de tri. Ce même service communique avec le dashboard (dashboard en readonly) pour trier les données selon les critères spécifiés.
On peut trier par id, nom ou commentaire, puis rechercher avec la barre de recherche. Enfin, on peut trier par ordre croissant ou décroissant.
### Detail machine
Le composant sert a afficher et éditer certaines propriétés d'une machine.
Pour le moment il est en phase de développement. Les données mockup ont été adaptées et toutes les cases sont disponibles pour la pavix, il faudra encore certainement éditer ou enlever certains (ou rentre dynamique le formulaire) pour les autres machines
Bien que l'infrastructure soit en place, il est encore nécessaire de développer une partie des fonctionnalités pour l'édition des propriétés de machines (l'affichage, lui, est fonctionnel).
Un css élémentaire a été mis en place pour visualiser en gros le layout de la page.
## Futurs mises à jour
* Implémentation des composants manquants ou inachevés
* Détails machine
* Bouton d'édition
* Barre d'édition
* Reprendre la structure d'une barre de navigation
* Panel d'édition
* Assignation de programme
* Edition de programme
* Autres
* Eventuellement une passe d'uniformisation sur les settings et les pages
* Ajout nécessaires à la classe "page" suivant l'évolution de l'application
* Données
* Uniformisation des services de données.
* Eventuellement n'avoir qu'un seul data service pour les parks, les islands et les machines au lieu d'en avoir un chacun.
* Réécritures des services pour inclure le backend
* Backend
* Connexion utilisateur
* Stockage de données de machines