fix(recipes): garde le popover de correction ouvert pendant la sélection d'un span #47

Merged
kyuno merged 2 commits from fix/correction-popover-span-selection into main 2026-09-05 23:14:35 +02:00
Owner

Corrige l'issue #36.

Le bug

Depuis la refonte du popover de correction des tech-steps (#29-#32), attacher un ingrédient / ustensile / température à une correction demande de surligner le passage concerné dans la description (invite selectSpanHint). Le popover est explicitement conçu pour ne pas se fermer pendant cette sélection.

En pratique il se fermait : le <p> de la description (StepDescription, containerRef) est un frère du popover dans le DOM, donc le mousedown qui démarre le glisser-sélectionner est vu par le listener « clic extérieur » du popover comme un clic dehors → onClose() → closeActiveCorrection() remet pendingSpanRequest à null avant le mouseup. Le mouseup tombe alors dans la branche par défaut de handleMouseUp et ouvre un nouveau popover traitant le texte sélectionné comme une proposition de technique fraîche — technique choisie + métadonnées déjà ajoutées perdues.

Le correctif

TechStepCorrectionPopover accepte un prop optionnel descriptionContainerRef — StepDescription lui passe simplement son containerRef existant. Dans handleClickOutside, un mousedown dont la cible est à l'intérieur de ce conteneur n'est plus traité comme « extérieur ».

Sans risque de régression : StepDescription pilote déjà explicitement chaque interaction utile dans la description (setActiveCorrection sur clic d'une technique/température surlignée, setResolvedMetadataSpan sur sélection quand une demande est en cours) — cette fermeture concurrente ne faisait qu'arriver à la même conclusion par coïncidence pour certains cas, et cassait tous les autres. Un clic vraiment hors zone ferme toujours le popover.

Tests

TechStepCorrectionPopover.cy.tsx disait ce cas « couvert par le scénario e2e » — qui n'existait pas. Ajouté dans apps/web/cypress/e2e/recipes.cy.ts : ouvre une vraie StepDescription éditable, ouvre une correction, clique « Ajouter un ingrédient », puis simule une vraie sélection de texte (document.createRange() + Selection sur les nœuds data-offset, séquence mousedown → mouseup réelle, pas un .click()), et vérifie que le même popover reste ouvert avec le sous-formulaire ingrédient — pas un popover vierge.

Vérifié localement : 10/10 avec le correctif, échoue sur ce scénario sans lui.

🤖 Generated with Claude Code

Corrige l'[issue #36](https://git.dev.kyuno.fr/kyuno/batchCooking/issues/36). ## Le bug Depuis la refonte du popover de correction des tech-steps (#29-#32), attacher un ingrédient / ustensile / température à une correction demande de **surligner le passage concerné dans la description** (invite `selectSpanHint`). Le popover est explicitement conçu pour ne **pas** se fermer pendant cette sélection. En pratique il se fermait : le `<p>` de la description (`StepDescription`, `containerRef`) est un **frère** du popover dans le DOM, donc le `mousedown` qui démarre le glisser-sélectionner est vu par le listener « clic extérieur » du popover comme un clic dehors → `onClose()` → `closeActiveCorrection()` remet `pendingSpanRequest` à `null` **avant le `mouseup`**. Le `mouseup` tombe alors dans la branche par défaut de `handleMouseUp` et ouvre **un nouveau popover** traitant le texte sélectionné comme une proposition de technique fraîche — technique choisie + métadonnées déjà ajoutées perdues. ## Le correctif `TechStepCorrectionPopover` accepte un prop optionnel `descriptionContainerRef` — `StepDescription` lui passe simplement son `containerRef` existant. Dans `handleClickOutside`, un `mousedown` dont la cible est à l'intérieur de ce conteneur n'est plus traité comme « extérieur ». Sans risque de régression : `StepDescription` pilote déjà explicitement chaque interaction utile dans la description (`setActiveCorrection` sur clic d'une technique/température surlignée, `setResolvedMetadataSpan` sur sélection quand une demande est en cours) — cette fermeture concurrente ne faisait qu'arriver à la même conclusion par coïncidence pour certains cas, et cassait tous les autres. Un clic vraiment hors zone ferme toujours le popover. ## Tests `TechStepCorrectionPopover.cy.tsx` disait ce cas « couvert par le scénario e2e » — qui n'existait pas. Ajouté dans `apps/web/cypress/e2e/recipes.cy.ts` : ouvre une vraie `StepDescription` éditable, ouvre une correction, clique « Ajouter un ingrédient », puis simule une **vraie sélection de texte** (`document.createRange()` + `Selection` sur les nœuds `data-offset`, séquence `mousedown` → `mouseup` réelle, pas un `.click()`), et vérifie que **le même** popover reste ouvert avec le sous-formulaire ingrédient — pas un popover vierge. Vérifié localement : 10/10 avec le correctif, échoue sur ce scénario sans lui. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kyuno added 1 commit 2026-09-05 21:01:48 +02:00
fix(recipes): garde le popover de correction ouvert pendant la sélection d'un span
Some checks failed
CI / lint (push) Successful in 2m12s
CI / build (push) Successful in 4m10s
CI / intent-service-test (push) Successful in 7m28s
CI / test (push) Failing after 9m18s
CI / e2e (push) Successful in 9m54s
bc077b770e
Depuis la refonte #29-#32, attacher un ingrédient/ustensile/température à
une correction de technique demande de surligner le passage concerné dans
la description. Mais le `<p>` de la description est un frère du popover
dans le DOM, et le listener « clic extérieur » du popover (`mousedown`
hors de son propre DOM → `onClose`) fermait le popover dès le `mousedown`
qui démarre ce glisser-sélectionner — avant même le `mouseup`. Le
`mouseup` ouvrait alors un nouveau popover vierge pour le texte
sélectionné, traité comme une toute nouvelle proposition de technique (la
technique choisie et les métadonnées déjà ajoutées étaient perdues).

`TechStepCorrectionPopover` accepte désormais un prop optionnel
`descriptionContainerRef` (le `containerRef` que `StepDescription` a
déjà) : un `mousedown` à l'intérieur n'est plus un clic extérieur.
`StepDescription` pilote déjà explicitement chaque interaction dans la
description (`setActiveCorrection`/`setResolvedMetadataSpan`), donc retirer
cette fermeture concurrente ne perd rien ; un clic vraiment ailleurs ferme
toujours le popover.

Comble aussi le trou de couverture que `TechStepCorrectionPopover.cy.tsx`
prétendait déjà délégué à un scénario e2e inexistant : nouveau test dans
`recipes.cy.ts` avec une vraie sélection de texte (Range/Selection sur les
nœuds `data-offset`, séquence mousedown→mouseup réelle) — vérifié qu'il
échoue sans le correctif.

Closes #36

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
kyuno added 1 commit 2026-09-05 22:58:45 +02:00
chore: relance la CI (job test cassé par une course d'infra)
All checks were successful
CI / lint (push) Successful in 2m56s
CI / build (push) Successful in 3m53s
CI / intent-service-test (push) Successful in 4m13s
CI / e2e (push) Successful in 7m57s
CI / test (push) Successful in 15m29s
e64bbc37e9
Le job `test` a échoué dans le hook racine `beforeAll` sur un
`prisma.diet.upsert()` → P2002 « Unique constraint failed on (key) », un
symptôme classique de seed concurrent : deux jobs `test` (run 87 sur
`main` post-merge #46, run 88 sur cette branche) démarrés à 3 min
d'intervalle partagent le même conteneur Postgres `--name postgres` sur
l'hôte du runner. Aucun rapport avec ce correctif (100% frontend, vérifié
localement 10/10). `main` a son job `test` vert (run 87).
kyuno merged commit f01ac58fec into main 2026-09-05 23:14:35 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: kyuno/batchCooking#47
No description provided.