diff --git a/TEST_SCENARIOS.md b/TEST_SCENARIOS.md index 2b91aab..1bcfec1 100644 --- a/TEST_SCENARIOS.md +++ b/TEST_SCENARIOS.md @@ -357,7 +357,12 @@ l'éditeur slideover : créer + éditer une entrée, ajouter/retirer des tags, - **ACTION prévue** : ouvrir *Vault health* → mettre à la corbeille une entrée listée → revenir sur health sans *Recompute* → **Fix** sur cette entrée. - **Pourquoi c'est irréalisable** : G3 a rendu ce cas impossible à mettre en scène — le cache est invalidé à **chaque** mutation, donc revenir sur le tableau de bord recalcule toujours et l'entrée supprimée n'y figure plus. Le garde reste en place dans le code (`openEntryForFix` sort si `openSlideOver` renvoie `false`), il n'est simplement plus atteignable par l'interface. - **Tentative la plus proche, vérifiée** : cocher une entrée dans la liste (la barre de sélection apparaît) → passer en *Vault health* → *Delete* depuis cette barre. Le tableau de bord se **recalcule tout seul** et l'entrée disparaît de la liste : toujours pas de liste périmée. -- **Défaut trouvé au passage** : la barre de sélection **survivait** au passage en vue santé (comme en authenticator et journal d'audit), qui n'affichent aucune case à cocher. Elle proposait *Delete* / *Move to folder* / *Add tag* sur des entrées qu'on ne voyait plus sélectionnées. La sélection est désormais vidée à l'entrée dans ces trois vues. +- **Défaut trouvé au passage** : la sélection **survivait au changement de vue**. Visible en santé / authenticator / journal d'audit, qui n'affichent aucune case à cocher tout en gardant la barre d'actions. **Bien plus grave vers la corbeille** : les identifiants cochés désignent des entrées **vivantes**, alors que la barre de la corbeille propose *Delete forever* — on pouvait donc purger définitivement des entrées qui n'y étaient jamais entrées. La sélection est maintenant vidée dès que la vue change, quelle qu'elle soit. + +### G6 · la sélection ne franchit pas les vues +- **ACTION** : cocher deux entrées dans *All items* → passer à la **corbeille**. +- **ATTENDU** : plus rien de coché, barre d'actions disparue. Surtout pas *Delete forever* actif sur une sélection d'entrées vivantes. +- **Variantes** : vers un dossier, un tag, *Notes*, *Recently used*, *Vault health*, *Authenticator*, *Audit log* — même résultat partout. Et au retour dans la vue d'origine, la sélection reste vide (elle n'est pas mémorisée). ### G5 · activer / désactiver HIBP depuis la vue santé ✅ - **ACTION** : dans *Vault health*, activer la vérification HIBP → attendre la fin du scan **sans quitter la vue**. diff --git a/js/app.js b/js/app.js index bf663e2..23f75a5 100644 --- a/js/app.js +++ b/js/app.js @@ -2288,20 +2288,23 @@ async function addTagToEntry(id, tag) { } catch (err) { toast(err.message, 'error'); } } -// Views that render no checkboxes: audit log, authenticator grid, vault health. -const VIEWS_WITHOUT_SELECTION = ['audit', 'authenticator', 'health']; +// A selection belongs to the view it was made in. Carrying it across is never +// what the user meant, and between the list and the trash it is dangerous: the +// checked ids are LIVE entries while the trash bar offers "Delete forever", so +// a purge would hit rows that were never in the trash. Views without checkboxes +// (health, authenticator, audit) were the visible symptom of the same problem. +let selectionView = null; function renderGrid() { + if (state.view !== selectionView) { + selectionView = state.view; + state.checked.clear(); + } $('#contentTitle').textContent = viewTitle(); // Re-apply the keyboard cursor after the grid re-renders. Defer one // tick so the new cards are in the DOM before we query for them. setTimeout(applyCursorHighlight, 0); - // A selection made in the list survived into these views, where nothing - // shows what is selected — yet the batch bar still offered Delete, Move to - // folder and Add tag on rows the user could no longer see. - if (state.checked.size && VIEWS_WITHOUT_SELECTION.indexOf(state.view) !== -1) - state.checked.clear(); // Audit log: read-only chronological feed, custom render. if (state.view === 'audit') {