Skip to main content

Migration progressive des modules AngularJS → React

Open ENT modernise l'ergonomie de ses modules en migrant leur interface d'AngularJS vers React (chantier CCTP 51C). La migration est progressive et sans rupture : le backend Java reste inchangé (mêmes routes REST), et les deux interfaces cohabitent pendant la transition.

Principe

Chaque module migré expose un frontend React (Vite, React 18, @open-ent/react / @open-ent/bootstrap / @open-ent/client, @tanstack/react-query, react-i18next) monté sous la route serveur existante du module. Le contrôleur d'affichage choisit la vue à rendre :

  • par défaut, l'interface pilotée par la configuration frontend-ui ("angular" tant que la parité fonctionnelle n'est pas atteinte, puis "react") ;
  • à la demande, via le paramètre d'URL ?ui=react ou ?ui=angular (repli toujours disponible).
final String uiParam = request.params().get("ui");
final String frontendUi = "react".equals(config.getString("frontend-ui", "angular")) ? "react" : "angular";
final String ui = ("react".equals(uiParam) || "angular".equals(uiParam)) ? uiParam : frontendUi;
if ("react".equals(ui)) {
renderView(request, new JsonObject(), "<module>-react.html", null);
} else {
renderView(request); // vue AngularJS historique
}

Le bundle React est servi sous /<module>/public/index.js ; le bundle AngularJS historique (souvent /<module>/public/dist/application.js) reste intact. Un rebuild backend seul ne touche pas au frontend, et réciproquement.

Migration incrémentale et bascule du défaut

Un module est migré par incréments (un lot de fonctionnalités à la fois). Tant que la parité avec l'interface AngularJS n'est pas atteinte, le React reste opt-in (?ui=react) et les utilisateurs sont servis par AngularJS. Dès la parité atteinte, le défaut bascule sur React (frontend-ui: "react"), tout en conservant le repli ?ui=angular.

État de la migration (campagne terminée le 04/07/2026)

16 modules migrés AngularJS → React (backend Java inchangé, toggle ?ui=) — plus aucun module de la suite sans version React :

ModuleCheminCouverture ReactDéfaut
search-engine/searchenginerechercheReact
forum/forummessages, sujets sous catégories, éditeur riche, partage, renommageReact
rbs/rbsplanning Jour/Semaine/Mois multi-ressources, réservations, modération, CRUD, disponibilités, partage, exportReact
calendar/calendaragenda Jour/Semaine/Mois/Liste, calendriers, agendas partagés et externes (ICS), événements, partageReact
pages/pagessites + pages, recherche, dossiers, corbeille (restauration), partageReact
statistics/statstableau de bord d'usage (KPI, accès par app, granularité)React
competences/competencesréférentiels, arbre de compétences, relevé de notes, évaluations, saisie de notesReact
cahier-de-textes/diaryvue calendaire (devoirs et séances), types, séances (publication), progressionsopt-in
vie-scolaire/viescolaireréférentiel, périodes, services, regroupements, exclusions, mémento, trombinoscope, passerellesopt-in
edt/edtgrille horaire (« Mon emploi du temps » par défaut), création de coursopt-in
presences/presencestableau de bord complet, registre d'appel, absences, régularisation, dispenses, paramétrageopt-in
incidents/incidentsincidents (recherche, export CSV, saisie, bascule « traité »), punitionsopt-in
massmailing/massmailingpublipostage (types, seuils, anomalies), historiqueopt-in
statistics-presences/statistics-presencesindicateur Global (compteurs + tableau élèves × types)opt-in
community/communitycommunautés (CRUD, recherche, détail, membres), annuaire de partageopt-in
timeline-generator/timelinegeneratorfrises (recherche) + événements + partageopt-in

La campagne s'est conclue par une comparaison visuelle intégrale Angular↔React (captures appariées pleine page des 16 modules) qui a permis de détecter et corriger les derniers écarts — dont un bug transverse de thème rendant les boutons btn-link invisibles (blanc sur blanc). Test intégral final : 58/58 scénarios Playwright verts. Les modules opt-in basculent en React par défaut au fil de la consolidation, avec repli ?ui=angular garanti.

Bonnes pratiques

  • Router par hash (createHashRouter) : le module est servi par une route serveur unique, la navigation se fait dans le fragment (#/…) — évite les 404 au rafraîchissement des sous-routes.
  • i18n à clés plates : les clés ENT contiennent des points → désactiver keySeparator et nsSeparator, et charger les traductions du module via /<module>/i18n.
  • XSRF : sur certains modules, les mutations (POST/PUT/DELETE) exigent l'en-tête X-XSRF-TOKEN (valeur du cookie XSRF-TOKEN).
  • Nom de bundle stable et distinct : conserver des noms de fichiers fixes (la vue backend les référence en dur) et distincts du bundle historique pour éviter toute collision.