Vérifie via Selenium/DashComposite que /tableau charge et affiche la
grille AG Grid avec au moins une ligne rendue, sans erreur console
SEVERE. Dernière tâche de la migration DataTable -> AG Grid.
Décrit les filtres de colonne AG Grid (flottant/entonnoir, texte/numérique/
date, combinaison ET/OU), le tri multi-colonne (Maj+clic) et le défilement
infini, à la place de l'ancienne syntaxe icontains/i</i> et des liens
d'exemple ?filtres=... (mécanisme retiré à la tâche 10). Retire la ligne
"Partager la vue" de la légende des boutons (bouton supprimé).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Les vues stockent désormais {filterModel, columnState} en JSON dans
saved_views.query au lieu d'une query string DSL. Le rappel d'une vue
applique filterModel + columnState à la grille AG Grid via un nouveau
callback apply_saved_view, déclenché par pattern-matching sur les items
du menu "Mes vues" (désormais cliquables au lieu de liens href).
Retire restore_view_from_url, sync_url_and_reset_button,
show_confirmation, le bouton "Partager la vue" et le clientside
clean_filters de tableau.py - la migration AG Grid retire le mécanisme
d'URL riche sans rétrocompatibilité.
Le lien "Ouvrir" de compte/vues.py pointe maintenant vers /tableau nu
(limitation connue documentée, le rappel cross-page reste à faire).
Rewrite download_data to read filterModel/columnState from the AG Grid
component and add export_dataframe (compiles filterModel to SQL via
filtermodel_to_ast/ast_to_sql, builds ORDER BY, excludes hidden columns,
queries DuckDB via query_marches). Replaces the old Polars filter_query
pipeline tied to the removed DataTable.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
apply_hidden_columns régénère columnDefs (via grid_column_defs) sur
tableau_grid quand le Store tableau-hidden-columns change, remplaçant
store_hidden_columns qui ciblait l'ancienne prop hidden_columns de la
DataTable (supprimée en tâche 7). update_checkboxes_from_hidden_columns
lit désormais directement le Store plutôt que la prop de la DataTable
disparue, pour que la synchronisation cases à cocher <-> colonnes
masquées continue de fonctionner.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Remplace le composant DataTable et le callback update_table de tableau.py
par la grille dash-ag-grid (mode ligne infini) et un callback get_rows_tableau
piloté par getRowsRequest/getRowsResponse, plus un callback update_meta qui
synchronise nb_rows/btn-download-data/download-hint via un dcc.Store du total.
Les autres callbacks de la page (sélecteur de colonnes, vues sauvegardées,
export, restauration URL, aide) référencent encore les anciens
id/props (tableau_datatable, hidden_columns, filter_query, sort_by) et seront
mis à jour dans les tâches suivantes (8-11) du plan de migration #41.
Ajoute sort_model_to_sql (adapte le sortModel AG Grid vers sort_by_to_sql
existant) et ast_to_dict/ast_from_dict pour le round-trip JSON de l'AST,
nécessaire aux vues sauvegardées.
- `range` était ignoré silencieusement (TRUE, pas de filtre) sur les
colonnes texte/date car seul `_numeric_to_sql` le gérait. Ajout du
cas `range` dans la branche texte/date (BETWEEN, CAST VARCHAR pour
les dates, comme les autres opérateurs de comparaison).
- `blank`/`notBlank` comparaient toujours à `''`, ce qui fait planter
DuckDB (Conversion Error) sur les colonnes numériques/date. Le
check est déplacé après le calcul de is_numeric/col_is_date : ces
types utilisent IS [NOT] NULL sans comparaison à chaîne vide.
Ajoute une représentation canonique du filtre sous forme d'AST booléen
(Condition/And/Or/Not) et son compilateur vers SQL DuckDB paramétré
(ast_to_sql). Réutilise tokenize_text_filter pour les feuilles texte.
Fondation pour la migration /tableau vers dash-ag-grid : cet AST sera
alimenté par le filterModel d'AG Grid (tâche suivante) et, plus tard,
par un champ de requête booléenne libre (#97).
Ajoute des tests de bout en bout pour les filtres montant/date/cpv, le
chemin titulaire de search_organisations, et la pagination (page>1,
clamping page=0). Normalise montant_total en float dans les deux
branches de compute_org_stats.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dash 4 utilise le token CSS --Dash-Fill-Interactive-Strong (violet par
défaut) pour l'état actif/focus des composants dcc (Dropdown, Input,
Tabs, DatePicker...). Surchargé au :root avec var(--primary-color).
Dash 4 ajoute des boutons +/- aux dcc.Input type="number" ; inutiles pour
des montants et prennent de la place, retirés via .dash-input-stepper
(l'input récupère l'espace grâce à son flex: 1 1 0).
Dash 4.4 remplace complètement le react-select v1 sous-jacent de
dcc.Dropdown par un nouveau composant (classes dash-dropdown-*) : les 11
Dropdown de l'app (acheteur.py, titulaire.py, observatoire.py, dont 5
multi=True) restent fonctionnels tels quels — ouverture, recherche,
sélection simple/multiple, fermeture. Le nouveau défaut
closeOnSelect=False sur les multi-select (menu qui reste ouvert après
sélection) est accepté sans correction, conformément au plan.
Retrait de la règle CSS .Select--multi .Select-value (style.css),
devenue totalement inerte : dcc.Dropdown ne rend plus ces classes
react-select, et aucune colonne dropdown de dash_table (admin) n'est
configurée en multi-select. Les autres règles .Select-* (Select-menu-outer,
Select-placeholder) sont conservées : elles servent encore l'éditeur de
cellules dropdown de dash_table (hors périmètre de cette migration).
Le callback Dash _update_table est un endpoint serveur global
(/_dash-update-component) invocable indépendamment du layout : la garde
is_admin() de layout() ne protégeait que l'affichage. Sans contrôle dans
le callback, un non-admin — voire un anonyme sur le chemin lecture —
pouvait lire/écrire toute la base SQLite utilisateurs.
Ajoute la garde en tête du callback + test de non-régression.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>