# Changelog - FlowDeck ## v7.45.5 (2026-10-03) — Poubelle : actions groupées, tri/filtres réels, purge, et 4 bugs ### Added - **Sélection multiple** sur /trash : case « Select all » (portée au filtre courant), barre d'actions groupées **Restore / Delete / Clear** avec compteur, et compteur de résultats (`N pages` / `N of M pages`). - **Empty Trash** : purge totale en un clic (confirm) via le nouveau `POST /board/api/trash/empty` — traitement en masse côté serveur (une seule requête, pas N appels). - **Tri** : Recently deleted (défaut) / Oldest first / Page name A → Z — remplace le bouton décoratif « Last edited by ▾ » qui ne faisait rien. - **Filtre par emplacement** réel (`In ▾` décoratif remplacé) : liste déroulante construite depuis les workspaces présents dans la poubelle, avec état actif. - **Dates par élément** : « Deleted 3 days ago · 27 days left » (rétention 30 j alignée sur `app/services/trash.py`), horodatages UTC ou ISO gérés. - **États vides distincts** : poubelle vide vs aucun résultat pour les filtres (avec bouton « Clear filters »), et **toasts** sur chaque action (succès et échec) au lieu d'échecs silencieux. ### Fixed - **Les boutons Restore / Delete ne marchaient JAMAIS** : `getCsrf()` renvoie la CHAÎNE du jeton mais le code faisait `csrf?.[1]` → 2ᵉ caractère → 403 CSRF systématique, avalé par `if (r.ok)`. Corrigé + toasts d'erreur. - **« Move to Trash » depuis l'éditeur envoyait une 404** : la route appelée (`/board/api/pages/{id}/trash`) n'existe pas — route réelle `/api/pages/{id}/trash` — et le `.then()` naviguait quand même, donc la page partait à l'accueil SANS être mise à la poubelle. URL corrigée + on ne navigue plus si la réponse n'est pas ok. - **Une page restaurée disparaissait de Library / Recents / Private** : la suppression depuis l'éditeur réécrivait `parent_section='Trash'` et la restauration ne le remettait pas, alors que tous les listings filtrent `parent_section != 'Trash'`. `deleted_at` est maintenant la seule source de vérité (écriture retirée) + réparation au boot des lignes déjà cassées (`db.init_db`, idempotente). - **Routes trash sans aucune authentification** : `GET /board/api/trash`, `restore`, `delete` et `POST /api/pages/{id}/trash` ne vérifiaient rien (le CSRF ne protège pas : cookie lisible + en-tête forgé par l'attaquant) → 401 obligatoire, comme les routes sœurs du même fichier. Vérifié anonyme : 401. - Le sidebar de /trash listait `parent_section='Trash'` → aligné sur `deleted_at IS NOT NULL`. ### Tests - `tests/test_trash_api.py` (5 tests) : auth 401, soft-delete sans marqueur `Trash`, restauration, suppression définitive, purge en masse (ne touche pas aux pages vivantes), réparation au boot. - `e2e/trash_ui.spec.js` : rendu, dates, sélection groupée, restauration unitaire (le vrai test du fix CSRF), purge — noms uniques par exécution et garde « on ne vide jamais la poubelle d'autrui ». - `test_smoke_uncovered.py` : l'assertion qui codait le bug (`parent_section == 'Trash'`) corrigée. ## v7.45.4 (2026-10-03) — Anti-FOUC au chargement complet + morts nettoyés ### Fixed - **Flashs au chargement COMPLET** (F5, première visite, navigation servie par le service worker) : le masquage `x-cloak`/`opacity` de v7.45.3 ne couvrait que les swaps partiels fdLoad — un chargement de document peignait la page tant qu'Alpine n'avait pas initialisé `.app-layout`, donc sidebar brute (toutes sections ouvertes, menu utilisateur visible) **et** contenu de la zone dont la bande rouge « You are offline. Changes will sync when connection is restored. » (aucun `x-cloak` sur elle). Fix : `x-cloak` sur le nœud racine Alpine `.app-layout` (base.html) — tout l'app (sidebar + zone + bandeau) reste masqué tant que `appState()` n'est pas monté, puis Alpine retire l'attribut. Vérifié par le probe (3 pages × plein chargement) : 0 frame de contenu brut, `x-cloak` retiré et `display:flex` à la fin (donc pas de page blanche). ### Changed - **`fd-navigating` supprimée** : classe posée/retirée à chaque `fdLoad` mais sans aucune règle CSS dans le dépôt (grep css/js/html → seulement app.js) — code mort. - **`e2e/probe_nav_perf.spec.js` étendu à 4 scénarios avec assertions** : navigations partielles (5 pages), **clic réel sur le bouton Home**, Home avec réseau coupé (SW actif), et plein chargement. Asserte : 0 frame de contenu brut peint, zone révélée (`opacity:1`) et montée (`0 [x-show]` non montés, `x-ignore` absent), `.app-layout` sans `x-cloak` et visible. Capture screenshot automatique si du contenu brut est peint + collecte console. ### Not reproduced - Le symptôme rapporté (Home → rafale de menus/fenêtres + bande rouge) n'est **pas rejouable** dans un navigateur frais : clic Home en ligne comme hors ligne, nav partielle et plein chargement donnent 0 frame de contenu brut et 0 erreur console. Reste à confirmer côté navigateur signalé (recharge dure après deploy, URL/instance testée). ## v7.45.3 (2026-10-03) — Navigation partielle : le contenu brut n'est plus peint ### Fixed - **Flashs de fenêtres / frames à chaque changement de page ou de section** : pendant la fenêtre `x-ignore` (swap → `Alpine.initTree`), la zone `.main-wrapper` était peinte **non montée** — tous ses `[x-show]` visibles à leur valeur brute (menus, panneaux, états loading/empty/table superposés), puis masqués d'un coup au montage Alpine. Mesure (`e2e/probe_nav_perf.spec.js`, instance locale) : **19 éléments bruts visibles sur 87 ms** en arrivant sur /library (CLS 0.149, sources `lib-loading`/`lib-empty`/`lib-table`), **80 éléments sur 732 ms** sur /settings, 7 sur /workspaces, 0 sur /trash. Fix : `opacity: 0` + `pointer-events: none` posés **dans** le handler `htmx:afterSwap` (même task que le swap → aucun paint intermédiaire possible) et retirés **après** `Alpine.initTree` sur les 3 chemins de démontage (scripts chargés, zéro script, filet 4 s). Seul le contenu monté est peint. ### Added - **`e2e/probe_nav_perf.spec.js`** — probe de fluidité de navigation : marques htmx (`beforeRequest`/`beforeSwap`/`afterSwap`/`afterSettle`), fenêtre `x-ignore`, échantillon par frame du nombre d'`[x-show]` bruts encore visibles et d'`[x-cloak]` masqués, `layout-shift` (CLS) avec sources. `node node_modules/@playwright/test/cli.js test probe_nav_perf` (npx est cassé sur ce poste). ## v7.45.2 (2026-10-03) — Navigation partielle : montage Alpine sans course + scripts idempotents ### Fixed - **Cascades d'erreurs Alpine en navigation partielle** (« Undefined variable: … » puis « reading 'has' » sur `$store.fdCtx`) : sur un swap fdLoad, les `