Skip to content

fix(web): busy gate + toast on mark-read#411

Merged
intendednull merged 1 commit into
mainfrom
claude/issue-345-mark-read-feedback
Apr 27, 2026
Merged

fix(web): busy gate + toast on mark-read#411
intendednull merged 1 commit into
mainfrom
claude/issue-345-mark-read-feedback

Conversation

@intendednull
Copy link
Copy Markdown
Owner

Why

mark_read_click swallow per-peer errors with let _ =. No busy gate → spammable. No toast → silent fail on flaky link.

Fix

  • New mark_busy RwSignal<bool> separate from busy (retry path).
  • Click handler early-return when already busy. Reset on every exit path.
  • Loop collect Err count from mark_queue_read calls.
  • On any failures push error toast via existing ToastStack (lazy lookup so headless tests without provide_notifier() still drive the handler).
  • Button gain disabled + aria-busy + label flip to marking… while in flight (mirror existing ACTION_RETRY_BUSY pattern).

Test

  • crates/web/tests/browser.rs — new sync_queue_view_mark_as_read_button_has_busy_attrs pins aria-busy contract + idle label + early-return reset.
  • Unit: toast_mark_read_failed_pluralises in sync_queue_copy::tests.

Verify

Closes #345


Generated by Claude Code

mark_read_click swallow per-peer errors. No busy guard.
Add `mark_busy` RwSignal, disable+aria-busy button while in
flight, collect Err count, push error toast via ToastStack.
Browser test pin busy contract.

Closes #345
intendednull added a commit that referenced this pull request Apr 27, 2026
Handler closures in `crates/web/src/handlers.rs` swallowed every async
error with `let _ = h.<action>(...).await`. Send/edit/delete/react/
pin/unpin failures vanished — typed message disappeared from input,
no log, no toast. Refs #350 [GEN-07].

New `warn_and_toast_with(action, e, toasts)` helper:
- `tracing::warn!(error = ?e, action, "ui handler failed")`
- Pushes `Toast::err("Couldn't {action}. Try again.")` with a per-
  action `dedup` key so back-to-back failures coalesce instead of
  stacking. Mirrors the lazy `use_context::<ToastStack>()` pattern
  PR #411 introduced for the inbound mark-read button.

Each handler now captures the toast stack on the synchronous frame
(reactive owner intact) before `spawn_local`, then forwards into the
helper from the async path — `wasm_bindgen_futures::spawn_local`
strips the owner, so context lookup must happen earlier.

7 sites patched: send_message, send_reply, edit_message, delete_
message, react, pin_message, unpin_message. switch_channel /
switch_server stay as-is — they return `()` so there was nothing to
swallow.

Browser test `handler_error_toasts::*` covers helper happy-path,
dedup coalescing, and missing-stack no-panic. Test exercises the
exact production code path; the handler closures themselves are
pinned to ClientHandle<IrohNetwork> with no trait seam to inject a
failing double, so going one level deeper would buy nothing.

`rg "let _ = h\." crates/web/src/handlers.rs` returns empty.
fmt + clippy + native tests + wasm check all green; browser tier
verified locally via `cargo check -p willow-web --tests` + manual
review of the test mod (Firefox/wasm-pack not on this box, browser
suite runs in CI).

Co-authored-by: Claude <noreply@anthropic.com>
@intendednull intendednull merged commit 25ec7cf into main Apr 27, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[GEN-02] mark_read_click swallows per-peer errors with no toast or busy guard

2 participants