diff --git a/CHANGELOG.md b/CHANGELOG.md index a45dc0a..ad420cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,61 @@ # Changelog - FlowDeck +## v7.67.0 (2026-10-08) — Réactions dans le tiroir Comments (+ suppression) et refonte du menu de sélection + +### Added + +- **Les réactions vivent dans le tiroir « Comments »** : section **Reactions** + au-dessus des fils — émoji, compte (si >1) et **texte ancré** lu dans le DOM + (`reactionList()` / `_anchorText()`, offsets source hors pastilles). L'état + vide « No comments yet » ne s'affiche plus s'il reste des réactions. +- **Suppression d'une réaction — deux entrées, un seul chemin** : + - **✕** sur la ligne de la section Reactions (visible uniquement sur **mes** + réactions) ; + - au **survol de la pastille**, l'émoji que j'ai posé devient une **croix** + (`::after`, aucun nœud ajouté → offsets source inchangés), un clic retire. + - les deux appellent `removeReaction()` → `POST /reactions` (toggle) → + `loadReactions()` + repeindre les ancres. + +### Changed + +- **Refonte du menu de sélection façon capture** : + - ligne 2 `[A] B I U T Tx` (le barré est conservé — absent de la maquette, + décision volontaire pour ne pas perdre la fonction) ; + - ligne 3 `🔗 S √x …` (la réaction en est sortie) ; + - **ligne 4 = une rangée scannée** : `💬 Comment` (libellé) à gauche, + `🙂+` réaction à droite (`.ft-row-split`) ; + - entête **Skills** avec `≡` à droite (`.ft-skills-head::after`), liste + **scrollable** (`.ft-skills`, `max-height` + `overflow-y`) ; + - **✨ Ask AI retiré** de la toolbar : doublon exact de « Edit with AI » du + pied (même `fmtAskAI()`). + +### Fixed + +- **Flake de gate corrigé (racine)** : `test_v55.py::TestOGParser:: + test_fetch_og_metadata_success` dépendait d'un **vrai** `socket.getaddrinfo + ("example.com")` via le garde SSRF `_is_public_host` ; sous `pytest -n auto` + un `socket.timeout` (non couvert par `except socket.gaierror`) remontait + dans le `except Exception` de `fetch_og_metadata` → repli silencieux + (`title='example.com'`) → AssertionError, 3 fois sur 5 runs. + - `_is_public_host` catch désormais **`OSError`** : le garde renvoie un + booléen, il ne lève jamais (les autres appelants gagnent aussi) ; + - fixture `stub_dns` sur `TestOGParser` (même motif que + `test_agent_web_tools.stub_dns`) : zéro DNS dans les tests OG. + +### Tests + +- `tests/test_v767_reactions_drawer.py` (3) ; `tests/test_v762_selection_toolbar.py` + (ligne 4 + styles) ; `tests/test_v764_comments_reactions.py` (position de + `fmtReact`). +- **e2e** : `v764_comments_reactions` étendu — section Reactions dans le tiroir + (texte ancré), **suppression A** (✕ du tiroir → pastille disparue), + **suppression B** (croix `::after` visible seulement au survol, puis clic) ; + `v762_selection_toolbar` — `Comment` + `ft-row-split .ft-react`, + `ft-skills-head` = « Skills », plus de bouton ✨. +- `pytest tests/ -q -n auto` → **1390 passed, 0 failed** (flake corrigé), + `ruff check app tests` → OK. + + ## v7.66.0 (2026-10-08) — Escape du menu slash retire le « / » + bouton « commenter » à droite du bloc ### Added diff --git a/ROADMAP.md b/ROADMAP.md index 8d64af3..9e331d8 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1501,6 +1501,29 @@ Détails livrés : `tests/test_v766_slash_esc_comment_btn.py` (3) ; `pytest` **1386 passed**, `ruff` OK ; `VERSION` + `app/main.py` = 7.66.0 +### v7.67.0 — Réactions dans le tiroir + suppression + refonte du menu de sélection ✅ (2026-10-08) +> **Objectif** : une réaction s'ajoute/supprime depuis le tiroir Comments, et +> le menu de sélection correspond à la maquette ASCII fournie. **COMPLETED**. + +- [x] **Section « Reactions » du tiroir** — `reactionList()` + `_anchorText()` + (texte de la plage lu dans le DOM, hors pastilles), compte si >1, état vide + adapté ; `removeReaction()` = POST toggle +- [x] **Suppression** — ✕ dans le tiroir (mes réactions seulement) **et** + croix `::after` au survol de la pastille sur l'émoji que j'ai posé (aucun + nœud ajouté → offsets source intacts) +- [x] **Refonte du menu** — ligne 4 scannée `💬 Comment | 🙂 réaction`, + réaction sortie de la ligne 3, entête `Skills ≡`, liste Skills scrollable, + `✨ Ask AI` retiré (doublon exact du pied) + - écart volontaire à la maquette : le **barré (T)** de la ligne 2 est + conservé (il n'y figure pas) pour ne pas perdre la fonction +- [x] **Flake de gate corrigé** — `_is_public_host` attrape `OSError` (le + garde SSRF ne lève plus) + fixture `stub_dns` sur `TestOGParser` + (le test faisait un vrai `getaddrinfo("example.com")`, échec sous `-n auto`) +- [x] **Tests** — `tests/test_v767_reactions_drawer.py` (3), e2e v764 étendu + (réactions dans le tiroir + suppression A/B), e2e v762 (nouvelle ligne 4) ; + `pytest` **1390 passed / 0 failed**, `ruff` OK ; `VERSION` + + `app/main.py` = 7.67.0 + --- ## ✅ Fonctionnalités livrées hors roadmap (bonus détectés dans le code) diff --git a/VERSION b/VERSION index 52b5df3..6a09420 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -7.66.0 +7.67.0 diff --git a/WORKLOAD.md b/WORKLOAD.md index 1fc588b..7fe61f4 100644 --- a/WORKLOAD.md +++ b/WORKLOAD.md @@ -1,6 +1,6 @@ # WORKLOAD — FlowDeck Notion Clone -> **Début**: 2026-07-08 | **Version**: v7.66.0 (Escape du menu slash retire le / + bouton commenter à droite du bloc) | **Statut**: EN COURS 🔄 +> **Début**: 2026-07-08 | **Version**: v7.67.0 (réactions dans le tiroir Comments + suppression, refonte du menu de sélection) | **Statut**: EN COURS 🔄 > **Cible**: parité Notion + intégration forge · **Follow-ups v7.3 livrés**: sidebar teamspaces, notif `page.updated`, charts `number` + dashboards multi-DB, unfurl forge, UI Settings → Audit — voir `ROADMAP.md § v7.3.0` ## Avancement Global diff --git a/app/main.py b/app/main.py index 156316a..458accb 100644 --- a/app/main.py +++ b/app/main.py @@ -186,7 +186,7 @@ async def lifespan(_app: FastAPI): app = FastAPI( title="FlowDeck", - version="7.66.0", + version="7.67.0", docs_url="/docs", redoc_url="/redoc", lifespan=lifespan, diff --git a/app/services/importers/url_fetch.py b/app/services/importers/url_fetch.py index 80faa48..5d4982e 100644 --- a/app/services/importers/url_fetch.py +++ b/app/services/importers/url_fetch.py @@ -26,7 +26,10 @@ def _is_public_host(host: str) -> bool: return False try: infos = socket.getaddrinfo(host, None) - except socket.gaierror: + except OSError: + # gaierror, socket.timeout, herror… : le garde-fou doit TOUJOURS + # renvoyer un booléen, jamais lever — sinon l'appelant tombe dans son + # `except Exception` (bookmarks) au lieu d'un refus explicite. return False for info in infos: address = info[4][0] diff --git a/app/templates/_page_editor_content.html b/app/templates/_page_editor_content.html index 97be069..f50e7b0 100644 --- a/app/templates/_page_editor_content.html +++ b/app/templates/_page_editor_content.html @@ -590,7 +590,20 @@
-
+ +
+
Reactions
+ +
+
No comments yet. Select some text and click 💬 Comment.