Files
sao2.0/AG_GRID_SESSION_INDEX.md
2026-05-20 08:41:40 +02:00

22 KiB

AG Grid Session Index

Point d'entree

Ce fichier sert de synthese rapide pour reprendre le projet AG Grid / SAO a la prochaine session.

Documents a lire dans l'ordre

  1. AG_GRID_COMPATIBILITY_ANALYSIS.md

    • vision d'ensemble
    • contraintes structurelles SAO / AG Grid
    • architecture cible et risques
  2. AG_GRID_PROGRESS.md

    • etat d'avancement du POC
    • ce qui est deja branche dans le code
    • ce qui restait a faire apres les premieres passes
  3. AG_GRID_STYLING_NOTES.md

    • retour d'experience de la grosse session de debug CSS
    • ce qui a fait perdre du temps
    • ce qui a vraiment aide
    • methode recommandee pour les prochaines retouches visuelles

Synthese globale

1. Ce qui est valide

  • POC AG Grid Community en JavaScript pur branche dans SAO
  • fallback historique SAO conserve
  • selection de lignes fonctionnelle
  • tri fonctionnel
  • filtres popup fonctionnels
  • rendu visuel fortement rapproche du style AG Grid standard
  • persistance locale du layout utilisateur
  • panneau Columns custom stable
  • grouping multi-level avec agregations, sous-totaux et grand total

2. Ce qu'on a appris

  • le principal risque n'est pas AG Grid, mais le vieux CSS global SAO
  • les pseudo-elements et les styles globaux sur les controles natifs peuvent casser le theme AG Grid
  • les retouches visuelles doivent etre debuggees avec des traces DOM/cascade, pas seulement "a l'oeil"
  • les bugs de state doivent eux aussi etre traces tres tot
  • les traces utiles a partager doivent etre en JSON plat
  • si 1 ou 2 corrections "intuitives" ne suffisent pas, il faut instrumenter immediatement

3. Strategie pour la prochaine session

  • ne pas repartir de zero
  • relire d'abord cette page puis la section la plus recente de AG_GRID_PROGRESS.md
  • relire ensuite AG_GRID_STYLING_NOTES.md
  • si un bug visuel resiste a 1 ou 2 corrections, passer tout de suite a un dump cible
  • si un bug de state ou de rendering resiste a 1 ou 2 corrections, ajouter tout de suite une trace ..._FLAT_JSON
  • eviter les gros changements globaux de priorite CSS sans isolation claire

Point de reprise apres la session du 2026-03-30

Le POC a franchi un palier important:

  • panneau Columns hors Bootstrap, stable et persiste
  • configuration utilisateur locale de la grille
  • panneau Grouping
  • grouping multi-level client-side
  • agregations
  • sous-totaux
  • grand total
  • toolbar simplifiee et icones plus propres

Les traces suivantes ont ete introduites pour accelerer le debug:

  • COLUMNS_MENU_LAYOUT_FLAT_JSON
  • GROUPING_ACTION_FLAT_JSON
  • GROUPING_STATE_FLAT_JSON
  • GROUPING_PERSISTED_FLAT_JSON
  • ROW_DATA_KIND_FLAT_JSON

Memo important:

  • produire les traces plus frequemment
  • preferer des JSON plats des le debut
  • ne pas attendre plusieurs tentatives "a l'aveugle" quand un symptome resiste

Point de reprise apres la session du 2026-03-31

Deux chantiers supplementaires ont ete consolides:

  • diagnostic de fallback AG Grid plus riche
  • dark mode V1 safe sur le shell principal et la grille

Fallback renderer

La trace a lire en premier est maintenant:

  • TREE_VIEW_DECISION_FLAT_JSON

Elle permet de savoir immediatement si une vue part sur:

  • ag_grid
  • legacy_tree

Et pourquoi, avec notamment:

  • children_field
  • editable_view
  • embedded_relation_tree

