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=reactou?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 :
| Module | Chemin | Couverture React | Défaut |
|---|---|---|---|
| search-engine | /searchengine | recherche | React |
| forum | /forum | messages, sujets sous catégories, éditeur riche, partage, renommage | React |
| rbs | /rbs | planning Jour/Semaine/Mois multi-ressources, réservations, modération, CRUD, disponibilités, partage, export | React |
| calendar | /calendar | agenda Jour/Semaine/Mois/Liste, calendriers, agendas partagés et externes (ICS), événements, partage | React |
| pages | /pages | sites + pages, recherche, dossiers, corbeille (restauration), partage | React |
| statistics | /stats | tableau de bord d'usage (KPI, accès par app, granularité) | React |
| competences | /competences | référentiels, arbre de compétences, relevé de notes, évaluations, saisie de notes | React |
| cahier-de-textes | /diary | vue calendaire (devoirs et séances), types, séances (publication), progressions | opt-in |
| vie-scolaire | /viescolaire | référentiel, périodes, services, regroupements, exclusions, mémento, trombinoscope, passerelles | opt-in |
| edt | /edt | grille horaire (« Mon emploi du temps » par défaut), création de cours | opt-in |
| presences | /presences | tableau de bord complet, registre d'appel, absences, régularisation, dispenses, paramétrage | opt-in |
| incidents | /incidents | incidents (recherche, export CSV, saisie, bascule « traité »), punitions | opt-in |
| massmailing | /massmailing | publipostage (types, seuils, anomalies), historique | opt-in |
| statistics-presences | /statistics-presences | indicateur Global (compteurs + tableau élèves × types) | opt-in |
| community | /community | communautés (CRUD, recherche, détail, membres), annuaire de partage | opt-in |
| timeline-generator | /timelinegenerator | frises (recherche) + événements + partage | opt-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
keySeparatoretnsSeparator, 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 cookieXSRF-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.