fix: thread move/delete act on the whole conversation and surface failures#302
fix: thread move/delete act on the whole conversation and surface failures#302Monkey7539 wants to merge 1 commit into
Conversation
…lures Three related gaps in threaded-view actions: 1. Single-thread move ignored the bulk-move response. The server returns 200 with a per-message `moved` list; messages skipped (destination folder missing on that account) or whose IMAP move failed were silently dropped — the row disappeared optimistically and reappeared on the next sync with no error. Now partial failures restore the row and show the bulk-move error toast, mirroring the checkbox bulk handler. 2. Thread moves are scoped to the acting message's account. A thread can span accounts (and always includes Sent copies); the destination folder path is account-specific, so the other account's copies were guaranteed server-side skips. Scoping makes the move do exactly what it can do, with nothing silently dropped. 3. Checkbox bulk move/delete on thread rows only acted on each thread's visible (newest) message — the rest of the conversation stayed behind. Both handlers now expand selected thread rows via resolveMessagesForThreadAction (move expansion scoped per account as above; delete keeps its delete-everywhere semantics), and the undo / unmount-flush paths carry the full id set. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for this. The underlying problems are real: bulk delete only removed each thread's visible message, and the single-row move swallowed partial failures. I want both fixed. But it can't merge as-is because of how it selects the messages to act on. Blocker: destructive actions are keyed on The codebase already has the safe primitive for exactly this: Also, high severity: the move path is not chunked. Tests. This is destructive, multi-account, partial-failure logic with no coverage. The snooze reply-chain path is unit-tested ( The failure-surfacing improvements are the right direction. Once the expansion goes through the reply chain and the move is chunked, I am happy to re-review. |
|
One clarification on where this fix should live. Heads-up that the same helper also feeds the non-destructive read/star actions. Switching it to the reply chain changes those too. That is arguably more correct, but it is a behavior change, so either scope the reply-chain expansion to the destructive delete/move paths specifically, or make the read/star change deliberately. |
Problem
With group by thread enabled:
Thread move looks like it worked but doesn't (or only partially). The single-thread
moveTohandler callsapi.bulkMove(...)and never inspects the response./messages/bulk-movereturns 200 with a per-messagemovedlist, and messages can legitimately be missing from it: the destination folder is verified per account with an exact path match, and IMAP move failures are only logged server-side. The row disappears optimistically, no error shows, and the unmoved messages come back on the next sync.Cross-account threads guarantee silent skips.
GET /thread/:threadIddeliberately spans all of the user's accounts (and includes Sent copies). A thread woven from two accounts moved into an account-specific folder produces server logs like:while the client shows success. (Real logs from my instance — this is how I hit it.)
Checkbox bulk move/delete on thread rows only acts on each thread's visible (newest) message. The single-row handlers resolve the whole conversation via
resolveMessagesForThreadAction; the multi-select paths don't, so the rest of the thread stays behind.Thread delete was also affected by (3), and cross-account threads surface real per-message failures (that path already checks
result.deleted) — e.g. when one account's IMAP connection is unhealthy.Fix (frontend only,
MessageList.jsx)moveTo(single thread): checkresult.moved; on partial failure restore the visible row and show the existing bulk-move error toast (reusesmessageList.bulkMoved.failBody— no new locale keys).handleBulkMove/handleBulkDelete: expand selected thread rows viaresolveMessagesForThreadActionbefore calling the API; undo and the unmount/beforeunload flush paths carry the full id set; failure toasts count actual failed messages.Testing
npm test(frontend): 1394 passnpm run lint: clean (--max-warnings 0)npm run build: cleanWritten with AI assistance (Claude); I have reviewed and tested the changes and am authorized to submit them under the project's CLA.
🤖 Generated with Claude Code