feat(ux): Esc-to-cancel + type-to-confirm for destructive actions (PMS-369) #259

Merged
nrupard merged 1 commit from feat/pms-369-confirm-esc-type-to-confirm into main 2026-06-17 17:32:55 +02:00
Owner

What

Closes the three remaining ACs of PMS-369. The destructive-confirmation sweep was already broad on main (ConfirmDialog wired across 11 pages, incl. the SLA "Remove" the review named), so AC1/AC2 were satisfied; this adds Esc, type-to-confirm, the test, and the doc.

Changes

  • Esc-to-cancel (AC3): the shared Modal now focuses itself on mount (tabindex=-1 + set_focus) and fires onclose on Escape, so every confirm/modal cancels on Esc - on top of the existing backdrop-click and Cancel.
  • Type-to-confirm (AC4): ConfirmDialog gains an optional confirm_phrase. When set, the destructive button stays disabled until the user types the entity's name. Gate logic confirm_phrase_satisfied (exact match, trimmed, case-insensitive) is unit-tested. Wired the SPA's one cascading delete - delete company (removes its sites, unlinks contacts/tickets) - to require typing the company name. There is no tenant-delete in the SPA (admin tenant page is a read-only roster).
  • Test (AC5): unit tests on confirm_phrase_satisfied. DOM-interaction tests (click -> modal -> DELETE) are not supported by the host-side cargo test --lib harness (no wasm/browser runner is set up); noted in the doc.
  • Doc: dev-docs/destructive-actions.md (companion to form-conventions.md) - the confirm convention, simple-vs-type-to-confirm line, current coverage, and the testing limitation.

AC mapping

  • AC1 (every destructive action confirms) / AC2 (named target + red button + Cancel): already satisfied app-wide.
  • AC3 (Cancel / outside-click / Esc cancel): Esc added here; the other two existed.
  • AC4 (catastrophic deletes use type-to-confirm; documented): delete-company gated + documented.
  • AC5 (test in CI): gate-logic unit tests; DOM test limitation documented.

Verification

wasm cargo check, cargo clippy --target wasm32-unknown-unknown --lib -- -D warnings, cargo fmt --all --check, and cargo test --lib modal::tests (2 passed) all pass.

#PMS-369

## What Closes the three remaining ACs of PMS-369. The destructive-confirmation sweep was already broad on main (`ConfirmDialog` wired across 11 pages, incl. the SLA "Remove" the review named), so AC1/AC2 were satisfied; this adds Esc, type-to-confirm, the test, and the doc. ## Changes - **Esc-to-cancel (AC3):** the shared `Modal` now focuses itself on mount (`tabindex=-1` + `set_focus`) and fires `onclose` on `Escape`, so every confirm/modal cancels on Esc - on top of the existing backdrop-click and Cancel. - **Type-to-confirm (AC4):** `ConfirmDialog` gains an optional `confirm_phrase`. When set, the destructive button stays disabled until the user types the entity's name. Gate logic `confirm_phrase_satisfied` (exact match, trimmed, case-insensitive) is unit-tested. Wired the SPA's one cascading delete - **delete company** (removes its sites, unlinks contacts/tickets) - to require typing the company name. There is no tenant-delete in the SPA (admin tenant page is a read-only roster). - **Test (AC5):** unit tests on `confirm_phrase_satisfied`. DOM-interaction tests (click -> modal -> DELETE) are not supported by the host-side `cargo test --lib` harness (no wasm/browser runner is set up); noted in the doc. - **Doc:** `dev-docs/destructive-actions.md` (companion to `form-conventions.md`) - the confirm convention, simple-vs-type-to-confirm line, current coverage, and the testing limitation. ## AC mapping - AC1 (every destructive action confirms) / AC2 (named target + red button + Cancel): already satisfied app-wide. - AC3 (Cancel / outside-click / Esc cancel): Esc added here; the other two existed. - AC4 (catastrophic deletes use type-to-confirm; documented): delete-company gated + documented. - AC5 (test in CI): gate-logic unit tests; DOM test limitation documented. ## Verification wasm `cargo check`, `cargo clippy --target wasm32-unknown-unknown --lib -- -D warnings`, `cargo fmt --all --check`, and `cargo test --lib modal::tests` (2 passed) all pass. #PMS-369
feat(ux): Esc-to-cancel + type-to-confirm for destructive actions (PMS-369)
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 1m47s
Create release / Create release from merged PR (pull_request) Has been skipped
c5cd70b5dc
The destructive-confirmation sweep was already broad on main (ConfirmDialog wired across 11 pages, including the SLA "Remove" the review named). This closes the three remaining ACs.

- Esc-to-cancel (AC3): the shared Modal now focuses itself on mount and fires onclose on Escape, so every confirm/modal cancels on Esc in addition to the existing backdrop-click and Cancel button.
- Type-to-confirm (AC4): ConfirmDialog gains an optional confirm_phrase. When set, the destructive button stays disabled until the user types the entity's name; the gate logic (confirm_phrase_satisfied: exact match, trimmed, case-insensitive) is unit-tested. Wired the one cascading delete in the SPA - delete company (removes its sites, unlinks its contacts/tickets) - to require typing the company name. There is no tenant-delete in the SPA (admin tenant page is a read-only roster).
- Test (AC5): unit tests on confirm_phrase_satisfied (ungated-when-blank, exact/trim/case behaviour). Full DOM-interaction tests (click -> modal -> DELETE) are not supported by the host-side cargo test --lib harness (no wasm/browser runner); noted in the doc.
- Doc: dev-docs/destructive-actions.md (companion to form-conventions.md) documents the confirm convention, simple-vs-type-to-confirm line, current coverage, and the testing limitation.

AC1 (every destructive action confirms) and AC2 (named target + red button + Cancel) were already satisfied app-wide; this PR adds Esc, the type-to-confirm gate, the test, and the doc.

#PMS-369
nrupard deleted branch feat/pms-369-confirm-esc-type-to-confirm 2026-06-17 17:32:55 +02:00
Sign in to join this conversation.
No reviewers
No labels
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
psa-systems/mokosh-apps!259
No description provided.