Le nouveau garde-fou embedded_relation_tree est important:

  • il evite que des sous-listes embarquees de type one2many ou relationnelles partent par erreur sur AG Grid

Dark mode V1

Le dark mode est maintenant present dans une version prudente:

  • toggle global pres du logo
  • persistance locale
  • logo light/dark dedie
  • topbar, menu, shell, filtres modernises, toolbar de formulaire et AG Grid traites

Ne pas supposer que tout legacy est theme en dark:

  • les composants fragiles n'ont pas encore tous ete traites
  • il faut continuer par zones locales

Next steps produit memorises

Priorite probable

  • presets / bookmarks d'affichage par user/vue

Idee retenue:

  • permettre au user de choisir une configuration nommee de grille
  • separer si besoin:
    • bookmark de filtre SAO
    • preset de layout/tri/grouping AG Grid

Suite logique apres grouping / sous-totaux

  • Reset layout
  • Reset grouping
  • Expand all / Collapse all
  • presets nommes de vue
  • support de plus de colonnes speciales
  • meilleure visibilite des raisons de fallback vers l'ancien tree
  • plus tard: agregations backend sur tout le dataset filtre

Suite logique dark mode

  • finir le perimetre safe du dark mode
  • verifier les toolbars / panneaux encore heterogenes
  • traiter ensuite les modales et dropdowns les plus utilises
  • garder la bascule light/dark strictement non destructive

Recommandation long terme

Si AG Grid doit devenir central dans les vues tree, il faudra probablement:

  • mieux isoler AG Grid du CSS global SAO
  • ou rationaliser les anciennes regles SAO sur input/select/radio/checkbox
  • ou definir une vraie zone de styles AG Grid maitrisee

Point de reprise apres la session du 2026-05-04

Session de stabilisation apres migration vers le depot:

  • https://gitea.open-squared.tech/admin/sao2.0.git

Regle importante d'arborescence / deploiement

Le repo local ne correspond pas exactement a l'arborescence serveur:

  • index.html est gere dans le repo parent cote serveur
  • les fichiers utiles au runtime sont charges depuis dist/
  • quand on modifie tryton-sao.js ou tryton-sao.css, penser a synchroniser aussi:
    • dist/tryton-sao.js
    • dist/tryton-sao.css

Ce point a explique pourquoi une correction CSS Many2One semblait inactive.

Correctif Many2One

Probleme corrige:

  • texte des champs Many2One chevauchant l'icone primaire d'ouverture

Correction retenue:

  • ne pas compter uniquement sur le CSS
  • Sao.View.Form.Many2One.display() appelle maintenant _sync_icon_padding
  • _sync_icon_padding pose directement le padding gauche/droite selon les icones visibles

Trace temporaire:

  • [M2O_ICON_LAYOUT]

Correctif grouping AG Grid restaure

Probleme corrige:

  • apres reouverture d'une vue, le panneau Grouping restaurait bien Supplier
  • mais les groupes etaient reconstruits avec des valeurs vides, donc (Empty)

Cause:

  • le grouping persistait plus vite que le chargement des valeurs texte Many2One / rec_name

Correction:

  • _load_grouping_values charge les champs presents dans grouping.groupBy
  • display() attend ce chargement avant de construire rowData

Traces a lire si le sujet revient:

  • [AGGRID][GROUPING_LOAD_FIELDS_FLAT_JSON]
  • [AGGRID][GROUPING_KEYS_FLAT_JSON]
  • [AGGRID][ROW_DATA_KIND_FLAT_JSON]

Favicon

  • ajout de images/tradon-icon.png
  • style: grand T vert sur fond carre arrondi bleu petrole / vert
  • attention au cache navigateur favicon

Commits de reprise

  • d9292b8 Fix served Many2One icon padding
  • d78c9e0 Fix AG Grid restored grouping values
  • fb54c32 Add Tradon browser favicon

