Deux bugs découverts en usage réel sur /tableau :
1. filtermodel_to_ast lisait condition1/condition2 pour un filtre à
deux conditions (ET/OU) sur une colonne — mais AG Grid >=29.2 (la
version 35.2.0 utilisée ici) encode ça via une liste `conditions`,
confirmé par la doc Dash AG Grid "Filter Model & Dash Callbacks" >
"Filter Model Multiple Conditions". Le filtre était donc
silencieusement ignoré (colonne exclue du AST, comme si aucun
filtre n'était posé), d'où des résultats sans rapport avec les
valeurs saisies. Corrigé : filtermodel_to_ast lit désormais
`conditions` (N éléments) en priorité, avec repli sur
condition1/condition2 (forme dépréciée mais "still accepted" selon
AG Grid). L'inverse (ast_to_filtermodel, utilisé au rappel d'une
vue sauvegardée) produit aussi la forme `conditions`.
2. Le bouton "Réinitialiser" ("Supprime tous les filtres et les tris")
ne réinitialisait que filterModel, jamais le tri. Corrigé via
resetColumnState (remet les colonnes à l'état de columnDefs, qui
reflète déjà la visibilité choisie via le sélecteur de colonnes —
seul le tri est donc affecté).
Reproduit et corrigé en TDD (tests/test_query_ast.py,
tests/test_grid.py), vérifié manuellement en navigateur par l'auteur
du rapport de bug.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Menu de filtre de colonne (Contient, Égal à, Vide, ET/OU, etc.) traduit
via l'option native AG Grid localeText, exposée par dashGridOptions.
N'affecte pas l'apparence de base conservée au Lot 1 (aucun thème/CSS
custom) — uniquement le texte des libellés.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Les tests qui démarrent l'app complète (Selenium) écrivent dans la base
users pointée par USERS_DB_PATH (comptes créés, vues sauvegardées...).
Comme ce fichier était le fixture committé lui-même, chaque exécution de
la suite le laissait modifié dans l'arbre de travail — gênant pour les
commits et le nettoyage de worktree.
Même schéma déjà utilisé pour DUCKDB_PATH et DATA_SCHEMA_CACHE dans ce
fichier : le fixture committé est copié vers une base jetable gitignorée
(tests/users.runtime.sqlite) au chargement de conftest.py, et
USERS_DB_PATH pointe sur la copie. tests/users.test.sqlite reste
désormais toujours propre.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
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>
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>
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>
_reabo_button() ne prend plus has_used_trial (bouton de réabonnement
simplifié) ; les deux anciens tests testant M'abonner/Me réabonner
sont remplacés par un test du comportement actuel.
Le callback _toggle_submit référence inf-cb-retractation/inf-cb-cgu en
Input sans condition, mais ces cases n'étaient rendues qu'en mode
"subscribe". Elles sont maintenant toujours montées (masquées et
pré-cochées en mode configure) pour que Dash trouve toujours ces ids.
Ajoute la fonction _change_hint et étend le callback _select_plan pour afficher
un hint "changement à la prochaine échéance" quand l'utilisateur sélectionne
un plan différent du plan courant.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>