diff --git a/docs/#Project/Home.md b/docs/#Project/Home.md new file mode 100644 index 0000000..f10a985 --- /dev/null +++ b/docs/#Project/Home.md @@ -0,0 +1,20 @@ + +Bienvenue à la documentation du projet de SVGLayoutDesigner. + +Ici se trouve les documents qui explique en détail l'implémentation +des fonctionnalités du projet. + +Sélectionnez un lien ou un fichier pour lire la documentation + +Liens : + +- [Structure du projet](Pages/Project_Structure.md) +- [Structure des composants](Pages/ComponentStructure.drawio) (nécessite diagrams.net) +- [Dépendences du projet](Pages/Dependencies.md) +- [Structure de données des conteneurs](Pages/DataStructure.md) +- [Système de comportement](Pages/Behaviors.md) +- [Cycle de vie de l'application](Pages/Application.md) +- [Implémentation du menu contextuel](Pages/ContextMenu.md) +- [Web workers](Pages/WebWorkers.md) +- [Système de CI/CD](Pages/Behaviors.md) +- [Mise en place du SmartComponent sur Modeler](Pages/SmartComponent.md) diff --git a/docs/#Project/Pages/Application.md b/docs/#Project/Pages/Application.md new file mode 100644 index 0000000..cb731f3 --- /dev/null +++ b/docs/#Project/Pages/Application.md @@ -0,0 +1,179 @@ +# Cycle de vie de l'application + +# Menu principal + +Lorsque l'on lance l'application pour la première fois, +le premier composant qui s'affiche est `App.tsx`. + +En fonction de la valeur de `FAST_BOOT`, +il peut soit afficher un menu principal (composant `MainMenu`) si `FAST_BOOT=false` +ou soit afficher l'editeur directement (composant `Editor`). + +Lorsque le menu principal est affiché il y a 3 états : *Main*, *Load* ou *Loading*. + +Lorsqu'on est dans Main, nous avons les deux boutons principaux affiché : *Start from scratch* ou *Load* + +## Start from scratch + +Lorsque l'on clique sur *Start from scratch*, +l'action qui se fait est de charger une configuration depuis l'API +(ou d'utiliser une configuration préchargée via un event custom). +On passe à l'état *Loading*. + +Après chargement, `isLoaded` est `true` et le composant `Editor` est affiché. + +## Load + +Quand on veut charger un json, on clique sur *Load* et l'état passe à *Load*. + +Ici, le composant `MainMenu` affichera un bouton pour charger un fichier. +Charger le fichier change l'état de la configuration dans `App` +et active `isLoaded` qui enfin affiche `Editor`. + + +# Editor + +Lorsque `Editor` est affiché, +il reçoit en props la configuration que l'on a chargé au menu principal. + +Il reçoit également un historique par défaut pour avoir au moins quelque chose d'affiché. + +Il reçoit `root` un element HTML où l'on insert SVGLayoutDesigner par `main.tsx`. +`root` est utilisé pour lui donner des events qui seront utilisé pour communiquer avec le SmartComponent. + +Plusieurs sous-composant sont affichés ensuite. +Vous pouvez en savoir plus sur [la structure de composants](./ComponentStructure.drawio) +avec dragrams.net. + + +# Save and load + +Pour enregistrer le travail fait, il existe plusieurs méthode de le faire. + +## SmartComponent + +La première, en passant par le SmartComponent `svg-layout-designer.ts`, est de stringifier l'état de l'éditeur +et de le sauvegarder quelque part. + +On utilise `GetEditorAsString` pour obtenir une version stringifié du projet +que l'on peut ensuite sauvegarder dans un fichier, bdd ou autre. +On peut également utiliser GetEditorState et le sauvegarder tel quel dans le JS +mais on ne peut pas le stringifier à un object json ne peut pas avoir deux références +(sauf si on a le code source de saveload.ts, +utilisant un *replacer* éliminant les références circulaires, +voir [JSON par interaction](#json-par-interaction). + +Pour charger l'état de l'éditeur, il faut en premier le parser avec `JSON.parse` (pas de soucis à ce niveau là); +Enfin, on peut ensuite utiliser `LoadEditor` du SmartComponent pour charger l'état. + +`LoadEditor` est une macro de trois autres appels : +- `ReviveEditorState` qui fait revivre tous les doublons de références +- `SetEditor` qui charge la configuration de l'application +- `SetHistory` qui charge l'historique de l'editeur + +La raison que l'on utilise `SetHistory` en plus de `SetEditor` est parce que, +`SetEditor` ne fait que charger une configuration par défaut de `App.tsx` +(exemple: lorsque l'on crée un conteneur, l'éditeur va lire cette configuration). +Si l'application est déjà chargée, c'est-à-dire que *isLoaded* de `App` est `true`, +alors l'application ne va pas relire `history` et `historyCurrentStep` et l'application n'aura pas *chargé*. +C'est pourquoi on a besoin de `SetHistory` pour charger l'état courant dans `Editor.tsx` (à l'opposé de `App.tsx`). + +Note: Pour rappel, *App* n'est qu'un menu principal. +Comme dans un menu principal de jeu vidéo, +écraser une sauvegarde ne fait pas charger la sauvegarde. +C'est en chargeant la sauvegarde en cours de jeu ou dans le menu principal, +que la partie change. + + +## JSON par interaction + +On peut charger un fichier JSON manuellement. + +Pour cela il faut que `FAST_BOOT` de `default.ts` soit désactivé. + +Dans l'éditeur, on peut exporter une configuration par fichier JSON grâce au composant `Settings.tsx`. +Cette sauvegarde, comme pour sauvegarder avec le SmartComponent, utilise `JSON.stringify`. +Et donc utilise un *replacer* pour supprimer les dépendances circulaires. + +Ce *replacer* se trouve dans `worker.js` mais +un fallback est également donné dans `saveload.ts` +dans le cas où la fonctionnalité de Web Worker n'est pas supportée par le navigateur web. +Pour corriger des bugs sur la sauvegarde, il faudra donc modifier ces deux fichiers. + +Décrivons rapidement ce qu'elle fait : + +```typescript +export function GetCircularReplacer(): (key: any, value: object | Map | null) => object | null | undefined { + return (key: any, value: object | null) => { + if (key === 'parent') { + return; + } + + if (key === 'containers') { + return Array.from((value as Map).entries()); + } + + if (key === 'symbols') { + return Array.from((value as Map).entries()); + } + + if (key === 'linkedContainers') { + return Array.from(value as Set); + } + + return value; + }; +} +``` + +Nous faisons les actions suivantes pour supprimer les types non supportés par le stringify : +- nous transformons les *Map* `containers` et `symbols` en tableau de vecteur clés-valeurs +- nous transformons les *Set* `linkedContainers` en tableau de clés. + +Nous supprimons toutes les références de `parent` qui sont déjà référencés dans `containers`. + +Enfin, nous retournons `value` si tout est bon. + +Normalement, le JSON retourné ressemble à l'objet qu'était EditorState +mais sans les références de parent et avec des tableaux partout. + + +Pour le charger, il faut revenir au menu principal et +cliquer sur Load pour charger avec l'input. + +Charger le fichier JSON, utilisera ce qu'on appelle un *reviver* +qui s'occupe de recréer les types non supportés par JSON et de remettre les références dupliquées. + +Ce reviver se trouve dans `saveload.ts` avec la fonction `Revive()`. + +`Revive` change la valeur de `historyCurrentStep` avec de faire revivre l'historique + +`ReviveHistory` itère sur chaque état de `history` pour les revivre. + +`ReviveState` fait revivre en premier les *Map* et les *Set*. +Ensuite, il va itérer sur tous les conteneurs existants, +pour remettre leur parent. + +Comme vous pouvez vous en douter cette algorithme coûte O(n) juste pour revivre les parents. +avec *n* le nombre total de conteneurs sur toute la durée de vie de l'application. +Surtout qu'il n'est plus très utile depuis que tous les conteneurs sont dans une hash *Map* +(et que donc parent est accessible avec un coût O(1)). + +On pourrait juste utiliser `GetContainerById` au lieu de la référence. + + +## JSON par requête GET HTTP + +Pour charger un JSON via HTTP GET, +il faut que le serveur web distant autorise notre domaine +dans le méchanisme *cross-origin resource sharing (CORS)* +et qu'il nous autorise à faire des requêtes *GET*. + +Après cela pour charger le JSON, +il faut que l'url de SVGLayoutDesigner soit paramétrée avec l'url de la resource : + +``` +http://localhost:5173/?state=http://other-server.com/state.json +``` + +Après cela, l'éditeur chargera directement le fichier. diff --git a/docs/Behaviors.md b/docs/#Project/Pages/Behaviors.md similarity index 95% rename from docs/Behaviors.md rename to docs/#Project/Pages/Behaviors.md index 57b5905..47ce155 100644 --- a/docs/Behaviors.md +++ b/docs/#Project/Pages/Behaviors.md @@ -1,3 +1,16 @@ +> TL;DR +> Behaviors.ts définis les comportements qui sont utilisés. + +> Actuellement sont activés par défaut : +> - Corps rigide (simple) : Est restraint dans le parent +> - Ancrage : Impose la priorité de position et de taille +> - Flex : se redimensionne automatiquement + +> Désactivés: +> - Corps rigide (complet) : Est restraint par les parents et par ses voisins (fonctionne mais pas intuitif) +> - Poussé : quand un conteneur est ajouté au bout de la bande filante, pousse tous les conteneurs à sa gauche (fonctionne mais pas intuitif) +> - Swap : échange de place avec un autre conteneur lorsqu'ils sont superposés (buggué ne pas utiliser) + # Comportements des conteneurs Ce document traite des comportements spéciaux et uniques qu'un conteneur peut avoir. @@ -21,8 +34,6 @@ Cependant, il a une règle commune pour tout comportement qui s'applique à ses Il s'agit d'appliquer les comportements spéciaux de ses enfants (rigide ou ancré). -Traduit avec www.DeepL.com/Translator (version gratuite) - ## Applications @@ -37,11 +48,10 @@ An example would be trying to overlap an element in order to use it as a layer. ## Références de code et algorithmes -Dans le module `PropertiesOperations.ts` dans les fonctions suivantes : +Dans le module `ContainerOperations.ts` dans les fonctions suivantes : - `OnPropertyChange()` -- `OnPropertiesSubmit()` -et dans le module `ContainerOperation.ts` dans `AddContainer()`, +et dans le module `AddContainer.ts` dans `AddContainer()`, il utilise la fonction `ApplyBehaviors` du module `Behaviors.ts` pour appliquer les comportements spéciaux de ses enfants. @@ -168,8 +178,6 @@ Nous avons initialement tout l'espace disponible : laissez `space` être cet esp Pour simplifier l'algorithme lors de l'ajout d'un conteneur, comparons cela à manger une bûche de Noël. -![buche](./assets/yule-log-cake.jpg) - Comme pour le gâteau, il faut le couper et en prendre une part. Il y a 5 façons possibles de le couper : diff --git a/docs/CICD.md b/docs/#Project/Pages/CICD.md similarity index 94% rename from docs/CICD.md rename to docs/#Project/Pages/CICD.md index 4aee2bf..55b74db 100644 --- a/docs/CICD.md +++ b/docs/#Project/Pages/CICD.md @@ -5,7 +5,7 @@ This project uses Azure Pipelines to runs automatic tests. Its `azure-pipelines.yml` configuration file can be found at the root project folder. -# Drone.io +# Drone.io (deprecated) Due to the limitations of Azure Pipelines (limited free usage, no parallel, no dockerhub...), it might be more useful to use Drone.io. However `pnpm` will not be as useful as in Azure Pipelines since we cannot cache on the parent machine. diff --git a/docs/ComponentStructure.drawio b/docs/#Project/Pages/ComponentStructure.drawio similarity index 100% rename from docs/ComponentStructure.drawio rename to docs/#Project/Pages/ComponentStructure.drawio diff --git a/docs/#Project/Pages/ContextMenu.md b/docs/#Project/Pages/ContextMenu.md new file mode 100644 index 0000000..2e5420b --- /dev/null +++ b/docs/#Project/Pages/ContextMenu.md @@ -0,0 +1,55 @@ +> TL;DR: Menu.tsx est le composant qui affiche et qui traite l'event contextmenu sur la page +> InitActions de Editor.tsx prépare le modèle pour Menu.tsx +> ContextMenuActions définient les actions de l'API + +# Context Menu + +Ce document présente comment le menu contextuel est implémenté. + + +# Event listener + +Pour implémenter le menu contextuel, il faut en premier ajouter un event listener sur `contextmenu`. + +Cela se fait dans le composant `Menu.tsx` via la fonction `UseMouseEvents()`. + +Elle équipe plusieurs events sur la page en plus de `contextmenu` afin de fermer correctement lorsque l'on clique ailleurs. + +Il n'existe donc qu'un seul menu contextuel pour toute la page. + + +# Affichage du contenu + +On a vu que `Menu.tsx` s'occupe de traiter l'event `contextmenu`. Regardons maintenant comment elle affiche le menu. + +Ce composant utilise une hashmap `actions: Map` pour lire les différentes actions possible, la clé servant d'identifiant et de pattern. + +En effet, la fonction `AddClassSpecificActions`, obtenant le composant html lit les *classes* et vérifie s'il est présent dans le dictionnaire avec `props.actions.get(className)`. + +S'il est présent, alors on itère sur les différentes actions possible pour cette classe pour ajouter des `MenuItem` représentant une ligne du menu contextuel. Chaque `MenuItem` possède un fonction qui sera exécutée lorsque la ligne est cliquée. Il possède également un texte, un titre qui sera affiché si le curseur survole la ligne, et, optionnellement, un raccourci qui sera affiché à droite de la ligne. + +En plus des actions de classes, il y a aussi des actions universelles comme le `undo` ou `redo` qui sont affichées n'importe où on clique. Celle-ci ont pour id `''`, une chaine de caractères vide. On itère sur cette liste d'action pour ajouter les lignes. + +L'ordre d'affichage est donc défini : + +1) actions de classes +2) actions universelles + +L'ordre des classes est l'ordre d'ajout dans le dictionnaire. + + +# Création du dictionnaire + +Parlons de l'initialisation du dictionnaire. + +Le composant `Menu` est utilisé dans `Editor`. C'est aussi ici que l'ont crée le dictionnaire. + +La fonction `InitActions` s'occupe d'enrichîr le dictionnaire des différentes actions. + +On peut voir qu'au début de la fonction que les actions universelles y sont initialisées. Ensuite, les actions spécifiques aux classes y sont ajoutés avec au début les actions définies dans SVGLayoutDesigner et après, les actions définies dans la configuration de l'API (donc `Diviser remplissage par exemple`). + +Chaque action provenant de l'API utilise la fonction `GetAction` du fichier utilitaire `ContextMenuActions.ts`. + +Cette fonction équipe l'action qui sera exécutée d'une autre fonction appelé `SetContainerList`. Cette autre fonction s'occupe de faire un appel REST vers l'api sur le point d'accès `Configuration.APIConfiguration.apiSetContainerListUrl` ou, si elle n'est pas définie, sur `VITE_API_SET_CONTAINER_LIST_URL`. + +Cela veut dire que pour l'instant toutes les actions provenant de l'API a pour but de remplacer, d'ajouter ou de supprimer des conteneurs. \ No newline at end of file diff --git a/docs/DataStructure.md b/docs/#Project/Pages/DataStructure.md similarity index 98% rename from docs/DataStructure.md rename to docs/#Project/Pages/DataStructure.md index b04f245..1c57864 100644 --- a/docs/DataStructure.md +++ b/docs/#Project/Pages/DataStructure.md @@ -1,3 +1,6 @@ + +> TL;DR: Ce projet utilise un dictionnaire pour représenter un arbre/graphe + # Préface Ce document explique la structure de données utilisée pour les conteneurs. @@ -40,7 +43,7 @@ B: Node = { Donc le graphe est simplement `A <-> B` -Ceci est un graphe cyclique que nous ne verrons pas souvent dans ce projet. +Ceci est un graphe cyclique que nous ne verrons pas souvent dans ce projet. En effet, nous avons plutôt quelque chose comme ça: ``` diff --git a/docs/Dependencies.md b/docs/#Project/Pages/Dependencies.md similarity index 100% rename from docs/Dependencies.md rename to docs/#Project/Pages/Dependencies.md diff --git a/docs/Project_Structure.md b/docs/#Project/Pages/Project_Structure.md similarity index 100% rename from docs/Project_Structure.md rename to docs/#Project/Pages/Project_Structure.md diff --git a/docs/DevDocs/Pages/SmartComponent.md b/docs/#Project/Pages/SmartComponent.md similarity index 86% rename from docs/DevDocs/Pages/SmartComponent.md rename to docs/#Project/Pages/SmartComponent.md index e632da8..07c880c 100644 --- a/docs/DevDocs/Pages/SmartComponent.md +++ b/docs/#Project/Pages/SmartComponent.md @@ -1,3 +1,5 @@ +Source: https://dev.azure.com/techformsa/SmartConfigurator/_wiki?pageId=122&friendlyName=Int%C3%A9grer-le-projet-en-tant-que-composant-dans-Modeler# + - [Préface](#préface) - [Customiser et build le projet (recommandé)](#customiser-et-build-le-projet-(recommandé)) * [Configurer les options de build](#configurer-les-options-de-build) @@ -74,29 +76,6 @@ Cliquez sur le menu hamburger et cliquez sur **Download Artifacts** : - Puis copier les fichiers de build dans le dossier. (copiez l'entièreté du dossier `dist` ou extrayez le zip selon la méthode). -- Modifiez le fichier `index.html` du composant pour changer les chemins absolus en relatifs: - -```diff - - - - - - - - Vite + React + TS -- -+ -- -+ - - -
- - - -``` - - Si **besoin**, modifier le fichier `smartcomponent/svg-layout-designer.html` pour avoir la bonne url relative à la basename de l'url : ```diff diff --git a/docs/#Project/Pages/WebWorkers.md b/docs/#Project/Pages/WebWorkers.md new file mode 100644 index 0000000..6b42c0f --- /dev/null +++ b/docs/#Project/Pages/WebWorkers.md @@ -0,0 +1,38 @@ +# Web workers + +Cette page explique la raison d'utiliser un web worker. + + +# Qu'est-ce qu'un web worker ? + +Rapidement, c'est juste un fichier js qui est exécuté côté dans un Thread différent. + +Il attend un réponse, la traite et peut répondre ensuite. + + +# Pourquoi en utiliser ? + +Cela permet du véritable code asynchrone évitant le freeze du navigateur lorsqu'il fait des calculs compliqués ou lorsqu'il attend. + +Exemple: https://mdn.github.io/dom-examples/web-workers/fibonacci-worker/ + + +# Comment sont-ils utilisés ? + +## Sauvegarde + +Le premier web worker, situé dans [`public/workers/worker.js`](../../../public/workers/worker.js) s'occupe de faire une seule est unique tâche : `JSON.stringify` cependant on fonction de la taille de l'objet à stringifier en JSON cela peut prendre plusieurs secondes auquel cas l'utilisateur peut croire que son navigateur à bloqué. + +On le met donc dans un web worker pour éviter cela. + +Dans `Save.ts`, on crée le web worker avec `new Worker('workers/worker.js')` et on le termine quand il a fini sa tache avec `terminate()` + +## Envois de message + +Le deuxième web worker, situé dans [`public/workers/worker.js`](../../../public/workers/message_worker.js) s'occupe de faire des appels REST en stringifiant l'état de l'application. + +Pour la même raison que la sauvegarde, on le met pour éviter un freeze. + +Il est évidemment moins utile que la sauvegarde qui prends un objet beaucoup plus lourd. + +Contrairement à la sauvegarde, le web worker est crée dans `UI.tsx` avec `UseWorker()` et existe sur tout le long de la durée de vie de l'application. Il est initialisé dans l'utilisation du module `UseWorker.tsx`. \ No newline at end of file diff --git a/docs/Eric BF/01_141017-WG-11328-SYME-VERNUCCI-DET BF ind A.pdf b/docs/Documents/01_141017-WG-11328-SYME-VERNUCCI-DET BF ind A.pdf similarity index 100% rename from docs/Eric BF/01_141017-WG-11328-SYME-VERNUCCI-DET BF ind A.pdf rename to docs/Documents/01_141017-WG-11328-SYME-VERNUCCI-DET BF ind A.pdf diff --git a/docs/Eric BF/02_141017-WG-11328-SYME-VERNUCCI-DET BF ind B.pdf b/docs/Documents/02_141017-WG-11328-SYME-VERNUCCI-DET BF ind B.pdf similarity index 100% rename from docs/Eric BF/02_141017-WG-11328-SYME-VERNUCCI-DET BF ind B.pdf rename to docs/Documents/02_141017-WG-11328-SYME-VERNUCCI-DET BF ind B.pdf diff --git a/docs/Eric BF/03_SYME KLINE cde BV.pdf b/docs/Documents/03_SYME KLINE cde BV.pdf similarity index 100% rename from docs/Eric BF/03_SYME KLINE cde BV.pdf rename to docs/Documents/03_SYME KLINE cde BV.pdf diff --git a/docs/Eric BF/04_ARC KL_K1485985-ARC-K1485985.pdf b/docs/Documents/04_ARC KL_K1485985-ARC-K1485985.pdf similarity index 100% rename from docs/Eric BF/04_ARC KL_K1485985-ARC-K1485985.pdf rename to docs/Documents/04_ARC KL_K1485985-ARC-K1485985.pdf diff --git a/docs/Eric BF/05_DT_K1485985.pdf b/docs/Documents/05_DT_K1485985.pdf similarity index 100% rename from docs/Eric BF/05_DT_K1485985.pdf rename to docs/Documents/05_DT_K1485985.pdf diff --git a/docs/Eric BF/06_ Photo IMG_1406.jpg b/docs/Documents/06_ Photo IMG_1406.jpg similarity index 100% rename from docs/Eric BF/06_ Photo IMG_1406.jpg rename to docs/Documents/06_ Photo IMG_1406.jpg diff --git a/docs/Eric BF/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.dwg b/docs/Documents/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.dwg similarity index 100% rename from docs/Eric BF/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.dwg rename to docs/Documents/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.dwg diff --git a/docs/Eric BF/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.pdf b/docs/Documents/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.pdf similarity index 100% rename from docs/Eric BF/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.pdf rename to docs/Documents/131421 KALIA - 15541 - PARVIS DE RODE - D0371837 - BANDE FILANTE PLAN 01 à 07 -IND B.pdf diff --git a/docs/Eric BF/image0000001.jpg b/docs/Documents/image0000001.jpg similarity index 100% rename from docs/Eric BF/image0000001.jpg rename to docs/Documents/image0000001.jpg diff --git a/docs/DevDocs/Home.md b/docs/Tutorial/Home.md similarity index 78% rename from docs/DevDocs/Home.md rename to docs/Tutorial/Home.md index b29d664..f90ca70 100644 --- a/docs/DevDocs/Home.md +++ b/docs/Tutorial/Home.md @@ -1,5 +1,5 @@ -Bienvenue à la documentation développeur de SVGLayoutDesigner. +Bienvenue au tutoriel de SVGLayoutDesigner. Cette documentation a pour objectif de familiariser les nouveaux développeur aux outils du projet et à apprendre à développer des composants sous React. diff --git a/docs/DevDocs/Pages/BasesReact.md b/docs/Tutorial/Pages/BasesReact.md similarity index 100% rename from docs/DevDocs/Pages/BasesReact.md rename to docs/Tutorial/Pages/BasesReact.md diff --git a/docs/DevDocs/Pages/Heroicon.md b/docs/Tutorial/Pages/Heroicon.md similarity index 100% rename from docs/DevDocs/Pages/Heroicon.md rename to docs/Tutorial/Pages/Heroicon.md diff --git a/docs/DevDocs/Pages/PourCommencer.md b/docs/Tutorial/Pages/PourCommencer.md similarity index 100% rename from docs/DevDocs/Pages/PourCommencer.md rename to docs/Tutorial/Pages/PourCommencer.md diff --git a/docs/DevDocs/Pages/PremierComposantReact.md b/docs/Tutorial/Pages/PremierComposantReact.md similarity index 100% rename from docs/DevDocs/Pages/PremierComposantReact.md rename to docs/Tutorial/Pages/PremierComposantReact.md diff --git a/docs/DevDocs/Pages/Tailwind.md b/docs/Tutorial/Pages/Tailwind.md similarity index 100% rename from docs/DevDocs/Pages/Tailwind.md rename to docs/Tutorial/Pages/Tailwind.md diff --git a/docs/assets/yule-log-cake.jpg b/docs/assets/yule-log-cake.jpg deleted file mode 100644 index 79d2165..0000000 --- a/docs/assets/yule-log-cake.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:348ffea20dbd9b2a499dc84e0ddfb7d7220c91980ab7840c36847f6eedd18d6d -size 187625 diff --git a/public/workers/worker.js b/public/workers/worker.js index 11246a0..a933fc2 100644 --- a/public/workers/worker.js +++ b/public/workers/worker.js @@ -10,11 +10,13 @@ const getCircularReplacer = () => { } if (key === 'containers') { - return Array.from(value.entries()); + return [...value.entries()] + .map(([Key, Value]) => ({ Key, Value })); } if (key === 'symbols') { - return Array.from(value.entries()); + return [...value.entries()] + .map(([Key, Value]) => ({ Key, Value })); } if (key === 'linkedContainers') { diff --git a/src/Components/API/api.ts b/src/Components/API/api.ts index 6d5ac3b..fd91133 100644 --- a/src/Components/API/api.ts +++ b/src/Components/API/api.ts @@ -1,7 +1,7 @@ import { IConfiguration } from '../../Interfaces/IConfiguration'; import { ISetContainerListRequest } from '../../Interfaces/ISetContainerListRequest'; import { ISetContainerListResponse } from '../../Interfaces/ISetContainerListResponse'; -import { GetCircularReplacerToDotnet } from '../../utils/saveload'; +import { GetCircularReplacer } from '../../utils/saveload'; /** * Fetch the configuration from the API @@ -35,7 +35,7 @@ export async function FetchConfiguration(): Promise { export async function SetContainerList(request: ISetContainerListRequest, configurationUrl?: string): Promise { const url = configurationUrl ?? import.meta.env.VITE_API_SET_CONTAINER_LIST_URL; - const dataParsed = JSON.stringify(request, GetCircularReplacerToDotnet()); + const dataParsed = JSON.stringify(request, GetCircularReplacer()); // The test library cannot use the Fetch API // @ts-expect-error // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions diff --git a/src/Components/Messages/Messages.tsx b/src/Components/Messages/Messages.tsx index 9e04670..4fe95ce 100644 --- a/src/Components/Messages/Messages.tsx +++ b/src/Components/Messages/Messages.tsx @@ -5,7 +5,7 @@ import { MessageType } from '../../Enums/MessageType'; import { IHistoryState } from '../../Interfaces/IHistoryState'; import { IMessage } from '../../Interfaces/IMessage'; import { DISABLE_API } from '../../utils/default'; -import { GetCircularReplacerToDotnet } from '../../utils/saveload'; +import { GetCircularReplacer } from '../../utils/saveload'; import { TITLE_BAR_HEIGHT } from '../Sidebar/Sidebar'; interface IMessagesProps { diff --git a/src/Components/UI/UseWorker.tsx b/src/Components/UI/UseWorker.tsx index 7a6a8f0..c231f07 100644 --- a/src/Components/UI/UseWorker.tsx +++ b/src/Components/UI/UseWorker.tsx @@ -3,7 +3,7 @@ import { IHistoryState } from '../../Interfaces/IHistoryState'; import { IGetFeedbackRequest } from '../../Interfaces/IGetFeedbackRequest'; import { IGetFeedbackResponse } from '../../Interfaces/IGetFeedbackResponse'; import { IMessage } from '../../Interfaces/IMessage'; -import { GetCircularReplacerToDotnet } from '../../utils/saveload'; +import { GetCircularReplacer } from '../../utils/saveload'; // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions const myWorker = window.Worker && new Worker('workers/message_worker.js'); @@ -38,7 +38,7 @@ export function UseAsync( // eslint-disable-next-line @typescript-eslint/naming-convention ApplicationState: state }; - const dataParsed = JSON.stringify(request, GetCircularReplacerToDotnet()); + const dataParsed = JSON.stringify(request, GetCircularReplacer()); fetch(import.meta.env.VITE_API_GET_FEEDBACK_URL, { method: 'POST', headers: new Headers({ diff --git a/src/Events/EditorEvents.ts b/src/Events/EditorEvents.ts index aa90c79..c572bda 100644 --- a/src/Events/EditorEvents.ts +++ b/src/Events/EditorEvents.ts @@ -54,7 +54,6 @@ function SetHistory(root: Element | Document, eventInitDict?: CustomEventInit): void { const history: IHistoryState[] = eventInitDict?.detail.history; const historyCurrentStep: number | undefined = eventInitDict?.detail.historyCurrentStep; - ReviveHistoryAction(history); setNewHistory(history, historyCurrentStep); const customEvent = new CustomEvent('setHistory', { detail: editorState }); root.dispatchEvent(customEvent); diff --git a/src/Interfaces/IContainerModel.ts b/src/Interfaces/IContainerModel.ts index ff24d67..8e38efa 100644 --- a/src/Interfaces/IContainerModel.ts +++ b/src/Interfaces/IContainerModel.ts @@ -2,6 +2,8 @@ import { IContainerProperties } from './IContainerProperties'; export interface IContainerModel { children: string[] + // TODO: Remove parent now that accessing the parent by id is faster. + // TODO: Use GetContainerById(container.properties.parentId) as the better alternative. parent: IContainerModel | null properties: IContainerProperties userData: Record @@ -13,6 +15,8 @@ export interface IContainerModel { */ export class ContainerModel implements IContainerModel { public children: string[]; + // TODO: Remove parent now that accessing the parent by id is faster. + // TODO: Use GetContainerById(container.properties.parentId) as the better alternative. public parent: IContainerModel | null; public properties: IContainerProperties; public userData: Record; diff --git a/src/utils/saveload.ts b/src/utils/saveload.ts index 7250500..5033fab 100644 --- a/src/utils/saveload.ts +++ b/src/utils/saveload.ts @@ -1,6 +1,8 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { FindContainerById, MakeDFSIterator } from './itertools'; import { IEditorState } from '../Interfaces/IEditorState'; import { IHistoryState } from '../Interfaces/IHistoryState'; +import { IContainerModel } from '../Interfaces/IContainerModel'; /** * Revive the Editor state @@ -32,7 +34,9 @@ export function ReviveState(state: IHistoryState): void { for (const symbol of state.symbols.values()) { symbol.linkedContainers = new Set(symbol.linkedContainers); } - state.containers = new Map(state.containers); + + const containers: Array<{ Key: string, Value: IContainerModel }> = (state.containers) as any; + state.containers = new Map(containers.map(({ Key, Value }: {Key: string, Value: IContainerModel}) => [Key, Value])); const root = FindContainerById(state.containers, state.mainContainer); @@ -40,6 +44,8 @@ export function ReviveState(state: IHistoryState): void { return; } + // TODO: remove parent and remove this bloc of code + // TODO: See IContainerModel.ts for more detail const it = MakeDFSIterator(root, state.containers); for (const container of it) { const parentId = container.properties.parentId; @@ -62,43 +68,13 @@ export function GetCircularReplacer(): (key: any, value: object | Map).entries()); + return [...(value as Map).entries()] + .map(([Key, Value]: [string, any]) => ({ Key, Value })); } if (key === 'symbols') { - return Array.from((value as Map).entries()); - } - - if (key === 'linkedContainers') { - return Array.from(value as Set); - } - - return value; - }; -} - -export function GetCircularReplacerToDotnet(): (key: any, value: object | Map | null) => object | null | undefined { - return (key: any, value: object | null) => { - if (key === 'parent') { - return; - } - - if (key === 'containers') { - return [...(value as Map).entries()].map((keyPair: [string, any]) => { - return { - Key: keyPair[0], - Value: keyPair[1] - }; - }); - } - - if (key === 'symbols') { - return [...(value as Map).entries()].map((keyPair: [string, any]) => { - return { - Key: keyPair[0], - Value: keyPair[1] - }; - }); + return [...(value as Map).entries()] + .map(([Key, Value]: [string, any]) => ({ Key, Value })); } if (key === 'linkedContainers') { diff --git a/vite.config.ts b/vite.config.ts index f4b4d95..3df6f17 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,5 +5,6 @@ import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [ react() - ] + ], + base: './' });