Nettoyage futur

  • retirer les traces temporaires une fois la stabilisation confirmee
  • garder le reflexe des traces JSON plates pour les bugs AG Grid difficiles

Dernier correctif en cours

  • les modales Sao.Window.Search ouvertes par les loupes Many2One ne doivent pas utiliser AG Grid pour l'instant
  • marqueur ajoute: search_window: true
  • fallback AG Grid ajoute: search_window
  • symptome corrige: fenetre Search Broker vide alors que les records existent

Presets de vues AG Grid

  • menu Views ajoute dans la toolbar AG Grid
  • persistance locale version: 2:
    • currentState
    • activePresetId
    • defaultPresetId
    • presets[]
  • migration automatique depuis l'ancien state local unique
  • les presets couvrent colonnes, tri, grouping, aggregations et options d'affichage

Hauteur AG Grid

  • ne pas forcer .ag-grid-tree-container a height: 100%
  • la grille utilise maintenant une hauteur viewport/minimum pour eviter les scrollbars internes trop petits sous les gros filtres
  • eviter les hacks de padding/height sur .ag-center-cols-*, car ils peuvent couper le scroll apres expansion
  • un refresh layout AG Grid est force apres chaque rowData
  • pour eviter la compression verticale, content-box.ag-grid-content-box sort du flex compressif SAO et passe en overflow: visible
  • AG Grid force maintenant ses scrollbars via alwaysShowHorizontalScroll / alwaysShowVerticalScroll
  • la hauteur du host AG Grid est ajustee en JS apres rendu pour eviter le fallback a 320px
  • si le host retombe a 320px, verifier le parent flex SAO: content-box.ag-grid-content-box doit rester flex: 0 0 auto et overflow: visible
  • pour retrouver le scroll horizontal, les largeurs de colonnes sont forcees par defaut et les states/presets anciens trop etroits sont reajustes
  • le log SCROLL_LAYOUT_DEBUG_JSON inclut maintenant les largeurs DOM et la largeur totale des colonnes visibles pour diagnostiquer le scroll horizontal
  • ne pas laisser content-box.ag-grid-content-box en overflow: visible: cela peut afficher la bordure du panneau SAO au milieu des lignes
  • _resize_grid_host ajuste aussi la hauteur du conteneur AG Grid et du content-box SAO sur toolbar + host
  • utiliser [AGGRID][CONTAINER_CLIP_DEBUG_JSON] si le scrollbar horizontal disparait encore: il montre quel parent se termine ou clippe avant le host ou le scrollbar
  • le conteneur AG Grid a maintenant une hauteur explicite et overflow: hidden, pour eviter que le panneau SAO s'arrete au milieu des lignes
  • [AGGRID][HORIZONTAL_WIDTH_FORCE_JSON] indique si la largeur minimale totale des colonnes visibles depasse bien le viewport et force le container de scrollbar horizontal
  • si AG Grid conserve son scrollbar interne invisible, un scrollbar externe .ag-grid-tree-external-horizontal-scroll est affiche sous la grille et synchronise vers .ag-body-horizontal-scroll-viewport / .ag-center-cols-viewport
  • [AGGRID][SAO_AGGRID_LAYOUT_DEBUG_JSON] sert a diagnostiquer la cohabitation SAO/AG Grid: wideElements indique quel noeud elargit la page, screenChildren indique quel bloc se termine visuellement trop haut
  • garder les conteneurs AG Grid en min-width: 0 / max-width: 100% pour eviter qu'un scrollbar ou inner width AG Grid etire le header/formulaire SAO
  • point cle: la largeur visible du host AG Grid doit etre forcee en pixels dans _resize_grid_host; la largeur interne scrollable peut etre plus grande, mais ne doit jamais definir la largeur du content-box ou du panel SAO
  • cause inspecteur: div#tab-1.tab-pane.active avait une taille minimale flex egale au contenu AG Grid; verrouiller la chaine #tabs, .main-offcanvas, #tabcontent, tab-pane.active, panel, panel-body avec min-width: 0
  • pour l'alignement horizontal final, calculer la largeur visible avec le bord droit du screen-container moins le bord gauche de la grille
  • traces console AG Grid/M2O retirees apres stabilisation
  • la largeur scrollable horizontale inclut un tampon de 72px pour que la derniere colonne reste lisible au maximum scroll
  • apres columnMoved, columnPinned, columnResized et columnVisible, relancer le layout via _schedule_grid_layout_refresh; un ResizeObserver garde le host aligne si le conteneur SAO change
  • le clic hamburger/offcanvas modifie seulement la classe .row-offcanvas; un MutationObserver relance le layout avec delais pour attendre la transition CSS de 250ms
  • filtre custom Sao.View.AGGridValueSetFilter: checklist pour colonnes non numeriques avec cardinalite <= 80, sinon fallback texte/date/nombre standard
  • les presets incluent maintenant filters dans l'etat capture/restaure
  • si la liste du filtre custom est vide, verifier la lecture de filterParams; fallback ajoute pour recalculer les valeurs via params.api.forEachNode
  • le fallback du filtre custom doit lire node.data[colDef.field]; params.getValue(node) peut retourner vide selon la signature AG Grid utilisee
  • la checklist du filtre custom se reconstruit dans afterGuiAttached, car AG Grid peut initialiser le filtre avant que toutes les lignes soient disponibles
  • le filtre custom recoit maintenant getLiveValues() depuis _get_column_filter_params; cette fonction relit _last_row_data puis group, source la plus fiable pour les valeurs visibles SAO
  • doesFilterPass du filtre custom utilise getNodeValue() injecte depuis _get_column_filter_params; sans cela la checklist peut afficher les bonnes valeurs mais filtrer sur une valeur vide
  • robuste: le composant filtre custom retourne toujours true dans doesFilterPass; le vrai filtrage passe par le filtre externe AG Grid pilote par _sao_value_filters, pour eviter les incoherences de lifecycle du composant custom
  • _apply_sao_value_filters() doit appeler gridApi.onFilterChanged() et ensureIndexVisible(0, 'top'); le cas NONE puis recocher quelques valeurs laisse sinon le viewport AG Grid vide
  • test UX: bouton toolbar All filters / Any filter pour comparer ET vs OU entre colonnes checklist; mode non persiste pour l'instant
  • invariants finaux filtres checklist:
    • source de valeurs: group SAO complet, jamais le viewport AG Grid deja filtre
    • UI et filtrage separes: Sao.View.AGGridValueSetFilter affiche et notifie, _sao_value_filters filtre via external filter AG Grid
    • le mode any/all s'applique entre colonnes checklist; dans une meme colonne les valeurs sont toujours en OU
    • apres un refresh header SAO, supprimer les filtres checklist dont aucune valeur selectionnee n'existe encore dans le dataset courant
    • retirer les traces VALUE_FILTER_* une fois le diagnostic termine
  • ordre grouping: _apply_grouping_column_order() est appele apres restauration du state; les colonnes de groupBy passent en tete dans l'ordre d'ajout, les autres gardent leur ordre relatif
  • avec grouping actif, appliquer les filtres checklist avant _flatten_grouped_rows; sinon les groupes gardent un __recordCount pre-filtre alors qu'AG Grid masque des enfants ensuite
  • avec grouping actif, ne jamais restaurer un tri AG Grid natif depuis l'etat de colonnes: le grouping est manuel dans rowData, donc un sort AG Grid separe les records de leurs groupes
  • les listes internes Form.Many2Many doivent rester en tree historique via relation_widget: 'many2many'; elles dependent du flux SAO add/remove et ne sont pas encore compatibles AG Grid
  • au retour d'une action annulee ou d'un reload, reconcilier les filtres checklist avant _get_row_data; sinon un filtre fantome peut calculer un rowData vide alors que group contient encore les records
  • POC Filter logic: le bouton de mode filtre ouvre un panneau qui liste les filtres checklist actifs et bascule entre Match all et Match any; cela reste le moteur simple existant, pas encore les groupes ET/OU avec parentheses
  • POC groupes Filter logic: Use groups active un etat local _sao_value_filter_groups avec AND/OR par groupe et AND/OR entre groupes; garder le mode simple comme chemin par defaut tant que l'UX n'est pas stabilisee
  • quand les filtres header SAO rechargent les lignes, _reconcile_sao_value_filters_with_rows(row_data) met a jour le domaine courant des filtres checklist; sinon des selections anciennes peuvent vider la grille
  • _reconcile_sao_value_filters_with_rows supprime maintenant une checklist active si selected ∩ available est vide apres refresh header, afin d'eviter un resultat vide lie a des valeurs obsoletes
  • le state de vue sauvegarde maintenant les filtres checklist SAO et la logique Filter logic par groupes; les refresh AG Grid preservent aussi _selected_ids pendant la reconstruction de rowData pour eviter une perte de selection apres action/wizard
  • les champs utilises par les filtres checklist actifs sont charges avant recalcul rowData / filtre externe; sinon un retour de wizard ou un refresh pouvait comparer JUL26 a des valeurs record encore vides et afficher 0 ligne alors que screen.group contenait encore les records
  • invariant important apres action/wizard/cancel:
    • le compteur SAO peut indiquer encore des records (/63) pendant qu'AG Grid affiche 0 ligne si le filtre externe est reapplique avant chargement des champs filtres
    • display() doit appeler _load_sao_value_filter_values() avant _reconcile_sao_value_filters_with_rows() et avant _get_row_data()
    • ne pas supprimer cette attente: elle garantit que les filtres checklist comparent les valeurs selectionnees (JUL26, etc.) a des valeurs record chargees, pas a des chaines vides temporaires
    • symptome typique si regression: Any filter reste actif, le header et les colonnes sont presents, screen.group/compteur non vide, mais aucune ligne AG Grid meme apres refresh du rapport
    • trace garde-fou: [AGGRID][VALUE_FILTER_EMPTY_RESULT_JSON] se declenche seulement si un filtre checklist actif donne 0 resultat alors que le groupe SAO contient encore des records; regarder sampleRows[*:loaded] et les valeurs selected/all
  • persistence UI des checklists: le mode All/Any peut etre restaure sans que le popup de colonne affiche les cases filtrees si le composant AG Grid repart sur selected = all; filterParams.getSavedValueFilter() reinjecte l'etat _sao_value_filters dans Sao.View.AGGridValueSetFilter via _applySavedSelection()
  • separation critique: les filtres custom checklist ne doivent pas etre persistes dans le filterModel AG Grid (filterType: 'saoValueSet'); ils vivent dans valueFilters. setModel() ne notifie plus _sao_value_filters, sinon le lifecycle AG Grid peut ecraser les filtres sauvegardes avec une selection vide juste apres load_persisted_state
  • restauration avec screen.group vide: ne pas laisser _reconcile_sao_value_filters_with_rows() supprimer les filtres restaures pendant les premieres passes display() ou groupSize:0; tracer reconcile-skip-empty-group et attendre la passe avec le vrai dataset avant de recalculer/supprimer les selections obsoletes
  • methode de debug a retenir: pour les bugs AG Grid de vue sauvegardee, logger la chaine complete persisted state -> memory state -> display lifecycle -> rowData, avec instanceId, groupSize, rowDataCount, filterKeys, activeValueFilters; un etat sauvegarde correct peut encore etre detruit par une passe lifecycle trop precoce
  • clear/all checklist sauvegardee: les guards de restauration ne doivent pas ressusciter un filtre apres une action utilisateur; checkbox-change, all-button, none-button, clear-button oublient l'etat saved/restored de la colonne touchee avant de sauver le nouveau valueFilters
  • refresh checklist: parce que les filtres checklist prefiltrent le rowData avant AG Grid, tout changement qui peut elargir le resultat doit reconstruire rowData depuis screen.group; onFilterChanged() seul ne ramene pas des lignes absentes du rowData courant
  • vue vierge globale: le menu Views contient une entree systeme Default view qui applique un etat sans colonnes/filtres/valueFilters/grouping custom et retire le preset custom par defaut
  • resize colonnes: ne jamais utiliser la largeur par defaut metier comme minWidth; _get_default_column_width() sert au premier affichage, _get_minimum_column_width() sert au resize et aux corrections de vieux states
  • resize colonnes: ne pas lancer le refresh layout global depuis onColumnResized; annuler les timers pendant le drag et sauver la largeur avec skipLayoutRefresh, sinon doLayout() peut annuler la largeur choisie par l'utilisateur
  • resize colonnes: _force_horizontal_scroll_width() ne doit jamais appeler setColumnWidth(); calculer le scroll avec getActualWidth() pour respecter les largeurs utilisateur
  • futur tri en mode grouping: autoriser asc/desc/none et le memoriser dans la config de vue, mais ne pas reactiver le tri natif AG Grid sur le rowData groupe; capturer l'intention, trier les records source avant _flatten_grouped_rows(), puis reconstruire les lignes group/record/total en preservant expansions, totaux et filtres checklist actifs

