fix: le bouton close de Settings ferme en un clic (v7.69.4)
Le bouton close de Settings devait être cliqué deux fois. Symptomatique depuis
le menu utilisateur ; depuis /workspaces ça marchait.
Cause : closeSettings() faisait history.back() PUIS window.location.reload()
après un délai FIXE de 100 ms. Le retour est une navigation asynchrone : quand
elle n'est pas terminée en 100 ms, le reload() retombe sur /settings et le
panneau « se ferme puis revient ». La profondeur d'historique diffère selon le
parcours — d'où le caractère intermittent et le fait que /workspaces
échappait au symptôme.
Correctif : location.replace() vers la page d'origine. Une seule navigation
déterministe — ni history.back(), ni popstate, ni rechargement différé. Aucun
chemin ne peut plus se terminer sans navigation. Effet secondaire assumé et
souhaitable : « Retour » ne rouvre plus Settings.
La branche window.opener ne fait plus de return inconditionnel : window.close()
échoue en silence quand l'onglet n'a pas été ouvert par du script, et l'ancien
code abandonnait alors sans navigation de repli — le bouton semblait mort.
CONTRÔLE NÉGATIF FAIT — le même spec a été exécuté contre deux builds :
ancien closeSettings() -> le parcours menu-utilisateur ÉCHOUE
(Received: "…/settings"), /workspaces passe ;
correctif -> les deux passent.
Le test verrouille aussi que le panneau position:fixed n'est plus peint
(.settings-overlay absent), qui est le symptôme exact rapporté.
Correction de diagnostic : le diagnostic posé en v7.69.3 (« Alpine ne lie pas
le composant x-data="settingsInit()" ») était FAUX — un artefact de mon banc
d'essai target="_blank", pas le parcours réel. La page étant réactive après le
premier clic, le handler s'exécutait bien. ROADMAP.md et CHANGELOG.md § v7.69.3
corrigés pour ne pas laisser une piste fausse en héritage.
pytest 1421 passed / 0 failed · ruff OK · OpenAPI 526 chemins / 7.69.4
e2e 18/18 verts sur l'instance déployée
This commit is contained in:
+28
-28
@@ -1593,37 +1593,37 @@ près produisaient deux rendus. Surcharges retirées ; e2e compare les
|
||||
géométries calculées : **identiques des deux côtés** (overlay `fixed` avec
|
||||
fond, panneau 1050×765 centré, close à 13/13 px du coin).
|
||||
|
||||
**Non livré — double-clic sur le bouton close de Settings.** Cause racine
|
||||
trouvée, correctif NON appliqué (non vérifié sur le parcours réel).
|
||||
**Terminé en v7.69.4** — double-clic sur le bouton close de Settings.
|
||||
|
||||
Relevé d'investigation, à ne pas refaire :
|
||||
Le diagnostic posé en v7.69.3 était **FAUX** : je pensais qu'Alpine ne liait
|
||||
pas le composant (`_x_dataStack` absent), donc que le handler était inerte.
|
||||
La question à l'utilisateur a tranché : *« après le premier clic la page est
|
||||
réactive »* → Alpine lie bien le composant, le handler s'exécute. Le scénario
|
||||
`target="_blank"` qui m'avait donné `_x_dataStack` absent était un artefact de
|
||||
mon propre banc d'essai, pas le parcours réel. **Ne pas relire ce diagnostic.**
|
||||
|
||||
- **Cause racine** : Alpine ne LIE PAS le composant `x-data="settingsInit()"`
|
||||
dans certains contextes. Mesure sur un onglet où Settings a été ouvert via
|
||||
`target="_blank"` :
|
||||
`window.Alpine` existe, mais `button.settings-close._x_dataStack` est absent
|
||||
→ `@click="closeSettings()"` est **inerte**. Le premier clic ne fait rien du
|
||||
tout — ce qui correspond au symptôme rapporté. Ce n'est PAS la logique de
|
||||
navigation qui est en cause.
|
||||
- **Le bug se reproduit en e2e** : ouvrir `/settings` depuis un onglet distinct
|
||||
(`target="_blank"` avec `rel="opener"`), cliquer `button.settings-close` →
|
||||
l'URL reste `/settings`. Un test l'a confirmé (`APRES 1 clic= /settings`),
|
||||
sans `pageerror` ni message console : le handler ne s'exécute simplement pas.
|
||||
- **Ce qu'il ne faut PAS faire** : réécrire `closeSettings()`. L'ancienne
|
||||
implémentation (`window.opener` → `window.close()`, sinon `history.back()` +
|
||||
`reload()` après 100 ms) a été modifiée puis **annulée** : elle n'avait aucun
|
||||
effet sur le cas reproduit. Le `return` inconditionnel de la branche
|
||||
`window.opener` reste un défaut réel (`window.close()` échoue en silence si
|
||||
l'onglet n'a pas été ouvert par du script), mais il n'est pas la cause
|
||||
rapportée.
|
||||
- **Thèse de la course réfutée** : un retour plus lent que 100 ms ne provoque
|
||||
pas le symptôme (testé avec 400 ms de latence, un seul clic suffit).
|
||||
- Parcours de référence qui, lui, **fonctionne en un clic** : `/local-workspace`
|
||||
→ menu avatar → Settings (chargement de page complet).
|
||||
Cause réelle : `closeSettings()` faisait `history.back()` puis
|
||||
`window.location.reload()` après un délai **fixe de 100 ms**. Entre les deux,
|
||||
le retour est une navigation asynchrone ; quand elle n'est pas terminée en
|
||||
100 ms, le `reload()` retombe sur `/settings` — le panneau « se ferme puis
|
||||
revient ». Depuis `/workspaces`, la profondeur d'historique diffère et le
|
||||
retour arrive à temps : d'où l'absence de symptôme sur ce seul parcours.
|
||||
|
||||
**Prochaine étape concrète** : déterminer pourquoi `settingsInit()` échoue à
|
||||
s'initialiser — `settings.js` est-il chargé dans ce contexte ? Vérifier
|
||||
`x-data` au chargement et la présence d'une erreur CSP/nonce sur le script.
|
||||
Correctif : `location.replace()` vers la page d'origine. Une seule navigation
|
||||
déterministe, ni `history.back()`, ni `popstate`, ni rechargement différé.
|
||||
Effet secondaire assumé et souhaitable : « Retour » ne rouvre plus Settings.
|
||||
|
||||
**Preuve avant/après (contrôle négatif fait)** : même spec, deux builds.
|
||||
- ancien `closeSettings()` → le test du parcours menu-utilisateur **ÉCHOUE**
|
||||
(`Received: "…/settings"`), celui de `/workspaces` passe ;
|
||||
- correctif → **les deux passent**.
|
||||
|
||||
**Piège relevé** : ma « réfutation » de la thèse de course était fausse. J'avais
|
||||
interposé 400 ms via `page.route()`, qui intercepte les requêtes de sous-ressources
|
||||
— pas la navigation du document lors d'un `history.back()`, servie depuis le
|
||||
bfcache. Le délai n'a donc jamais été appliqué. Un contrôle négatif (rebuild
|
||||
avec l'ancien code) aurait tranché en un tour ; il a fallu plusieurs tours pour
|
||||
le faire.
|
||||
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user