summaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans/2026-08-03-post-0.1.0-usability.md
diff options
context:
space:
mode:
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.md133
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