AG Grid - règles d'or

  • lire d'abord AG_GRID_PROGRESS.md > Synthese fin de session AG Grid avant de toucher aux filtres, vues, rowData, layout ou resize
  • ne pas confondre: largeur par defaut, largeur minimale, largeur reelle utilisateur, largeur scrollable
  • ne pas confondre: filtre AG Grid natif, checklist UI, _sao_value_filters, valueFilters persiste, rowData prefiltre
  • toute correction de stabilisation doit etre testee contre une action utilisateur inverse: clear filtre, elargir filtre, reduire colonne, revenir a Default view
  • si une correction semble logique mais ne marche pas, ajouter une trace de transition avant/apres la fonction suspecte; c'est comme ca que _force_horizontal_scroll_width() a ete identifie
  • traces temporaires a supprimer/reduire apres validation finale: [AGGRID][COLUMN_RESIZE_JSON] et les logs lifecycle/value filter devenus trop bruyants

Point de reprise apres le correctif offcanvas/formulaire

  • bug corrige: formulaire Purchase/contrat bloque a environ 75% de largeur meme quand le menu gauche etait cache
  • cause: #tabs.main-offcanvas gardait les classes Bootstrap col-sm-8 col-lg-9; width: 100% seul ne suffisait pas toujours a annuler le comportement de colonne
  • correctif: .row-offcanvas:not(.active) .main-offcanvas force float: none, flex: 0 0 100%, width: 100%, max-width: 100%
  • complement: .screen-container force min-width: 0, width: 100%, max-width: 100%
  • verifier apres ce type de retouche: menu gauche ouvert et cache, formulaire classique, vue tree AG Grid, et toujours synchroniser dist/tryton-sao.css

Invariant critique scroll/layout AG Grid

  • ne jamais supprimer le scroll vertical SAO au niveau .screen-container; limiter les overrides de scroll a .content-box.ag-grid-content-box
  • _resize_grid_host() peut poser des styles inline sur le content_box; quand Sao.ScreenContainer.set() repasse sur un widget non AG Grid, nettoyer height, minHeight, flexBasis, flexShrink, width, maxWidth
  • regression typique si cet invariant casse: forme Purchase classique coupee en bas, onglets/lignes mal visibles, grande zone blanche ou largeur incorrecte apres toggle du menu gauche
  • test obligatoire: Purchase form sans AG Grid principale avec menu gauche ouvert/cache, puis Lots Management/report AG Grid avec filtres hauts