From 94462ae2cc68d563f883b29f1812f93d6b5a6c06 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 24 Aug 2026 18:55:38 +0200 Subject: feat(queries): drop pinning, the menu is every saved query's home Item 94. The query row is the six built-in filters (Unread, Inbox, Important, Sent, Drafts, Trash), which compose with the account dropdown, and every saved query lives in the More queries menu. Nothing has to decide which of the user's queries get button space, which is the question item 93 would otherwise have had to answer. SavedQuery::pinned is gone from the struct, the reader, the writer, the save dialog's checkbox and the pin/unpin context action. The stored key is stripped rather than left ignored, at the user's choice. That has one non-obvious requirement: `pinned` stays named in loadSavedQueries' `known` list precisely so it is NOT collected as an unknown field, since those are preserved and written straight back. A mutation removing that name puts the key in the file for ever. Confirmed with the user before starting that the built-in set covers their use, since removing pinning removes the escape hatch this item was blocked on. Tests: four pinning tests replaced by two on the new rule, four more converted from buttons to menu entries. migrationPinsEveryEntry and aStoredGeneratedQueryIsUnpinnedNotDropped are rewritten around the property that outlived the flag rather than deleted: an entry must be KEPT, which is what both assertions were really guarding. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KEcn3u19xPqv6ggD15PG4c --- .../2026-08-03-post-0.1.0-usability-closed.md | 46 +++++++++++++++++++++ .../plans/2026-08-03-post-0.1.0-usability.md | 47 +--------------------- 2 files changed, 47 insertions(+), 46 deletions(-) (limited to 'docs/superpowers') diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md index 0f7181b..7314700 100644 --- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md +++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md @@ -7392,3 +7392,49 @@ draft stayed disabled on a draft selected that way, and the reply family had the same blind spot without a test that could see it. It is now connected to both signals. Reading `currentRowChanged` is safe here for the reason `CLAUDE.md` gives: it answers "which row is current", and no count is read. + +## 94. `pinned` has nothing left to decide once the buttons are built-in + +**Observed (user, 2026-08-15),** thinking past item 93 rather than from the +notes: + +> after we've migrated [...] we can drop my 4 redundant (by then) saved queries, +> and there won't be a need for pinning anymore. The buttons will be driven by +> the hardcoded queries, the menu will be the home for saved queries. + +**The end state this describes:** the query row is built-in filters ONLY, and +every saved query lives in the menu. No mixing, so nothing has to decide which +saved queries get button real estate, and `SavedQuery::pinned` is dead weight. + +**This also disposes of a problem item 93 would otherwise have to solve.** With +both tiers sharing one row, something must order the four filters against the +user's pinned queries. Under this end state the question does not arise. + +**Blocked on 93, and deliberately not part of it.** The user needs to live with +the four buttons first and confirm they cover what they actually use. If one is +wrong, pinning is the escape hatch, and it has to still be there to be used. +Closing 93 and this together would remove the fallback before it was needed. + +**This is a user-visible removal, not a cleanup.** `pinned` shipped in 0.18.0: +`SaveQueryDialog` offers "Show as a button" (`src/savequerydialog.cpp:104`) and +the right-click menu offers "Move to menu" / "Show as a button" +(`src/mainwindow.cpp:1797`). Anyone who put a saved query on the row loses that +permanently. Semver on the user-visible surface makes it a minor bump with an +`### Upgrading` note. + +**The stored field is a separate decision from the UI.** `pinned` is written to +queries.json (`src/config.cpp:603`) and read back (`:542`). Two options, and the +cheaper one is also the reversible one: + +- **Stop reading it, leave it in the file.** Harmless: an ignored key, preserved + by the unknown-field handling, and a build that reintroduces pinning would + find every user's setting intact. +- **Strip it on the next save.** Cleaner file, and irreversible for anyone who + had it set. + +Prefer leaving it unless the user asks otherwise. No `kQueriesFormatVersion` +bump either way: an ignored optional field is not a breaking change. + +**Size: S.** Removing a field, two UI affordances and their tests. + +**Closed 2026-08-24** (unreleased). See the status table row for the outcome. 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 63bd833..49b9613 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 @@ -161,7 +161,7 @@ taking that too literally. | 92 | Nothing distinguishes a tag written by a rule from one the user applied | information | M | **postponed** 2026-08-15 at the user's request: "I don't see the utility, so I don't really know how to answer." Needs per-MESSAGE provenance nothing records, a two-repo format change blank on all existing mail. Reopen only if the need appears in use | | 93 | The query buttons are whatever the user pinned, not a designed set of filters | workflow | M | **done** 2026-08-15, unreleased; see `specs/2026-08-15-builtin-filters-design.md`. Absorbs item 90. Four built-in filters composing with the account dropdown; the user's own queries unpinned, never deleted | | 95 | A query in the overflow menu cannot be run | defect | XS | **done** 2026-08-15, unreleased. Pre-existing and not caused by 93: the entry's action owned a submenu, and Qt emits no `triggered` for those, so the connection had never fired. Surfaced because 93 moved every query into the menu | -| 94 | `pinned` has nothing left to decide once the buttons are built-in | maintenance | S | open; **blocked on 93**, and deliberately not part of it. A user-visible removal: the row becomes built-ins only and every saved query lives in the menu | +| 94 | `pinned` has nothing left to decide once the buttons are built-in | maintenance | S | **done** 2026-08-24, unreleased. The query row is the six built-in filters only, every saved query is in the menu, and `SavedQuery::pinned` is gone from the struct, the reader, the writer, the save dialog's checkbox and the pin/unpin context action. The user chose to **strip** the stored key rather than leave it ignored, against this entry's own preference, so `pinned` stays named in the reader's `known` list precisely so it is NOT preserved as an unknown field and written back. Confirmed with the user first that the built-in set covers their use, since removing pinning removes the escape hatch this item was blocked on. Six tests reached saved queries through buttons that no longer exist and were converted to the menu, two more replaced outright (`onlyPinnedQueriesBecomeButtons` and friends), and `migrationPinsEveryEntry` / `aStoredGeneratedQueryIsUnpinnedNotDropped` were rewritten around the property that survives: an entry must be KEPT, which is what those assertions were really guarding. Three translated strings retired, `lrelease` reports 479 finished 0 unfinished | | 96 | A query returning the thread already on display opens onto the placeholder | defect | S | **done** 2026-08-15, unreleased. Split from 66's unverified half, which had a different cause. Reproduced from two screenshots after four measured eliminations | | 97 | An edit made during a sync is reverted in the list when the sync ends | defect | S | **done** 2026-08-15, unreleased. Found by hand-testing item 89's fix. The sync-end refresh ran BEFORE the held-edit flush, so it read a database that still carried the old tag | | 98 | "Important" adds the tag but cannot remove it, unlike every other toggle | defect | XS | **done** 2026-08-17, unreleased. Calls `everySelectedRowHasTag()`, as the entry required. Its reply test needed THREE different states (list-first thread, the reply's own thread, the reply) before it could tell the two wrong answers apart; with the reply defaulted to its thread's state the item 105 mutation stayed green, measured | @@ -432,51 +432,6 @@ Those are three different features. **Size: `?`, unspecified**, and out of scope until v2 exists. Ask before designing anything. -## 94. `pinned` has nothing left to decide once the buttons are built-in - -**Observed (user, 2026-08-15),** thinking past item 93 rather than from the -notes: - -> after we've migrated [...] we can drop my 4 redundant (by then) saved queries, -> and there won't be a need for pinning anymore. The buttons will be driven by -> the hardcoded queries, the menu will be the home for saved queries. - -**The end state this describes:** the query row is built-in filters ONLY, and -every saved query lives in the menu. No mixing, so nothing has to decide which -saved queries get button real estate, and `SavedQuery::pinned` is dead weight. - -**This also disposes of a problem item 93 would otherwise have to solve.** With -both tiers sharing one row, something must order the four filters against the -user's pinned queries. Under this end state the question does not arise. - -**Blocked on 93, and deliberately not part of it.** The user needs to live with -the four buttons first and confirm they cover what they actually use. If one is -wrong, pinning is the escape hatch, and it has to still be there to be used. -Closing 93 and this together would remove the fallback before it was needed. - -**This is a user-visible removal, not a cleanup.** `pinned` shipped in 0.18.0: -`SaveQueryDialog` offers "Show as a button" (`src/savequerydialog.cpp:104`) and -the right-click menu offers "Move to menu" / "Show as a button" -(`src/mainwindow.cpp:1797`). Anyone who put a saved query on the row loses that -permanently. Semver on the user-visible surface makes it a minor bump with an -`### Upgrading` note. - -**The stored field is a separate decision from the UI.** `pinned` is written to -queries.json (`src/config.cpp:603`) and read back (`:542`). Two options, and the -cheaper one is also the reversible one: - -- **Stop reading it, leave it in the file.** Harmless: an ignored key, preserved - by the unknown-field handling, and a build that reintroduces pinning would - find every user's setting intact. -- **Strip it on the next save.** Cleaner file, and irreversible for anyone who - had it set. - -Prefer leaving it unless the user asks otherwise. No `kQueriesFormatVersion` -bump either way: an ignored optional field is not a breaking change. - -**Size: S.** Removing a field, two UI affordances and their tests. - - ## 99. The unread action is labelled "Toggle unread" whichever way it will go **Observed (user, from the notes):** "the label for 'toggle unread' should be -- cgit v1.2.3