Le padding vertical (.375rem) et le line-height (1.5) de .btn nécessitent 38px
alors que le bouton a une hauteur fixe de 34px (alignée sur l'input) : le
glyphe débordait vers le bas au lieu d'être centré.
Centrage en flex + neutralisation du padding vertical, pour que l'alignement
ne dépende plus du line-height.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le bundle dash-ag-grid (async-community.js) fuit un helper esbuild sous le nom
global `L`, écrasant le window.L de Leaflet. Nos fonctions clientside
pointToLayer/clusterToLayer lisaient ce global → `L.point`/`L.circleMarker is
not a function` → l'exception cassait tout le calque GeoJSON → carte vide.
Course entre le chunk AG Grid et le rendu : d'où le pattern « surtout avec
beaucoup de marchés ».
Une IIFE capture en privé le vrai Leaflet (celui exposant circleMarker) en
écoutant les affectations de window.L, sans changer ce que window.L renvoie
(AG Grid garde son helper). pointToLayer/clusterToLayer utilisent
window.leafletReal(). Nettoie aussi des console.log oubliés et un `color`
inutilisé dans clusterToLayer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
compute_considerations_stats initialisait les défauts `{key}_renseignees` en
2-uplets `(0, 0)` mais get_considerations_card_content les dépaquette en
3-uplets. Quand une colonne (considerationsSociales/Environnementales) est
absente du schéma filtré (fréquent avec peu de marchés sélectionnés), le défaut
survivait → ValueError: not enough values to unpack (expected 3, got 2).
Défaut porté à `(0, 0, 0)` : la barre dégrade à 0 % au lieu de planter.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le bouton utilisait height:auto, dépendant du padding/line-height par
défaut de .btn (~38px), plus haut que l'input fixé à 34px. Fixe la
hauteur du bouton à 34px pour qu'il s'aligne avec l'input.
Inclut aussi les changements en cours sur recherche.py (tagline
dynamique avec stats, home_intro, layout en fonction).
Les jetons MCP sont désormais chiffrés (Fernet dérivée de SECRET_KEY) en plus
du hash conservé pour l'auth, permettant leur ré-affichage/copie à tout moment.
Getter scopé au propriétaire, dégradation propre si clé absente/changée.
Migration 0013 + colonne token_enc. UI alignée sur « Copier le lien » des vues.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Championnat mensuel (fenêtre glissante sur created_at), recharge des
votes le lundi (Europe/Paris) sans report, pas de cap par feature, et
précondition de déploiement gatée sur le nombre de votants.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Le label du checklist CGU mélangeait des chaînes brutes et un composant
html.A dans une liste, ce que le rendu compound-label de dcc.Checklist
ne supporte pas (chaque item passe par ExternalWrapper qui suppose un
vrai composant Dash). Ça crashait en boucle et déclenchait des dizaines
de re-render, ce qui faisait aussi clignoter le lien Abonnement dans le
menu latéral. Fix : tout regrouper dans un seul html.Span.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Dropdown « Mes vues » : ajoute en tête un lien « Gérer mes vues » (couleur
primary) vers /compte/vues, séparé de la liste des vues.
- Corrige l'override de --bs-dropdown-link-hover-bg : Bootstrap 5.3 scope cette
variable sur .dropdown-menu, donc un override sur :root est masqué. Déplacé
sur .dropdown-menu.
Alphabet du jeton passé de base62 (a-z A-Z 0-9) à base36 (a-z 0-9), longueur
inchangée (6). Lien plus lisible/dictable et cohérent avec le slug déjà en
minuscules. Les jetons déjà générés (à casse mixte) restent valides (lookup par
match exact).
- Bouton de copie explicite (icône copy.svg + « Copier le lien » + retour
« ✓ Copié ») sur /tableau et /compte/vues, via dcc.Clipboard (children /
copied_children), à la place de l'icône seule.
- Le lien direct s'affiche en texte (span#share-url-text) plutôt qu'un
<input> : évite la troncature d'affichage du champ Bootstrap form-control en
flex (zone de texte bloquée ~218px), montre tout le lien avec retour à la
ligne, et prend la largeur du lien. Stylé comme un champ (bordure, coins
arrondis, texte 90%).
- Instructions /compte/vues simplifiées ; E2E adapté (#share-url-text).
Le datasource _get_rows des grilles acheteur/titulaire mélangeait une sortie
MATCH (getRowsResponse de la grille pattern-matching) avec deux sorties fixes
(<org>-total / -total-unique). Dash l'interdit : le dev-renderer (mode debug de
run.py) lève « MATCH wildcards must be on the same keys for all Outputs » (4
erreurs : 2 par page). Le callback échoue au dispatch et la grille reste vide.
Correctif : _get_rows n'a plus qu'une sortie MATCH (getRowsResponse) ; les
stores totaux (id fixes) sont alimentés impérativement via dash.set_props.
Test de régression en debug=True (dev-renderer) : sans le correctif la grille ne
charge aucune ligne ; avec, lignes + compteur « N marchés » présents.
La barre des vues sauvegardées restait masquée pour les non-abonnés via un
style inline display:none — inopérant car .d-inline-flex est
display:inline-flex !important, la barre était donc toujours visible.
La barre reste désormais visible pour tous ; « Sauvegarder la vue » et
« Mes vues » sont grisés et désactivés (disabled) pour les non-abonnés. Le
gating serveur de save_view (prepare_view_to_save) reste inchangé.
Remplace le verrou de dérive à compteur (suppress-next) par une détection
événementielle : eventListeners AG Grid (filterChanged/sortChanged) →
dashAgGridFunctions.hideShareOnUserAction, qui efface active-view sur action
utilisateur (source != 'api') et ignore l'écho de l'application programmatique.
Le compteur suppress-next souffrait d'une course d'ordonnancement Dash (l'écho
lisait la valeur pré-batch) et le diff de columnState était impraticable (état
réémis bruité). La visibilité du bloc bascule via la classe (d-flex/d-none) et
non le style inline, car .d-flex est display:flex !important.
Task 7 : test E2E de bout en bout (application + masquage sur action).