AG GRID agjustment

This commit is contained in:
2026-05-17 14:26:35 +02:00
parent 2ed47d698f
commit 991a875b94
6 changed files with 6720 additions and 1332 deletions

View File

@@ -801,6 +801,167 @@ Point de deploiement:
- `Sao.View.AGGridTree.get_support_diagnostics` exclut ce contexte avec `fallbackReason: search_window`
- resultat attendu: les recherches `Many2One` repassent sur le tree historique, avec selection simple/multiple et `search_filter` SAO standard
### Presets de vues AG Grid
- ajout d'un menu `Views` dans la toolbar AG Grid
- stockage local migre en `version: 2` avec plusieurs presets par base/utilisateur/modele/vue
- l'ancien etat unique est conserve comme `currentState` lors de la migration
- actions disponibles:
- appliquer un preset
- `Save as`
- `Update`
- renommer
- supprimer
- definir/effacer le preset par defaut
- revenir au layout standard
- le bouton affiche le preset actif et ajoute `*` si l'utilisateur a modifie la grille depuis l'application du preset
### Correctif hauteur AG Grid avec filtres hauts
- probleme observe: dans `Lots management`, le formulaire de filtres au-dessus de la grille laisse une grille basse avec un scrollbar interne minuscule
- cause probable: `.ag-grid-tree-container` forcait `height: 100%`, ce qui se calcule mal quand la grille est sous un gros bloc de filtres dans un contenu scrollable
- correctif CSS: hauteur AG Grid autonome basee sur le viewport, avec minimum lisible
- ne pas modifier les conteneurs internes `.ag-center-cols-*`: cela peut desynchroniser le scroll virtuel AG Grid apres expansion de groupe
- ajout d'un refresh layout AG Grid apres chaque changement de `rowData`
- traces ajoutees: `LAYOUT_REFRESH_FLAT_JSON` et compte `displayedRowCount` dans `SCROLL_LAYOUT_DEBUG_JSON`
- diagnostic suivant: le conteneur SAO et le viewport AG Grid avaient chacun leur scroll
- correctif retenu: AG Grid reste en layout normal avec son scroll interne, et le `content-box` SAO contenant une AG Grid passe en `overflow-y: hidden`
- les options AG Grid `alwaysShowHorizontalScroll` et `alwaysShowVerticalScroll` sont activees pour forcer la reservation de la zone de scroll
- la hauteur effective du host AG Grid est maintenant posee en JS apres rendu, car la regle CSS dynamique retombait a `320px`
- diagnostic suivant: le parent flex SAO comprimait encore le host AG Grid a `320px`; `content-box.ag-grid-content-box` passe en bloc non-flex et overflow visible
- horizontal: les colonnes AG Grid recoivent maintenant des largeurs minimales metier et les anciens presets trop etroits sont elargis apres restauration
- diagnostic horizontal ajoute dans `SCROLL_LAYOUT_DEBUG_JSON`: `clientWidth`, `scrollWidth`, colonnes visibles et `totalDisplayedWidth`
- artefact visuel corrige: `content-box.ag-grid-content-box` ne doit pas rester en `overflow: visible`, sinon la bordure du panneau SAO peut se dessiner au milieu des lignes AG Grid
- le resize JS force maintenant le conteneur AG Grid et le `content-box` SAO a englober toolbar + host, pour eviter que le panneau parent se termine avant la fin de la grille
- trace dediee ajoutee: `[AGGRID][CONTAINER_CLIP_DEBUG_JSON]`, avec les deltas entre le host, le scrollbar horizontal et chaque parent
- le conteneur AG Grid recoit maintenant une hauteur explicite, pas seulement un `min-height`, et `overflow: hidden`
- trace/correction horizontale ajoutee: `[AGGRID][HORIZONTAL_WIDTH_FORCE_JSON]` force la largeur minimale totale des colonnes visibles dans le container de scrollbar horizontal
- ajout d'un scrollbar horizontal externe sous le host AG Grid, synchronise avec les viewports AG Grid, car le scrollbar interne reste invisible malgre une largeur forcee superieure au viewport
- diagnostic global ajoute: `[AGGRID][SAO_AGGRID_LAYOUT_DEBUG_JSON]` liste les dimensions page/SAO/AG Grid, les enfants du `screen-container` et les `wideElements` qui elargissent le document
- CSS: les conteneurs AG Grid/SAO dedies recoivent `min-width: 0`, `max-width: 100%` et `box-sizing: border-box` pour eviter qu'un enfant scrollable etire le formulaire complet
- correction largeur: `_resize_grid_host` fixe maintenant explicitement la largeur visible du host/conteneur/content-box sur la largeur viewport disponible, separee de la largeur interne scrollable des colonnes
- cause identifiee via l'inspecteur: `#tabcontent > .tab-pane.active` etait un flex item dont la taille minimale suivait le contenu AG Grid (~3963px); ajout de `min-width: 0` / `max-width: 100%` / `overflow-x: hidden` sur la chaine `#tabs` -> `#tabcontent` -> `tab-pane` -> `panel` -> `panel-body`
- ajustement alignement: la largeur visible de la grille est maintenant calculee depuis le bord droit reel du `screen-container`, pas depuis `window.innerWidth - left`, pour aligner la grille avec le panneau de filtres/header
- nettoyage: suppression des traces console AG Grid/M2O temporaires
- finition scroll horizontal: ajout d'un tampon de 72px a la largeur scrollable pour eviter que la derniere colonne soit coupee par le bord/scrollbar
- stabilisation largeur apres interaction: les changements de colonnes AG Grid relancent maintenant `_resize_grid_host` et `_force_horizontal_scroll_width`; un `ResizeObserver` surveille aussi le conteneur SAO
- stabilisation offcanvas: un `MutationObserver` surveille `.row-offcanvas` et relance le layout a 0/80/180/320ms apres le toggle du menu lateral
- filtre multi-valeurs: colonnes non numeriques avec <= 80 valeurs distinctes utilisent un filtre custom a cases a cocher; au-dela on garde le filtre texte/numerique AG Grid standard
- les filtres AG Grid sont maintenant inclus dans l'etat/presets sauvegardes via `getFilterModel` / `setFilterModel`
- robustesse filtre multi-valeurs: le composant lit les valeurs depuis `params.filterParams`, `params.colDef.filterParams`, ou les recalcule depuis les lignes AG Grid si necessaire
- correction filtre multi-valeurs: le fallback lit maintenant `node.data[colDef.field]`, car `params.getValue(node)` retournait vide avec notre rowData texte
- correction filtre multi-valeurs: la checklist se rafraichit maintenant a l'ouverture du popup pour couvrir le cas ou le composant filtre est initialise avant le chargement complet du `rowData`
- correction filtre multi-valeurs: ajout de `getLiveValues()` dans `filterParams`, relu depuis `_last_row_data` puis `group`, afin de ne plus dependre des `params` internes du composant filtre AG Grid
- correction filtre multi-valeurs: ajout de `getNodeValue()` dans `filterParams` pour que `doesFilterPass` compare exactement les memes valeurs que celles affichees dans la checklist
- fiabilisation filtre multi-valeurs: le composant custom ne filtre plus directement; il alimente un etat `_sao_value_filters` et le filtrage effectif passe par `isExternalFilterPresent` / `doesExternalFilterPass`
- apres changement checklist, `_apply_sao_value_filters()` force `gridApi.onFilterChanged()`, remonte au premier index et relance le layout; necessaire apres `NONE` puis re-selection, sinon AG Grid peut rester sur un viewport vide
- test mode combinaison checklist: ajout du bouton toolbar `All filters` / `Any filter`; `all` applique un ET entre colonnes filtrees, `any` applique un OU entre colonnes filtrees
- apres refresh des filtres header SAO, les domaines `all` des filtres checklist sont reconciles avec le nouveau `row_data`; l'activite d'un filtre compare maintenant l'inclusion des valeurs, pas seulement la taille des sets
- si apres refresh header SAO une checklist active n'a plus aucune valeur selectionnee presente dans le nouveau dataset, le filtre est supprime pour eviter de vider la grille avec une selection fantome
- stabilisation finale checklist:
- la liste des valeurs doit venir du `group` SAO complet, pas des lignes deja filtrees par AG Grid
- le composant custom ne doit pas filtrer directement via `doesFilterPass`; il pilote seulement `_sao_value_filters`
- le filtrage reel passe par `isExternalFilterPresent` / `doesExternalFilterPass`
- `All filters` applique un ET entre colonnes; `Any filter` applique un OU entre colonnes
- apres refresh des filtres header SAO, reconcilier les filtres checklist avec le nouveau dataset et supprimer les selections devenues fantomes
- ne pas comparer seulement `selected.size` et `all.size`: verifier l'inclusion des valeurs disponibles
- ne pas laisser les traces `VALUE_FILTER_*` actives apres diagnostic
- ordre des colonnes avec grouping: apres restauration de l'etat/preset, `_apply_grouping_column_order()` place les colonnes groupees en premier dans l'ordre `groupBy`, puis conserve l'ordre relatif courant des autres colonnes
- grouping + filtres checklist: les records sont filtres avant `_flatten_grouped_rows`, afin que `__recordCount`, sous-totaux et enfants visibles restent coherents; les lignes groupe/total passent toujours le filtre externe
- grouping manuel + tri AG Grid: l'etat de colonnes restaure ne doit pas reappliquer `sort` / `sortIndex` quand le grouping est actif; sinon AG Grid trie le `rowData` plat et separe les records de leurs lignes groupe.
- Many2Many embarques: les trees creees par `Form.Many2Many` portent maintenant `relation_widget: 'many2many'` et retombent en renderer historique; AG Grid ne doit pas prendre ces listes tant que la suppression/add-remove relationnelle n'est pas explicitement compatible.
- retour d'action/cancel: `_reconcile_sao_value_filters_with_rows()` doit passer avant `_get_row_data()`. Sinon une checklist devenue obsolete apres reload/cancel peut etre supprimee trop tard et laisser la grille vide jusqu'au prochain display.
- POC logique filtres: le bouton `All filters` / `Any filter` ouvre maintenant un panneau `Filter logic` listant les filtres checklist actifs et permettant de choisir `Match all` ou `Match any`, sans changer encore le moteur vers des groupes ET/OU imbriques.
- POC groupes filtres: le panneau `Filter logic` peut maintenant activer `Use groups`, creer des groupes, placer chaque filtre actif dans un groupe, choisir AND/OR dans chaque groupe et AND/OR entre groupes. Le mode simple reste le comportement par defaut.
### Correctif retour wizard avec filtres checklist actifs
- scenario valide: dans `Lots management`, appliquer un `Any filter` sur deux periodes (`Purchase Delivery Period` / `Sale Delivery Period`), selectionner deux lignes, lancer l'action/wizard `Go to matching`, puis cliquer `Cancel`
- bug observe: au retour du wizard, l'action recevait bien les deux ids selectionnes, mais la grille revenait vide; le compteur SAO restait pourtant non vide (`/63`) et le refresh du rapport ne restaurait pas les lignes
- diagnostic: les records etaient encore presents dans `screen.group`; le probleme venait du filtre externe AG Grid pilote par `_sao_value_filters`
- cause technique: apres reload/cancel, les champs utilises par les filtres checklist pouvaient ne pas etre charges au moment de recalculer `rowData`; le filtre comparait alors les valeurs selectionnees (`JUL26`) a des valeurs record temporairement vides
- correctif: `display()` charge maintenant explicitement les champs des filtres checklist actifs via `_load_sao_value_filter_values()` avant `_reconcile_sao_value_filters_with_rows()` et avant `_get_row_data()`
- ordre a conserver:
- charger les valeurs de grouping si besoin
- charger les champs des filtres checklist actifs
- reconstruire les colonnes
- reconcilier les domaines checklist avec `screen.group`
- calculer `rowData`
- invariant: les valeurs de filtre doivent toujours etre comparees a partir du `group` SAO complet et de champs charges; ne pas laisser le viewport AG Grid deja filtre ou un record partiellement charge devenir la source de verite
- trace garde-fou: `[AGGRID][VALUE_FILTER_EMPTY_RESULT_JSON]` ne doit apparaitre que si un filtre checklist actif donne 0 resultat alors que `screen.group` contient encore des records; lire `sampleRows`, les indicateurs `*:loaded`, et les ensembles `selected/all`
- ne pas confondre avec une perte de selection: ici la selection initiale et les ids envoyes au wizard etaient corrects; l'incoherence etait post-retour dans le recalcul du filtre externe
### Synthese fin de session AG Grid
- principe general: distinguer les couches `state sauvegarde`, `state moteur en memoire`, `rowData donne a AG Grid`, `viewport/filtre AG Grid`; un bug peut venir d'une couche correcte puis detruite par la suivante
- lifecycle: `display()` peut passer avec `groupSize:0`; ne jamais supprimer/reconcilier agressivement des filtres ou des vues sur une passe sans donnees
- filtres checklist: `Sao.View.AGGridValueSetFilter` est une UI seulement; le vrai filtre vit dans `_sao_value_filters` et passe par external filter + prefiltrage du `rowData`
- rowData: quand une action checklist peut elargir le resultat (`Clear`, `All`, recocher, bascule `All/Any`), reconstruire `rowData` depuis `screen.group`; `gridApi.onFilterChanged()` seul ne peut pas ramener des lignes absentes du `rowData`
- persistence vues: les checklist filters ne doivent pas vivre dans le `filterModel` AG Grid (`saoValueSet`), mais dans `valueFilters`; `setModel()` du composant custom ne doit pas notifier le moteur
- actions utilisateur vs guards: les guards anti-perte de filtre ne doivent proteger que les passes techniques de restauration; une action utilisateur explicite doit toujours gagner contre l'etat saved/restored
- vue vierge: `Default view` est une entree systeme, pas un preset utilisateur; elle remet a zero colonnes/filtres/valueFilters/grouping custom et retire le preset custom par defaut
- resize colonnes: separer largeur par defaut et largeur minimale; les helpers de layout/scrollbar ne doivent jamais appeler `setColumnWidth()` ni reappliquer `columnDefs` pendant un drag utilisateur
- scrollbar horizontal: `_force_horizontal_scroll_width()` doit seulement dimensionner les conteneurs de scroll avec `getActualWidth()`; il ne doit pas modifier les largeurs utilisateur
- traces utiles si regression:
- vue/filtres: `[AGGRID][TREE_LIFECYCLE_JSON]`, `[AGGRID][VALUE_FILTER_STATE_JSON]`, `[AGGRID][VALUE_FILTER_CHANGE_JSON]`, `[AGGRID][VALUE_FILTER_EMPTY_RESULT_JSON]`
- resize: `[AGGRID][COLUMN_RESIZE_JSON]`
- lire la chaine complete: persisted state -> memory state -> display lifecycle -> rowData -> AG Grid viewport
- hygiene avant fin: retirer ou reduire les traces temporaires une fois les scenarios valides; garder seulement les traces garde-fou vraiment necessaires
### Correctif restauration UI des checklists sauvegardees
- bug observe: apres `Views > Update`, le preset restaurait bien le bouton `Any filter`, mais les popups `Purchase Delivery Period` / `Sale Delivery Period` rouvraient avec toutes les valeurs cochees
- cause: le moteur externe `_sao_value_filters` etait restaure, mais chaque instance `Sao.View.AGGridValueSetFilter` recreait son UI avec `selected = all values`
- correctif: `_get_column_filter_params()` fournit maintenant `getSavedValueFilter()`; le composant custom applique cet etat dans `_applySavedSelection()` a l'init, dans `setModel(null)` et apres `_refreshValuesFromGrid()`
- correction suite traces: ne pas persister/rejouer les modeles AG Grid `filterType: 'saoValueSet'` dans `state.filters`; ils peuvent rappeler `setModel()` pendant le lifecycle AG Grid et vider `_sao_value_filters`
- `Sao.View.AGGridValueSetFilter.setModel()` ne doit pas appeler `_notifySelectionChanged()`; seuls les clics utilisateur (`change`, `All`, `None`, `Clear`) doivent modifier l'etat externe
- invariant: sauvegarder/restaurer une vue doit garder trois couches coherentes:
- mode global `all/any`
- etat moteur `_sao_value_filters`
- cases cochees visibles dans les popups de colonnes
- test de regression: sauver une vue avec `Any filter` et deux Delivery Period partiellement cochees, recharger/appliquer la vue, ouvrir chaque filtre colonne; les valeurs non selectionnees doivent rester decochees
### Correctif restauration avant chargement du group
- bug observe: au retour dans une vue sauvegardee, `load_persisted_state` restaurait bien `r_del_period=JUL26` et `r_sale_del_period=JUL26`, puis la grille affichait les 180 lignes non filtrees jusqu'a une interaction manuelle sur le filtre
- cause tracee: `display()` peut s'executer une premiere fois avec `groupSize:0`; `_reconcile_sao_value_filters_with_rows()` voyait alors un domaine vide et supprimait les filtres restaures avant l'arrivee du vrai `screen.group`
- correctif: si des filtres checklist existent mais que `this.group` est encore vide, la reconciliation est ignoree et trace `reconcile-skip-empty-group`; les filtres restent actifs pour la passe suivante avec les records charges
- invariant: ne jamais supprimer un filtre checklist restaure sur une passe de lifecycle sans records; la suppression des selections obsoletes ne doit se faire que lorsque le dataset courant est reellement disponible
- lecon de debug: quand une vue restaure mal un filtre, ne pas s'arreter au log `load_persisted_state` correct; suivre aussi `init-end`, chaque `display-start`, `display-row-data`, `filterKeys`, `activeValueFilters`, `groupSize` et `rowDataCount`
- anti-pattern a eviter: une fonction de reconciliation ne doit jamais traiter `groupSize:0` comme une preuve que les valeurs sauvegardees sont obsoletes; `0 record` pendant le lifecycle peut seulement vouloir dire "les donnees ne sont pas encore arrivees"
- trace utile pour isoler vite ce type de bug: comparer `stateFilterKeys` (sauvegarde), `memoryFilterKeys` / `filterKeys` (moteur courant), et `persistedFilterKeys` (etat disponible pour l'UI du popup)
- diagnostic rapide attendu si regression: `load_persisted_state` contient les filtres, puis une passe `display-start groupSize:0` ne doit plus etre suivie d'une disparition de `filterKeys`; elle doit produire `reconcile-skip-empty-group`
### Correctif clear/all des checklists sauvegardees
- bug observe: apres restauration d'une vue avec filtres checklist, remettre une colonne a `Clear` / tout coche pouvait ne pas ramener les lignes attendues; l'ancien `valueFilters` sauvegarde restait disponible et pouvait etre relu par `getSavedValueFilter()`
- cause: les protections ajoutees contre les pertes de filtre au chargement etaient trop larges (`capture`/`merge` reprenaient l'etat persiste des qu'aucun filtre actif n'etait detecte)
- correctif: les sources utilisateur (`checkbox-change`, `all-button`, `none-button`, `clear-button`) deviennent prioritaires; elles oublient l'etat restaure/persisted de la colonne touchee dans l'instance courante
- invariant: un guard de restauration peut proteger une passe technique sans donnees, mais ne doit jamais annuler une intention utilisateur explicite de modifier ou supprimer un filtre
- consequence: apres `Clear` d'une checklist, `_sao_value_filters[colId]` est supprime, l'ancien saved state de cette colonne n'est plus re-injecte, puis `_apply_sao_value_filters()` relance `onFilterChanged()`
- correction suite: les filtres checklist prefiltrent aussi le `rowData` envoye a AG Grid; quand une action utilisateur elargit le filtre, `onFilterChanged()` seul ne peut pas faire revenir des records absents du `rowData` courant
- correctif rowData: `_apply_sao_value_filters()` reconstruit maintenant le `rowData` depuis `screen.group` via `_refresh_sao_value_filter_row_data()` avant de relancer le filtre externe AG Grid
- invariant: si un filtre custom change la population de records avant flatten/grouping, chaque changement utilisateur (`All`, `Clear`, checkbox, changement `All/Any`) doit reconstruire `rowData`, pas seulement appeler le moteur de filtre AG Grid
### Vue systeme vierge
- ajout d'une entree systeme `Default view` dans le menu `Views` de toutes les grilles AG Grid
- objectif: revenir a une vue vierge de personnalisation sans devoir supprimer ou modifier les presets utilisateur
- etat standard: pas de colonnes sauvegardees, pas de filtre AG Grid natif, pas de `valueFilters`, mode checklist `all`, pas de groupes de filtres, grouping par defaut
- choisir `Default view` applique cet etat standard et retire le preset custom marque comme default, afin qu'un reload ne ramene pas immediatement une ancienne vue personnalisee
### Resize colonnes
- bug observe: certaines colonnes revenaient immediatement a leur largeur avant/apres drag, surtout quand on essayait de les reduire
- cause: `_enforce_minimum_column_widths()` utilisait `_get_default_column_width()` comme largeur minimale; une largeur par defaut metier (`Supplier=320`, `Purchase/Sale=220`, `Period=180`) ne doit pas devenir une contrainte de resize utilisateur
- correctif: separation entre largeur par defaut et vraie largeur minimale via `_get_minimum_column_width()`; les colonnes gardent leur largeur initiale confortable, mais peuvent etre reduites jusque 80px environ selon le type
- invariant: les stabilisations de layout doivent corriger les vieux states absurdes, pas annuler une action manuelle valide de resize
- correction suite: le resize utilisateur ne passe plus par le refresh layout global; pendant le drag, les timers `_schedule_grid_layout_refresh()` sont annules, puis la largeur est seulement sauvegardee et le scroll horizontal est recalcule
- invariant: `onColumnResized` doit capturer/sauver la largeur, mais ne doit pas appeler `doLayout()` ou reappliquer des columnDefs/state pendant le drag
- cause finale tracee: `_force_horizontal_scroll_width()` recalculait le scroll horizontal avec les largeurs par defaut et appelait `setColumnWidth()` si une colonne etait plus petite; reduire `r_supplier` a 248px etait aussitot annule vers 320px
- correctif final: `_force_horizontal_scroll_width()` additionne maintenant les largeurs reelles `getActualWidth()` et ne modifie plus jamais les largeurs de colonnes
- invariant: une fonction de scrollbar peut dimensionner le conteneur de scroll, mais ne doit jamais changer la taille des colonnes utilisateur
### Commits importants
- `fc9ab5d Save SAO AG Grid work`

View File

@@ -240,3 +240,94 @@ Traces a lire si le sujet revient:
- 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
### 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

438
dist/tryton-sao.css vendored
View File

@@ -9329,11 +9329,16 @@ html[theme="default"] .carousel-caption h6 {
#tabcontent {
display: block;
width: 100%;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
#tabcontent > .tab-pane > .panel {
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
max-width: 100%;
margin-bottom: 5px;
}
#tabcontent > .tab-pane > .panel > .panel-body {
@@ -9342,9 +9347,14 @@ html[theme="default"] .carousel-caption h6 {
flex-direction: row;
padding-top: 0;
min-height: 0;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
#tabcontent > .tab-pane > .panel > .panel-body > div {
display: inline-flex;
min-width: 0;
max-width: 100%;
padding-left: 15px;
padding-right: 15px;
}
@@ -9355,10 +9365,16 @@ html[theme="default"] .carousel-caption h6 {
/* override bootstrap which sets display to block */
display: flex;
flex: 1;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
#tabcontent[data-view-type="tree"] {
display: flex;
flex: 1;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
@media screen and (min-width: 768px) {
#global-search-entry {
@@ -9677,6 +9693,15 @@ img.icon {
flex: 1;
overflow-y: auto;
}
.content-box.ag-grid-content-box {
flex: 0 0 auto;
min-height: 0;
min-width: 0;
width: 100%;
max-width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.tree-container {
display: flex;
flex-direction: column;
@@ -10638,6 +10663,11 @@ img.favorite-icon {
body {
overflow-x: hidden;
}
#tabs,
.main-offcanvas {
min-width: 0;
max-width: 100%;
}
.row-offcanvas {
position: relative;
-webkit-transition: all 0.25s ease-out;
@@ -10921,19 +10951,26 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
min-width: 0;
height: auto;
width: 100%;
max-width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.ag-grid-tree-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: flex-start;
gap: 12px;
padding: 6px 0;
}
.ag-grid-tree-columns > .btn,
.ag-grid-tree-grouping > .btn {
.ag-grid-tree-grouping > .btn,
.ag-grid-tree-layouts > .btn,
.ag-grid-value-filter-mode {
display: inline-flex;
align-items: center;
gap: 8px;
@@ -10951,8 +10988,12 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
.ag-grid-tree-columns > .btn:hover,
.ag-grid-tree-grouping > .btn:hover,
.ag-grid-tree-layouts > .btn:hover,
.ag-grid-value-filter-mode:hover,
.ag-grid-tree-columns > .btn:focus,
.ag-grid-tree-grouping > .btn:focus {
.ag-grid-tree-grouping > .btn:focus,
.ag-grid-tree-layouts > .btn:focus,
.ag-grid-value-filter-mode:focus {
background: linear-gradient(180deg, #f2faf7 0%, #e7f2ed 100%);
border-color: #bfd5cd;
color: #28484b;
@@ -10960,20 +11001,32 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
}
.ag-grid-tree-columns > .btn:active,
.ag-grid-tree-grouping > .btn:active {
.ag-grid-tree-grouping > .btn:active,
.ag-grid-tree-layouts > .btn:active,
.ag-grid-value-filter-mode:active {
transform: translateY(1px);
box-shadow: 0 2px 8px rgba(53, 81, 84, 0.12);
}
.ag-grid-tree-columns-label,
.ag-grid-tree-grouping-label {
.ag-grid-tree-grouping-label,
.ag-grid-tree-layouts-label,
.ag-grid-value-filter-mode-label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.01em;
text-transform: none;
}
.ag-grid-tree-grouping-panel .btn {
.ag-grid-value-filter-mode.active {
background: linear-gradient(180deg, #e0f4f1 0%, #cbe9e3 100%);
border-color: #8fc3bd;
color: #0f6f6d;
}
.ag-grid-tree-grouping-panel .btn,
.ag-grid-tree-layouts-panel .btn,
.ag-grid-filter-logic-panel .btn {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -10992,26 +11045,40 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
}
.ag-grid-tree-grouping-panel .btn:hover,
.ag-grid-tree-grouping-panel .btn:focus {
.ag-grid-tree-grouping-panel .btn:focus,
.ag-grid-tree-layouts-panel .btn:hover,
.ag-grid-tree-layouts-panel .btn:focus,
.ag-grid-filter-logic-panel .btn:hover,
.ag-grid-filter-logic-panel .btn:focus {
background: linear-gradient(180deg, #f2faf7 0%, #e7f2ed 100%);
border-color: #bfd5cd;
color: #28484b;
box-shadow: 0 4px 10px rgba(53, 81, 84, 0.14);
}
.ag-grid-tree-grouping-panel .btn:active {
.ag-grid-tree-grouping-panel .btn:active,
.ag-grid-tree-layouts-panel .btn:active,
.ag-grid-filter-logic-panel .btn:active {
transform: translateY(1px);
box-shadow: 0 1px 5px rgba(53, 81, 84, 0.1);
}
.ag-grid-tree-grouping-panel .btn[disabled],
.ag-grid-tree-grouping-panel .btn.disabled {
.ag-grid-tree-grouping-panel .btn.disabled,
.ag-grid-tree-layouts-panel .btn[disabled],
.ag-grid-tree-layouts-panel .btn.disabled,
.ag-grid-filter-logic-panel .btn[disabled],
.ag-grid-filter-logic-panel .btn.disabled {
opacity: 0.5;
box-shadow: none;
}
.ag-grid-tree-grouping-panel .btn-xs,
.ag-grid-tree-grouping-panel .btn-sm {
.ag-grid-tree-grouping-panel .btn-sm,
.ag-grid-tree-layouts-panel .btn-xs,
.ag-grid-tree-layouts-panel .btn-sm,
.ag-grid-filter-logic-panel .btn-xs,
.ag-grid-filter-logic-panel .btn-sm {
font-size: 12px;
line-height: 1.2;
}
@@ -11095,6 +11162,156 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
z-index: 3000;
}
.ag-grid-tree-layouts-panel {
width: 520px;
max-width: calc(100vw - 24px);
max-height: min(70vh, 640px);
overflow: auto;
padding: 14px;
background: #fff;
border: 1px solid #d6dfdb;
border-radius: 6px;
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.16);
z-index: 3000;
}
.ag-grid-filter-logic-panel {
width: 360px;
max-width: calc(100vw - 24px);
max-height: min(70vh, 640px);
overflow: auto;
padding: 14px;
background: #fff;
border: 1px solid #d6dfdb;
border-radius: 6px;
color: #355154;
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.16);
z-index: 3000;
}
.ag-grid-filter-logic-title {
margin-bottom: 10px;
font-size: 18px;
font-weight: 600;
color: #355154;
}
.ag-grid-filter-logic-mode {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 10px;
}
.ag-grid-filter-logic-mode .btn.active,
.ag-grid-filter-logic-group-controls .btn.active,
.ag-grid-filter-logic-group-header .btn.active {
background: linear-gradient(180deg, #e0f4f1 0%, #cbe9e3 100%);
border-color: #8fc3bd;
color: #0f6f6d;
}
.ag-grid-filter-logic-help,
.ag-grid-filter-logic-empty {
font-size: 12px;
line-height: 1.35;
color: #6a7b7a;
}
.ag-grid-filter-logic-help {
margin-bottom: 12px;
}
.ag-grid-filter-logic-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.ag-grid-filter-logic-group-controls,
.ag-grid-filter-logic-group-header {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.ag-grid-filter-logic-group-controls {
margin-bottom: 4px;
}
.ag-grid-filter-logic-group-label,
.ag-grid-filter-logic-group-title {
font-size: 12px;
font-weight: 700;
color: #28484b;
}
.ag-grid-filter-logic-group {
display: flex;
flex-direction: column;
gap: 8px;
padding: 10px;
border: 1px solid #dce9e4;
border-radius: 6px;
background: #fbfdfc;
}
.ag-grid-filter-logic-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 4px 10px;
padding: 8px 10px;
border: 1px solid #e1ece8;
border-radius: 6px;
background: #f8fbfa;
}
.ag-grid-filter-logic-item-title {
min-width: 0;
font-size: 12px;
font-weight: 700;
color: #28484b;
}
.ag-grid-filter-logic-item-values {
grid-column: 1 / -1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
color: #355154;
}
.ag-grid-filter-logic-item-count {
align-self: start;
padding: 1px 6px;
border-radius: 999px;
background: #e7f2ed;
font-size: 11px;
font-weight: 700;
color: #0f6f6d;
}
.ag-grid-filter-logic-operator {
align-self: flex-start;
padding: 2px 7px;
border-radius: 999px;
background: #eef5f2;
font-size: 10px;
font-weight: 700;
color: #2b8c87;
}
.ag-grid-filter-logic-group-select {
width: auto;
min-width: 92px;
height: 26px;
padding: 2px 24px 2px 8px;
font-size: 12px;
}
.ag-grid-tree-grouping-title {
font-size: 18px;
font-weight: 600;
@@ -11102,6 +11319,55 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
margin-bottom: 12px;
}
.ag-grid-tree-layouts-title {
font-size: 18px;
font-weight: 600;
color: #355154;
margin-bottom: 6px;
}
.ag-grid-tree-layouts-current {
margin-bottom: 12px;
}
.ag-grid-tree-layouts-empty {
padding: 8px 0;
}
.ag-grid-tree-layout-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto auto;
gap: 8px;
align-items: center;
padding: 6px 0;
border-top: 1px solid #edf3f0;
}
.ag-grid-tree-layout-row.active .ag-grid-tree-layout-apply {
font-weight: 700;
}
.ag-grid-tree-layout-apply {
min-width: 0;
justify-content: flex-start !important;
padding-left: 0 !important;
padding-right: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
color: #267f82 !important;
text-align: left;
white-space: normal;
overflow-wrap: anywhere;
}
.ag-grid-tree-layouts-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 14px;
}
.ag-grid-tree-grouping-section + .ag-grid-tree-grouping-section {
margin-top: 16px;
}
@@ -11189,12 +11455,16 @@ html[theme="default"] .ag-grid-tree-grouping-panel input[type="checkbox"]:after
}
.ag-grid-tree-host {
flex: 1 1 auto;
min-height: 320px;
flex: 0 0 auto;
min-height: 520px;
min-width: 0;
height: 520px !important;
width: 100%;
max-width: 100%;
border: 1px solid #d6dfdb;
border-radius: 4px;
overflow: hidden;
box-sizing: border-box;
--ag-border-color: #d6dfdb;
--ag-row-border-color: #e3ebe7;
--ag-header-background-color: #f5f8f6;
@@ -11203,6 +11473,109 @@ html[theme="default"] .ag-grid-tree-grouping-panel input[type="checkbox"]:after
--ag-checkbox-unchecked-color: #7a8785;
--ag-checkbox-checked-color: #2b8c87;
--ag-checkbox-indeterminate-color: #2b8c87;
--ag-scrollbar-size: 18px;
}
.ag-grid-tree-host .ag-body-horizontal-scroll,
.ag-grid-tree-host .ag-body-horizontal-scroll-viewport,
.ag-grid-tree-host .ag-body-horizontal-scroll-container {
min-height: 18px !important;
height: 18px !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll.ag-scrollbar-invisible {
display: block !important;
opacity: 1 !important;
visibility: visible !important;
pointer-events: auto !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll.ag-scrollbar-invisible * {
opacity: 1 !important;
visibility: visible !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll-viewport {
overflow-x: scroll !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll.ag-scrollbar-invisible::-webkit-scrollbar,
.ag-grid-tree-host .ag-body-horizontal-scroll-viewport::-webkit-scrollbar {
display: block !important;
height: 18px !important;
}
.ag-grid-tree-external-horizontal-scroll {
display: none;
flex: 0 0 18px;
height: 18px;
min-height: 18px;
min-width: 0;
width: 100%;
max-width: 100%;
overflow-x: scroll;
overflow-y: hidden;
box-sizing: border-box;
contain: layout paint;
border: 1px solid #d6dfdb;
border-top: none;
border-radius: 0 0 4px 4px;
background: #f7faf8;
}
.ag-grid-tree-external-horizontal-scroll-visible {
display: block;
}
.ag-grid-tree-external-horizontal-scroll-inner {
display: block;
height: 1px;
min-height: 1px;
}
.ag-grid-value-set-filter {
width: 240px;
max-width: min(280px, calc(100vw - 32px));
padding: 10px;
color: #355154;
}
.ag-grid-value-set-search {
margin-bottom: 8px;
}
.ag-grid-value-set-actions {
display: flex;
gap: 6px;
margin-bottom: 8px;
}
.ag-grid-value-set-list {
max-height: 260px;
overflow-y: auto;
border: 1px solid #d6dfdb;
border-radius: 4px;
background: #fff;
}
.ag-grid-value-set-option {
display: flex;
align-items: center;
gap: 8px;
min-height: 30px;
margin: 0;
padding: 5px 8px;
font-weight: 500;
white-space: nowrap;
}
.ag-grid-value-set-option:hover {
background: #f5f8f6;
}
.ag-grid-value-set-option input[type="checkbox"] {
flex: 0 0 auto;
margin: 0;
}
.ag-grid-tree-host .ag-header-cell,
@@ -12086,6 +12459,8 @@ html[data-theme-mode="dark"] .screen-container > .filter-box,
html[data-theme-mode="dark"] .screen-container .content-box > .form,
html[data-theme-mode="dark"] .screen-container .content-box > form,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel,
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel,
html[data-theme-mode="dark"] .ag-grid-tree-columns-panel {
background: linear-gradient(180deg, #162220 0%, #141e1d 100%);
border-color: #28403d;
@@ -12096,6 +12471,11 @@ html[data-theme-mode="dark"] .ag-grid-tree-columns-panel {
html[data-theme-mode="dark"] .screen-container .control-label,
html[data-theme-mode="dark"] .screen-container label,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-title,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-title,
html[data-theme-mode="dark"] .ag-grid-filter-logic-title,
html[data-theme-mode="dark"] .ag-grid-filter-logic-item-title,
html[data-theme-mode="dark"] .ag-grid-filter-logic-group-label,
html[data-theme-mode="dark"] .ag-grid-filter-logic-group-title,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-level-text,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-aggregate-label,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-check,
@@ -12124,7 +12504,10 @@ html[data-theme-mode="dark"] .screen-container .btn-group > .btn,
html[data-theme-mode="dark"] .screen-container .filter-box .btn,
html[data-theme-mode="dark"] .ag-grid-tree-columns > .btn,
html[data-theme-mode="dark"] .ag-grid-tree-grouping > .btn,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn {
html[data-theme-mode="dark"] .ag-grid-tree-layouts > .btn,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel .btn,
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn {
background: linear-gradient(180deg, #213130 0%, #1a2726 100%);
border-color: #35504d;
color: #dce7e2;
@@ -12136,12 +12519,37 @@ html[data-theme-mode="dark"] .screen-container .btn-group > .btn:hover,
html[data-theme-mode="dark"] .screen-container .filter-box .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-columns > .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-grouping > .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn:hover {
html[data-theme-mode="dark"] .ag-grid-tree-layouts > .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel .btn:hover,
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn:hover {
background: linear-gradient(180deg, #27403d 0%, #203230 100%);
border-color: #4f716c;
color: #f0faf6;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-help,
html[data-theme-mode="dark"] .ag-grid-filter-logic-empty,
html[data-theme-mode="dark"] .ag-grid-filter-logic-item-values {
color: #aebfba;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-item {
background: #182422;
border-color: #2a403d;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-group {
background: #151f1e;
border-color: #2a403d;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-item-count,
html[data-theme-mode="dark"] .ag-grid-filter-logic-operator {
background: #203230;
color: #8fe1d8;
}
html[data-theme-mode="dark"] .ag-grid-tree-host {
border-color: #2a3f3d;
--ag-background-color: #101817;

3438
dist/tryton-sao.js vendored

File diff suppressed because it is too large Load Diff

View File

@@ -9329,11 +9329,16 @@ html[theme="default"] .carousel-caption h6 {
#tabcontent {
display: block;
width: 100%;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
#tabcontent > .tab-pane > .panel {
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
max-width: 100%;
margin-bottom: 5px;
}
#tabcontent > .tab-pane > .panel > .panel-body {
@@ -9342,9 +9347,14 @@ html[theme="default"] .carousel-caption h6 {
flex-direction: row;
padding-top: 0;
min-height: 0;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
#tabcontent > .tab-pane > .panel > .panel-body > div {
display: inline-flex;
min-width: 0;
max-width: 100%;
padding-left: 15px;
padding-right: 15px;
}
@@ -9355,10 +9365,16 @@ html[theme="default"] .carousel-caption h6 {
/* override bootstrap which sets display to block */
display: flex;
flex: 1;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
#tabcontent[data-view-type="tree"] {
display: flex;
flex: 1;
min-width: 0;
max-width: 100%;
overflow-x: hidden;
}
@media screen and (min-width: 768px) {
#global-search-entry {
@@ -9677,6 +9693,15 @@ img.icon {
flex: 1;
overflow-y: auto;
}
.content-box.ag-grid-content-box {
flex: 0 0 auto;
min-height: 0;
min-width: 0;
width: 100%;
max-width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.tree-container {
display: flex;
flex-direction: column;
@@ -10638,6 +10663,11 @@ img.favorite-icon {
body {
overflow-x: hidden;
}
#tabs,
.main-offcanvas {
min-width: 0;
max-width: 100%;
}
.row-offcanvas {
position: relative;
-webkit-transition: all 0.25s ease-out;
@@ -10921,19 +10951,26 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
display: flex;
flex-direction: column;
min-height: 0;
height: 100%;
min-width: 0;
height: auto;
width: 100%;
max-width: 100%;
overflow: hidden;
box-sizing: border-box;
}
.ag-grid-tree-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: flex-start;
gap: 12px;
padding: 6px 0;
}
.ag-grid-tree-columns > .btn,
.ag-grid-tree-grouping > .btn {
.ag-grid-tree-grouping > .btn,
.ag-grid-tree-layouts > .btn,
.ag-grid-value-filter-mode {
display: inline-flex;
align-items: center;
gap: 8px;
@@ -10951,8 +10988,12 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
.ag-grid-tree-columns > .btn:hover,
.ag-grid-tree-grouping > .btn:hover,
.ag-grid-tree-layouts > .btn:hover,
.ag-grid-value-filter-mode:hover,
.ag-grid-tree-columns > .btn:focus,
.ag-grid-tree-grouping > .btn:focus {
.ag-grid-tree-grouping > .btn:focus,
.ag-grid-tree-layouts > .btn:focus,
.ag-grid-value-filter-mode:focus {
background: linear-gradient(180deg, #f2faf7 0%, #e7f2ed 100%);
border-color: #bfd5cd;
color: #28484b;
@@ -10960,20 +11001,32 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
}
.ag-grid-tree-columns > .btn:active,
.ag-grid-tree-grouping > .btn:active {
.ag-grid-tree-grouping > .btn:active,
.ag-grid-tree-layouts > .btn:active,
.ag-grid-value-filter-mode:active {
transform: translateY(1px);
box-shadow: 0 2px 8px rgba(53, 81, 84, 0.12);
}
.ag-grid-tree-columns-label,
.ag-grid-tree-grouping-label {
.ag-grid-tree-grouping-label,
.ag-grid-tree-layouts-label,
.ag-grid-value-filter-mode-label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.01em;
text-transform: none;
}
.ag-grid-tree-grouping-panel .btn {
.ag-grid-value-filter-mode.active {
background: linear-gradient(180deg, #e0f4f1 0%, #cbe9e3 100%);
border-color: #8fc3bd;
color: #0f6f6d;
}
.ag-grid-tree-grouping-panel .btn,
.ag-grid-tree-layouts-panel .btn,
.ag-grid-filter-logic-panel .btn {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -10992,26 +11045,40 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
}
.ag-grid-tree-grouping-panel .btn:hover,
.ag-grid-tree-grouping-panel .btn:focus {
.ag-grid-tree-grouping-panel .btn:focus,
.ag-grid-tree-layouts-panel .btn:hover,
.ag-grid-tree-layouts-panel .btn:focus,
.ag-grid-filter-logic-panel .btn:hover,
.ag-grid-filter-logic-panel .btn:focus {
background: linear-gradient(180deg, #f2faf7 0%, #e7f2ed 100%);
border-color: #bfd5cd;
color: #28484b;
box-shadow: 0 4px 10px rgba(53, 81, 84, 0.14);
}
.ag-grid-tree-grouping-panel .btn:active {
.ag-grid-tree-grouping-panel .btn:active,
.ag-grid-tree-layouts-panel .btn:active,
.ag-grid-filter-logic-panel .btn:active {
transform: translateY(1px);
box-shadow: 0 1px 5px rgba(53, 81, 84, 0.1);
}
.ag-grid-tree-grouping-panel .btn[disabled],
.ag-grid-tree-grouping-panel .btn.disabled {
.ag-grid-tree-grouping-panel .btn.disabled,
.ag-grid-tree-layouts-panel .btn[disabled],
.ag-grid-tree-layouts-panel .btn.disabled,
.ag-grid-filter-logic-panel .btn[disabled],
.ag-grid-filter-logic-panel .btn.disabled {
opacity: 0.5;
box-shadow: none;
}
.ag-grid-tree-grouping-panel .btn-xs,
.ag-grid-tree-grouping-panel .btn-sm {
.ag-grid-tree-grouping-panel .btn-sm,
.ag-grid-tree-layouts-panel .btn-xs,
.ag-grid-tree-layouts-panel .btn-sm,
.ag-grid-filter-logic-panel .btn-xs,
.ag-grid-filter-logic-panel .btn-sm {
font-size: 12px;
line-height: 1.2;
}
@@ -11095,6 +11162,156 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
z-index: 3000;
}
.ag-grid-tree-layouts-panel {
width: 520px;
max-width: calc(100vw - 24px);
max-height: min(70vh, 640px);
overflow: auto;
padding: 14px;
background: #fff;
border: 1px solid #d6dfdb;
border-radius: 6px;
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.16);
z-index: 3000;
}
.ag-grid-filter-logic-panel {
width: 360px;
max-width: calc(100vw - 24px);
max-height: min(70vh, 640px);
overflow: auto;
padding: 14px;
background: #fff;
border: 1px solid #d6dfdb;
border-radius: 6px;
color: #355154;
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.16);
z-index: 3000;
}
.ag-grid-filter-logic-title {
margin-bottom: 10px;
font-size: 18px;
font-weight: 600;
color: #355154;
}
.ag-grid-filter-logic-mode {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 10px;
}
.ag-grid-filter-logic-mode .btn.active,
.ag-grid-filter-logic-group-controls .btn.active,
.ag-grid-filter-logic-group-header .btn.active {
background: linear-gradient(180deg, #e0f4f1 0%, #cbe9e3 100%);
border-color: #8fc3bd;
color: #0f6f6d;
}
.ag-grid-filter-logic-help,
.ag-grid-filter-logic-empty {
font-size: 12px;
line-height: 1.35;
color: #6a7b7a;
}
.ag-grid-filter-logic-help {
margin-bottom: 12px;
}
.ag-grid-filter-logic-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.ag-grid-filter-logic-group-controls,
.ag-grid-filter-logic-group-header {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.ag-grid-filter-logic-group-controls {
margin-bottom: 4px;
}
.ag-grid-filter-logic-group-label,
.ag-grid-filter-logic-group-title {
font-size: 12px;
font-weight: 700;
color: #28484b;
}
.ag-grid-filter-logic-group {
display: flex;
flex-direction: column;
gap: 8px;
padding: 10px;
border: 1px solid #dce9e4;
border-radius: 6px;
background: #fbfdfc;
}
.ag-grid-filter-logic-item {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 4px 10px;
padding: 8px 10px;
border: 1px solid #e1ece8;
border-radius: 6px;
background: #f8fbfa;
}
.ag-grid-filter-logic-item-title {
min-width: 0;
font-size: 12px;
font-weight: 700;
color: #28484b;
}
.ag-grid-filter-logic-item-values {
grid-column: 1 / -1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
color: #355154;
}
.ag-grid-filter-logic-item-count {
align-self: start;
padding: 1px 6px;
border-radius: 999px;
background: #e7f2ed;
font-size: 11px;
font-weight: 700;
color: #0f6f6d;
}
.ag-grid-filter-logic-operator {
align-self: flex-start;
padding: 2px 7px;
border-radius: 999px;
background: #eef5f2;
font-size: 10px;
font-weight: 700;
color: #2b8c87;
}
.ag-grid-filter-logic-group-select {
width: auto;
min-width: 92px;
height: 26px;
padding: 2px 24px 2px 8px;
font-size: 12px;
}
.ag-grid-tree-grouping-title {
font-size: 18px;
font-weight: 600;
@@ -11102,6 +11319,55 @@ html[theme="default"] .screen-container .nav-tabs > li.active > a:hover {
margin-bottom: 12px;
}
.ag-grid-tree-layouts-title {
font-size: 18px;
font-weight: 600;
color: #355154;
margin-bottom: 6px;
}
.ag-grid-tree-layouts-current {
margin-bottom: 12px;
}
.ag-grid-tree-layouts-empty {
padding: 8px 0;
}
.ag-grid-tree-layout-row {
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto auto;
gap: 8px;
align-items: center;
padding: 6px 0;
border-top: 1px solid #edf3f0;
}
.ag-grid-tree-layout-row.active .ag-grid-tree-layout-apply {
font-weight: 700;
}
.ag-grid-tree-layout-apply {
min-width: 0;
justify-content: flex-start !important;
padding-left: 0 !important;
padding-right: 0 !important;
border: none !important;
background: transparent !important;
box-shadow: none !important;
color: #267f82 !important;
text-align: left;
white-space: normal;
overflow-wrap: anywhere;
}
.ag-grid-tree-layouts-actions {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 14px;
}
.ag-grid-tree-grouping-section + .ag-grid-tree-grouping-section {
margin-top: 16px;
}
@@ -11189,12 +11455,16 @@ html[theme="default"] .ag-grid-tree-grouping-panel input[type="checkbox"]:after
}
.ag-grid-tree-host {
flex: 1 1 auto;
min-height: 320px;
flex: 0 0 auto;
min-height: 520px;
min-width: 0;
height: 520px !important;
width: 100%;
max-width: 100%;
border: 1px solid #d6dfdb;
border-radius: 4px;
overflow: hidden;
box-sizing: border-box;
--ag-border-color: #d6dfdb;
--ag-row-border-color: #e3ebe7;
--ag-header-background-color: #f5f8f6;
@@ -11203,6 +11473,109 @@ html[theme="default"] .ag-grid-tree-grouping-panel input[type="checkbox"]:after
--ag-checkbox-unchecked-color: #7a8785;
--ag-checkbox-checked-color: #2b8c87;
--ag-checkbox-indeterminate-color: #2b8c87;
--ag-scrollbar-size: 18px;
}
.ag-grid-tree-host .ag-body-horizontal-scroll,
.ag-grid-tree-host .ag-body-horizontal-scroll-viewport,
.ag-grid-tree-host .ag-body-horizontal-scroll-container {
min-height: 18px !important;
height: 18px !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll.ag-scrollbar-invisible {
display: block !important;
opacity: 1 !important;
visibility: visible !important;
pointer-events: auto !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll.ag-scrollbar-invisible * {
opacity: 1 !important;
visibility: visible !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll-viewport {
overflow-x: scroll !important;
}
.ag-grid-tree-host .ag-body-horizontal-scroll.ag-scrollbar-invisible::-webkit-scrollbar,
.ag-grid-tree-host .ag-body-horizontal-scroll-viewport::-webkit-scrollbar {
display: block !important;
height: 18px !important;
}
.ag-grid-tree-external-horizontal-scroll {
display: none;
flex: 0 0 18px;
height: 18px;
min-height: 18px;
min-width: 0;
width: 100%;
max-width: 100%;
overflow-x: scroll;
overflow-y: hidden;
box-sizing: border-box;
contain: layout paint;
border: 1px solid #d6dfdb;
border-top: none;
border-radius: 0 0 4px 4px;
background: #f7faf8;
}
.ag-grid-tree-external-horizontal-scroll-visible {
display: block;
}
.ag-grid-tree-external-horizontal-scroll-inner {
display: block;
height: 1px;
min-height: 1px;
}
.ag-grid-value-set-filter {
width: 240px;
max-width: min(280px, calc(100vw - 32px));
padding: 10px;
color: #355154;
}
.ag-grid-value-set-search {
margin-bottom: 8px;
}
.ag-grid-value-set-actions {
display: flex;
gap: 6px;
margin-bottom: 8px;
}
.ag-grid-value-set-list {
max-height: 260px;
overflow-y: auto;
border: 1px solid #d6dfdb;
border-radius: 4px;
background: #fff;
}
.ag-grid-value-set-option {
display: flex;
align-items: center;
gap: 8px;
min-height: 30px;
margin: 0;
padding: 5px 8px;
font-weight: 500;
white-space: nowrap;
}
.ag-grid-value-set-option:hover {
background: #f5f8f6;
}
.ag-grid-value-set-option input[type="checkbox"] {
flex: 0 0 auto;
margin: 0;
}
.ag-grid-tree-host .ag-header-cell,
@@ -12086,6 +12459,8 @@ html[data-theme-mode="dark"] .screen-container > .filter-box,
html[data-theme-mode="dark"] .screen-container .content-box > .form,
html[data-theme-mode="dark"] .screen-container .content-box > form,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel,
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel,
html[data-theme-mode="dark"] .ag-grid-tree-columns-panel {
background: linear-gradient(180deg, #162220 0%, #141e1d 100%);
border-color: #28403d;
@@ -12096,6 +12471,11 @@ html[data-theme-mode="dark"] .ag-grid-tree-columns-panel {
html[data-theme-mode="dark"] .screen-container .control-label,
html[data-theme-mode="dark"] .screen-container label,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-title,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-title,
html[data-theme-mode="dark"] .ag-grid-filter-logic-title,
html[data-theme-mode="dark"] .ag-grid-filter-logic-item-title,
html[data-theme-mode="dark"] .ag-grid-filter-logic-group-label,
html[data-theme-mode="dark"] .ag-grid-filter-logic-group-title,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-level-text,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-aggregate-label,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-check,
@@ -12124,7 +12504,10 @@ html[data-theme-mode="dark"] .screen-container .btn-group > .btn,
html[data-theme-mode="dark"] .screen-container .filter-box .btn,
html[data-theme-mode="dark"] .ag-grid-tree-columns > .btn,
html[data-theme-mode="dark"] .ag-grid-tree-grouping > .btn,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn {
html[data-theme-mode="dark"] .ag-grid-tree-layouts > .btn,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel .btn,
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn {
background: linear-gradient(180deg, #213130 0%, #1a2726 100%);
border-color: #35504d;
color: #dce7e2;
@@ -12136,12 +12519,37 @@ html[data-theme-mode="dark"] .screen-container .btn-group > .btn:hover,
html[data-theme-mode="dark"] .screen-container .filter-box .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-columns > .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-grouping > .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn:hover {
html[data-theme-mode="dark"] .ag-grid-tree-layouts > .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-grouping-panel .btn:hover,
html[data-theme-mode="dark"] .ag-grid-tree-layouts-panel .btn:hover,
html[data-theme-mode="dark"] .ag-grid-filter-logic-panel .btn:hover {
background: linear-gradient(180deg, #27403d 0%, #203230 100%);
border-color: #4f716c;
color: #f0faf6;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-help,
html[data-theme-mode="dark"] .ag-grid-filter-logic-empty,
html[data-theme-mode="dark"] .ag-grid-filter-logic-item-values {
color: #aebfba;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-item {
background: #182422;
border-color: #2a403d;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-group {
background: #151f1e;
border-color: #2a403d;
}
html[data-theme-mode="dark"] .ag-grid-filter-logic-item-count,
html[data-theme-mode="dark"] .ag-grid-filter-logic-operator {
background: #203230;
color: #8fe1d8;
}
html[data-theme-mode="dark"] .ag-grid-tree-host {
border-color: #2a3f3d;
--ag-background-color: #101817;

File diff suppressed because it is too large Load Diff