diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-29 10:05:22 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-29 10:05:22 +0200 |
| commit | feb15bcec261501eb49ad0de1fdc05a9992227c2 (patch) | |
| tree | fe3228e437c78fe6f77d68c4408f15cdf9e9f71f /docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | |
| parent | f051dd657757bca3ac7e36454d7f2fc21f322f73 (diff) | |
| download | qtmaildir-feb15bcec261501eb49ad0de1fdc05a9992227c2.tar.gz qtmaildir-feb15bcec261501eb49ad0de1fdc05a9992227c2.zip | |
fix: refresh the conversation dashboard after a write
Item 181, from the user's notes: "the thread dashboard doesn't update
live with the modifications applied to the list pane. If I mark the
thread as read, the dash still reports N unread".
ThreadDashboard draws a ThreadDigest, which the worker builds from the
index and which reached the pane only when a conversation was selected.
A tag write updated the model optimistically and repainted the card
beside it, and nothing touched the digest, so the pane went on reporting
the unread count, the progress bar and the Waiting-for-you list the
conversation had when it was opened.
Reachable from the dashboard's own Mark all read button, which is the
worst version of it: the number sits directly above the button that
fails to move it.
refreshDashboardDigest() re-asks the worker for the digest of the
conversation on display, and returns at once when the pane is showing
anything else. It bumps m_digestGeneration like any other request, so
the guards in onThreadDigestLoaded() discard a reply that arrives after
the user has moved on. No placeholder digest, unlike the selection path:
the pane already holds this conversation, and blanking it to re-fill it
would flicker the whole dashboard for a change to one number.
Called from onTagsApplied(), where a write is CONFIRMED, and not from
the two write funnels. The first attempt put it beside the optimistic
model update by analogy with every other optimistic repaint, and that
analogy does not hold here: the digest is rebuilt from the index, so a
refresh queued beside the write reaches the worker before the write does
and answers from the state before it. The test failed identically to no
fix at all.
Every write rather than a chosen subset, at the user's decision:
narrowing it to the writes that change what the dashboard happens to
draw today is a list the dashboard can outgrow silently, and this costs
a round trip only while a conversation is on screen. Re-requested rather
than edited in place, because the digest is a derived summary and
recomputing it here would be a second place that has to agree with the
worker about what a write did.
The test is worker-backed over a real two-message conversation and is
driven through the mark_all_read action rather than the private funnel,
which is the path the dashboard's own button takes. It asserts the pane
carries the unread state before the write, so the assertion after it
means something.
Suite: 42 of 43, with undoMovesTheMessageBack failing as it does on
master (item 136).
Diffstat (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md')
| -rw-r--r-- | docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md index 1f5a45d..68c080c 100644 --- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md +++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md @@ -254,6 +254,7 @@ taking that too literally. | 175 | The send countdown says Undo, and cannot be skipped | presentation | XS | open, 2026-08-28, from the notes. Two changes in one control: the button reads Abort, and a second button sends immediately rather than waiting the countdown out | | 179 | Undo is one level deep in practice, and there is no Redo | workflow | ? | open, 2026-08-29, from the notes. The `QUndoStack` is real and multi-level; what is missing is a `redo` action (absent from `knownActions()`, never called) and an answer to the stack being CLEARED on every new query (`mainwindow.cpp:3458`), which is what makes a deep stack behave like a shallow one. The clear has a correct reason and cannot simply be removed. Redo re-applies a write to real mail, so item 176's rule binds it too | | 180 | The repaint rules are discovered one hole at a time | maintenance | S-L | open, 2026-08-29, from the notes, and a QUESTION rather than a defect. Items 105, 107, 109, 110 and 170 are each one hole in the same surface, all found by hand. Three mechanisms (optimistic repaint, `syncViewMembership()`, revert) agree by documentation rather than by code. Cheapest answer is one invariant test, not a rewrite; the user decides which, and that decides the size | +| 181 | The thread dashboard does not follow a write to the conversation it shows | defect | XS | **done 2026-08-29**, unreleased, on `thread-row-identity`, from the notes. The dashboard draws a `ThreadDigest` built by the worker from the INDEX, which arrived only on selection, so a tag write moved the model and the card and left the pane reporting the count the conversation had when it was opened. Reachable from the dashboard's OWN Mark all read button. Re-requested from `onTagsApplied()`, where the write is confirmed: queued beside the write it races it and answers from the state before it, which is how the first fix passed review and failed the test. Section in the closed file | Sizes are rough: XS under an hour, S a sitting, M a session. |
