diff options
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 | 133 |
1 files changed, 28 insertions, 105 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 5faf859..268dbb4 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 @@ -87,7 +87,7 @@ taking that too literally. | 20 | Thread view does not match the user's mental model | presentation | L | **done** 2026-08-10, as the card list; see 53 | | 21 | Default shortcuts are not sensible enough | discoverability | S | open | | 22 | Translatability audit and i18n wiring | correctness | M | open | -| 23 | No way to save a search query from the UI | workflow | M | open, specified 2026-08-13. Saved queries move to `queries.json`, which carries order, `pinned` and account scope; wants a spec before building | +| 23 | No way to save a search query from the UI | workflow | M | open, specified 2026-08-13; see `specs/2026-08-13-saved-queries-design.md`. Saved queries move to `queries.json`, carrying order, `pinned` and account scope | | 24 | No right-click actions on the thread list | discoverability | S | **done** | | 25 | No select-all, and bulk actions are undiscoverable | workflow | S | **done** | | 26 | No way to add or remove an arbitrary tag from the UI | workflow | S | **done** | @@ -145,7 +145,7 @@ taking that too literally. | 78 | No way to build a rule from something visible in a message | workflow | M | open; wants 76 first, so the created rule lands in a form that can hold it | | 80 | A rule with many conditions squeezes the rule list to one visible row | defect | XS | **done** 2026-08-13 on `rule-builder`, unreleased. Follows item 76 | | 79 | Opening the rules dialog and saving destroys the first rule | defect | XS | **fixed on `rule-builder`** 2026-08-13, unreleased. Shipped in 0.16.0; damaged one real rule, repaired by hand | -| 81 | No way to turn a saved query into a tagging rule | workflow | S | open; split out of 23 on 2026-08-13 and depends on it. Writes to the shared rules file, so it spans this repo and `mailctl` | +| 81 | No way to turn a saved query into a tagging rule | workflow | S | open; depends on 23, which builds the dialog, and is excluded from its spec on purpose. Writes to the shared rules file, so it spans this repo and `mailctl` | Sizes are rough: XS under an hour, S a sitting, M a session. @@ -213,112 +213,35 @@ does not appear there is not translatable, whatever the source looks like. **Observed (user, 2026-08-04):** saved queries live in the config file only. There is no way to keep a query you have just written without editing -`qtmaildir.conf` by hand. - -**Design (user, 2026-08-13).** The user described the shape they want, which is -more specific than the original sketch and settles the file question below. - -- A **Save query** button beside the search bar. It opens a dialog on the - current query bar contents, where the query gets a **name**, an **account - scope**, and whatever else is worth editing before it is kept. -- **Two tiers, presented differently.** Queries like Inbox and Unread stay - visible as buttons; user-made ones like "all messages from one correspondent" - go behind a menu. Today every entry in `[queries]` becomes a button - (`src/mainwindow.cpp:557`), which is the thing that does not scale. -- If the tiers split, **the button row moves to a row of its own**, rather than - sharing the query row with the account box, the sort dropdown and the query - bar. - -**There is no built-in default set.** Nothing in the code distinguishes a -default query from a user-made one: every entry in `[queries]` is user-written -config and is rendered identically. Sent is the lone exception and is not in -`[queries]` at all, it is built from `allSentQuery()` -(`src/mainwindow.cpp:579`). So the two tiers need a mechanism that does not -exist yet. - -**Decision (user, 2026-08-13): saved queries move out of the INI into -`~/.config/qtmaildir/queries.json`.** The user proposed it by analogy with the -rules file, and it is a better answer than the two the entry had considered (a -per-query `pinned` flag inside `[queries]`, or a `[general] pinned_queries` -list). It solves three things at once where those solved one each. - -- **Order.** `[queries]` is read through `childKeys()`, which returns keys - alphabetically and not in file order, so button order is alphabetical today - and cannot be chosen. `src/config.cpp:401` already records that a hand-rolled - parser would be needed to change it. A JSON array is ordered intrinsically, - so the row of buttons can be arranged. -- **The `pinned` flag**, which decides the two tiers. -- **Per-query account scope**, which the save dialog wants and which - `SavedQuery` (`src/config.h:99`) has no room for: it is `{name, query}` and - nothing else. - -**Take the shape of `rules.json`, not its machinery.** That file is JSON because -it has TWO independent implementations that must agree, this repo and mailctl's -`mailrules.py`; the unknown-field preservation and the `kFormatVersion` -handshake exist to stop two programs destroying each other's writes. Queries -have exactly one reader, so copying that wholesale would import the ceremony -without the reason for it. What is worth carrying across is a versioned document -read and written by one class, preserving unknown fields on the way through so a -field added later is not stripped by an older build. - -**Migration: read `[queries]` once, write the JSON, and leave the INI section -alone.** `[queries]` exists in the user's live config and in the README, so it -cannot simply stop being read. On a run where `queries.json` is absent, the -section is read, converted and written out; from then on `[queries]` is ignored -entirely. **Do not strip the section:** removing it means rewriting the -hand-edited file with QSettings, which drops comments and key order across the -WHOLE file and is exactly the loss this decision avoids. Leaving it costs a few -stale lines the user can delete by hand, and keeps a downgrade working. The -README should mark it legacy. Reject the third option, reading both forever: -two sources of truth for one thing, with no answer for which wins on a name -collision or where the dialog writes. - -**This retires the entry's original open question.** It asked whether the write -went to `qtmaildir.conf` or `uistate.conf`, and both answers were poor: the -first machine-writes a hand-edited file, the second files user intent as window -state. A machine-written JSON document beside the hand-written INI is the -cleaner split, and the README caveat about losing comments goes away with it. -The file belongs in `~/.config/`, not `~/.local/state/`: it is the user's -intent, hand-editable, and belongs in a config backup, which a state directory -is commonly excluded from. - -**"Save as a filter" is deliberately not part of this item.** The user raised it -as an option: the same dialog could write the query out as a tagging rule, the -reverse of item 77's Preview in list. It is left out because a rule is not a -view. Rules live in `~/.config/mailrules/rules.json`, which has two independent -implementations that agree by test rather than by shared code, and a `post-new` -hook applies them to real mail every ten minutes. Writing one is a two-repo -commitment with a live blast radius, and folding it in here would make a -presentation change carry that risk. It is item 81. +`qtmaildir.conf` by hand. Underneath it, every saved query becomes a button +(`src/mainwindow.cpp:557`), so the query row grows without bound and cannot tell +Inbox from a one-off search. + +**Specified 2026-08-13. Read +`specs/2026-08-13-saved-queries-design.md` instead of planning from here.** + +The three things that decide whether this can be picked up: + +- **Saved queries move out of `[queries]` into + `~/.config/qtmaildir/queries.json`**, gaining an order, a `pinned` flag and a + per-query account scope. The INI cannot express order at all: `childKeys()` + returns keys alphabetically and `src/config.cpp:401` already records that a + hand-rolled parser would be needed to change it. +- **It stays a single-repo change.** The format takes the shape of `rules.json`, + a versioned document preserving unknown fields, but none of its + two-implementation machinery, because queries have one reader. +- **`startup_query`'s fallback changes meaning**, from alphabetically-first to + first-in-the-user's-order. User-visible, so this is a minor bump and wants a + changelog line. The README documents `[queries]` in three places, one of which + explains the alphabetical ordering this removes. **Relation to item 10.** Item 10 is postponed, but its second half proposed exactly this: "saved queries that carry their own account scope, so one action -gets there". The 2026-08-13 design puts account scope in the save dialog -outright, so item 10's remaining complaint is answered as a side effect rather -than needing its own work. `Account::scopedQuery()` (`src/config.cpp:42`) -already composes the scope, so this is a UI question, not a query question. Do -not reopen item 10 to do it: the user postponed it and asked that the remaining -work not be proposed unprompted. - -**Constraint:** the button row is built inline in `MainWindow` -(`src/mainwindow.cpp:554-587`). There is no `SavedQueryBar` class and there -never has been, whatever an older revision of this entry said. Moving the -buttons to their own row is a change to that layout code. - -**Constraint: `startup_query` names a saved query by name**, and resolves -against the list with a case-insensitive match plus a fallback to the first -entry (`Config::startupSavedQuery()`, `src/config.cpp:422`). It must keep -resolving across the migration, which also means the "first entry" fallback -stops meaning "alphabetically first" and starts meaning "first in the user's own -order". That is an improvement rather than a regression, but it changes which -query a config with an unmatched `startup_query` opens on, so it is a -user-visible change and belongs in the changelog. - -**Constraint: the README documents `[queries]` in three places** (the -`startup_query` note at :109, the sample config at :194, and the query-row -description at :256), including a line explaining that buttons appear in -alphabetical order rather than file order. That explanation is exactly what this -change removes, so all three need revising, not just the sample. +gets there". The account scope in the save dialog answers it as a side effect. +Do not reopen item 10 to do it: the user postponed it and asked that the +remaining work not be proposed unprompted. + +**Item 81 depends on this** and is deliberately not part of it. ## 36. `test_mainwindow` cannot reach the worker |
