Browse Source

V8-3568 - analyse structurelle

Olivier Massot 3 years ago
parent
commit
499933c0e9
1 changed files with 344 additions and 0 deletions
  1. 344 0
      doc/analyse_082022.md

+ 344 - 0
doc/analyse_082022.md

@@ -0,0 +1,344 @@
+# Analyse - 09/2022
+
+## Workflow du traitement de données
+
+Etude du workflow des pages `pages/organization/index.vue` et `pages/organization/address/*`
+
+### Entités
+
+#### Get
+
+##### Via UiCollection
+
+> Exemple : l'affichage des adresses sur la fiche de la structure
+
+La page intègre le component `UiCollection`, qui prend en paramètres :
+
+* la query (récupérée depuis le repo)
+* le modèle de l'entity concernée
+* le modèle d'origine (ici Organization)
+* l'id d'origine (celui de l'orga)
+
+L'`UiCollection` récupère la méthode `getCollection` de `useDataUtils` (à qui elle a passé le `dataProvider`)
+
+Elle appelle ensuite cette méthode et récupère le `fetchState` et les items sous forme de ref
+
+Enfin, elle passe les items à son slot, qui les utilise pour afficher les données
+
+
+##### Via UiItemFromUri
+
+> Exemple : l'affichage du pays dans le détail des adresses de la fiche de la structure
+
+Extrait l'id de l'Uri
+
+utilise le `useFetch` natif de nuxt en lui passant en callback un appel à `$dataProvider.invoke`
+
+L'item est ensuite retourné sous forme d'une ComputedRef qui retourne elle-même `queryHelper.getItem`
+
+
+##### Via UiDataTable
+
+Prend en paramètres :
+
+* la query (récupérée depuis le repo)
+* le modèle de l'entity concernée
+* le modèle depuis lequel il est modifié
+* l'id du modèle depuis lequel il est modifié
+
+Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
+
+
+##### UiLayoutAlertBarCotisation
+
+Récupère l'état des cotisations avec un `useFetch` auquel on passe en callback un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+##### Composable useCountryProvider
+
+Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
+
+##### Composable useTypeOfPracticeProvider
+
+Utilise `useFetch` en lui passant en callback un appel à `$dataProvider.invoke(type: QUERY_TYPE.MODEL, ...)`
+
+
+
+#### Create
+
+##### Page `entity/new.vue`
+
+Passe le `$dataProvider` à `useDataUtils` qui retourne la méthode `createItem`
+
+Passe le store et le type d'entité à la méthode `createItem` qui retourne une fonction `create` et deux refs : `loading` (bool) et `item` (Model).
+La méthode `createItem` commit aussi le type du formulaire (`FORM_STATUS.CREATE`), et met le loading à true
+
+Côté client seulement: instancie une nouvelle Entité, et la passe à la méthode `create` qui la persist dans le repository
+
+La page inclut ensuite un component FormXxxx correspondant au type d'entité.
+
+##### Component FormXxxx
+
+Peut utiliser des composables pour retourner des données complémentaires (ex: listes déroulantes). Il récupère alors le dataProvider depuis
+le context pour le passer aux méthodes du composable.
+
+Récupère le repo propre à l'entité via `repositoryHelper.getRepository(Xxxxx)`
+
+Génère une query depuis le repo, déclare éventuellement les relations à charger au passage
+
+Génère une méthode `submitActions` qui retourne une liste d'actions caractérisées par : type d'action (cf. `SUBMIT_TYPE`) et adresse à laquelle se rendre après l'action
+
+Inclut le composant générique UiForm et lui passe l'`id`, le `model`, la `query`, les `submitActions`
+
+
+##### Component UiForm
+
+Importe via des methodes de composables :
+
+* `$dataPersister` et `store`
+* `router`
+* `markAsDirty`, `markAsNotDirty`, `readonly`, `nextStepFactory`
+
+Créé un store de type `Page`
+Créé une ref null nommée `form`
+
+Construit une computed ref `entry` qui sera passée au slot (le FormXxxx). Cette ref doit récupérer l'entrée du repo via `queryHelper.getFlattenEntry(query.value, id.value)`
+
+Construit la méthode `updateRepository` qui sera aussi passée au slot. Cette méthode invoque la méthode `markAsDirty()` qui met à jour le store Form pour le déclarer en dirty, maj la valeur du champs de l'entité correspondante et persist le tout dans le repo.
+
+Créé une méthode `validate` qui utilise la méthode du même nom du v-form (natif de vuetify)
+
+
+Créé une méthode `submit` qui reçoit un argument `next` (type de l'action exécutée):
+
+* Appelle la méthode `validate`
+* Si le formulaire est valide :
+  * Appelles la méthode `$dataPersister.invoke` et récupère la réponse
+  * ajoutes une alerte de type Success au store de la page
+  * appelles la méthode nextStep en lui passant l'argument `next`, qui est donc le type de l'action exécutée
+* Sinon :
+  * Ajoutes des alertes au store de la page et à un nouveau store de type Form (pqoi?)
+
+Créé la méthode `nextStep`, qui appelles la méthode `nextStepFactory` de `useForm`. Cette méthode associe les types d'actions à des callbacks appellant des méthodes de `useForm` (`save`, `sageAndGoto`). Exécute ensuite le callback retourné. Ces deux callbacks ne font qu'appeller le router pour rediriger vers la page suivante.
+
+Créé des méthodes `showDialog` et `closeDialog` qui mettent à jour le store générique
+
+Créé enfin une méthode `saveAndQuit` qui :
+
+* appelle la méthode `submit`
+* devrait appeller la méthode `quitForm` (voir plus bas), mais sauf erreur, le router a déjà été appellé par la méthode `submit`...
+
+Lorsqu'on quitte le formulaire, la boite de dialogue s'affiche et propose trois options : `back_to_form`, `save_and_quit`, `quit_form`
+
+Un clic sur le bouton `back_to_form` du formulaire appelle la méthode `closeDialog` qui ferme la boite de dialogue.
+
+Un clic sur le bouton `save_and_quit` du formulaire appelle la méthode `saveAndQuit` (voir au dessus)
+
+Un clic sur le bouton `quit_form` du formulaire appelle la méthode `quitForm`, qui à son tour:
+* appelles la méthode markAsNotDirty()
+* confirme dans le store la volonté de quitter
+* remet le store dans son état original
+
+
+
+##### Component FormXxxx (à nouveau)
+
+Le formulaire reçoit de UiForm la ref `entry` et la méthode `updateRepository`
+
+L'entry correspond à l'entité dans le store telle que récupérée via le repo
+
+`updateRepository` sera appellée par chaque input qui sont mis à jour
+
+
+
+#### Edit
+
+
+##### Page `entity/_id.vue`
+
+Idem *create*, excepté que le formulaire est inclus dans une page `entity/_id.vue`
+
+Passe le `$dataProvider` à `useDataUtils` qui retourne la méthode `getItemToEdit`
+
+Parse l'id de l'entité à éditer directement depuis l'url
+
+Passe l'id et le type d'entité à la méthode `getItemToEdit` qui appelle la méthode `$dataProvider.invoke` et retourne une ref `fetchState`.
+
+
+##### Composable useMyProfile
+
+Propose une méthode pour maj le profile via `$dataPersister.invoke({type: QUERY_TYPE.MODEL, ...})`
+
+
+#### Delete
+
+##### Via UiButtonDelete
+
+Appelle directement `$dataDeleter.invoke`
+
+
+
+
+#### Cas particulier : UiLayoutHeaderNotification
+
+Récupère les notifs depuis l'api via un useFetch avec un callback à `await $dataProvider.invoke({type: QUERY_TYPE.ENUM, enumType})`
+
+Récupère ensuite les notifs depuis le store sous forme de computed ref
+
+
+
+
+### Enums
+
+#### Get
+
+##### Via UiInputEnum
+
+Récupère l'enum via un useFetch avec un callback à `await $dataProvider.invoke({type: QUERY_TYPE.ENUM, enumType})`
+
+Lorsque les notifications ont été lues, créé un nouvel objet NotificationUser en :
+
+* mettant à jour le store avec `repositoryHelper.persist`
+* l'api avec `$dataPersister.invoke(type: QUERY_TYPE.MODEL, ...)`
+
+
+
+
+### Images
+
+#### Get
+
+##### Via UiImage
+
+Récupère l'image grâce à la méthode `getOne` du composable `useImageProvider` (à qui on a passé le data provider et la config du context)
+
+`getOne` appelle un dataProvider avec le type `QUERY_TYPE.IMAGE` et lui passe les arguments de config de l'image (id, hauteur, largeur)
+En cas d'erreur, retourne une image par défaut.
+
+
+##### Via UiInputImage
+
+Si un id a été passé aux props, récupère l'objet File via un useFetch avec un
+callback à `await $dataProvider.invoke({type: QUERY_TYPE.DEFAULT, url: 'api/files', id: props.existingImageId })`
+
+On récupère ensuite l'image grâce à la méthode `getOne` du composable `useImageProvider` (à qui on a passé le data provider et la config du context)
+
+`getOne` appelle un dataProvider avec le type `QUERY_TYPE.IMAGE` et lui passe les arguments de config de l'image (id, hauteur, largeur)
+En cas d'erreur, retourne une image par défaut.
+
+#### Put
+
+##### Via UiInputImage
+
+Met à jour le store avec `repositoryHelper.persist`
+
+Envoie la requête de maj du File avec `$dataPersister.invoke(type: QUERY_TYPE.MODEL, ...)`
+
+#### Post
+
+##### Via UiInputImage
+
+Créé un nouvel objet File à sauvegarder
+
+L'envoie à l'API avec `$dataPersister.invoke(type: QUERY_TYPE.FILE, ...)`
+
+
+### Api externes ou routes custom
+
+#### UiInputAutocompleteWithApi
+
+Appelle `useFetch` en lui passant le callback `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+#### UiTemplateMobytStatus
+
+Appelle `useFetch` en lui passant le callback `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+#### UiMap
+
+Appelle la route `/api/gps-coordinate-searching` via un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+#### Composable useAccessesProvider
+
+Appelle la route `/api/access_people` via un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+#### Composable useAddressPostalUtils
+
+Appelle la route `https://api-adresse.data.gouv.fr/search/...` via un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+#### Composable useValidator
+
+Appelle la route `/api/siret-checking` via un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+ou
+
+Appelle la route `/api/subdomains` via un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+#### Page subscription
+
+Appelle la route `/api/dolibarr/account/` via un appel à `$dataProvider.invoke({type: QUERY_TYPE.DEFAULT, ...})`
+
+
+## Propositions
+
+### Notes diverses
+
+##### Stores
+
+* faire un store 'appState', renommer form en formState? renommer page en pageState?
+* utiliser des interfaces pour le state des stores : https://pinia.vuejs.org/core-concepts/state.html#typescript (déja fait a priori)
+* j'ai l'impression que les dialogs ne sont pas gérés depuis le store "page", ce serait ptêt pas mal?
+
+##### Pinia
+
+* utiliser les hooks pinia pour répercuter les maj sur l'api? >> https://pinia-orm.codedredd.de/guide/model/lifecycle-hooks
+
+
+##### Data managers
+
+* je pense qu'on devrait sortir le `$nuxt.$loading.start()` du service baseDataManager, c'est pas trop à sa place ici
+* le data deleter ne passe pas par un data processor pour mettre à jour le store. mais est-ce nécessaire au final?
+* est-ce qu'on devrait pas choisir soit de récupérer les données dans des composables (ex: useTypeOfPracticeProvider, useCountryProvider), soit dans les components? si on maintient les composables, on pourrait
+  les mettre dans un sous-dossier? ou même factoriser la méthode?
+
+
+##### Forms
+
+* passer le create et le loader de la page Address/new dans le formulaire? faire la même chose partout?
+* `const entryCopy = query.value.first()` dabs `useForm` (L185): on pourrait peut-être factoriser ça dans un composable? au passage, v-form a une méthode `reset`, ça pourrait ptêt faire le job?
+* UiForm, methode `saveAndQuit`: est-ce qu'on passe dans la méthode `quitForm` au final? puisque la méthode nextStep appellée depuis submit a déjà dû faire la redirection?
+* page address/_id, ligne 18 : on ne pourrait pas faire mieux pour le `const id = parseInt(route.value.params.id)`? faire ça en amont? dans un service? ou carrément parser les paramètres directement depuis un middleware et les stocker dans un store dédié en lecture seule?
+* plutôt que d'instancier une entité dans la page et de la passer au form, est-ce qu'on ne passerait pas un param 'create' au form? il faudrait lever des erreurs si `create == true & id != null` ou `create == false & id == null`
+* comment imposer des propriétés à tous les FormXxxx? Serait-il possible de mettre en place une interface pour l'array props, et de la tester depuis UiForm?
+* useError, ligne 7 : je suppose que la docstring est pas la bonne?
+
+##### Actions des forms
+
+* `actions[SUBMIT_TYPE.SAVE] = { path: `/organization/address/` }` : un moyen de rendre plus explicite que l'url dans path est la page où l'on se rend après l'action?
+* est-ce que les chemins où se rendre après les actions submit ne devraient pas être paramétrables dans les props du formulaire lui-même?
+* plutôt que de passer un param 'accordion' (`{ path: `/organization`, query: { accordion: 'address_postal' } }`), est-ce qu'on ne pourrait pas utiliser des anchors?
+
+##### Divers
+
+* voir à sortir les services profiles/* et rights/* et à les passer dans les composables (il faudra maj les plugins ability et castl)
+* UiItemFromUri, ligne 52 : pqoi ne pas appeller directement `ModelsUtils.extractIdFromUri(uri)`
+* UiInputImage, ligne 120 : est-ce que ce ne serait pas à sa place dans un processor attaché au data provider ça?
+
+### Structure
+
+Mettre en place un "guichet unique" pour les entités, nommé par ex entityManager
+
+Décliner les data-managers en :
+
+* EntityManager (`em`)
+* EnumManager (`enumManager`)
+* FileManager (`fileManager`)
+* ImageManager (`imageManager`), utile? ou fusionner avec le FileManager?
+
+Ces managers auraient des méthodes comme : `getRepository` (voir si nécessaire de garder l'étape des repos), `fetch`, `persist`, `delete`, `new` ou `init`, `flush` (?)
+
+Ils seraient responsables de la validation, de l'état de loading, de l'état dirty
+
+Ils seraient importables depuis un composable du type `useDataManager` ou `useEntityManager`
+
+> Incorporer les méthodes de useDataUtils dans ce manager
+> Voir si utile de récupérer des méthodes de useForm? Pas sûr, mais l'objectif serait que useForm soit seul à interagir avec le store formState, et aussi le seul à interagir avec.
+