Improve TUI search, deletion, and export workflows - #723
Conversation
roborev: Combined Review (
|
247e03c to
c8f1c6f
Compare
roborev: Combined Review (
|
c8f1c6f to
4fa0b70
Compare
roborev: Combined Review (
|
4fa0b70 to
9af74a9
Compare
roborev: Combined Review (
|
3026d35 to
3aa9b3c
Compare
roborev: Combined Review (
|
3aa9b3c to
5c791a3
Compare
roborev: Combined Review (
|
|
reviewing |
|
I pushed a follow-up in Here is what changed:
The generated API client was updated for the daemon path. The full tagged Go test suite, |
roborev: Combined Review (
|
|
Fixed the three follow-up review findings:
I added regression tests for each case. The full test suite, |
roborev: Combined Review (
|
|
Reviewed both follow-up findings:
I added focused coverage for the semantic case. The full test suite, |
roborev: Combined Review (
|
|
Fixed this follow-up issue. Whitespace and empty operators such as I added focused tests for both the TUI staging record and the exact daemon request. The full test suite, |
roborev: Combined Review (
|
|
Fixed both remaining review findings in 7383f92.
I added regression coverage for fast and deep deletion searches, empty-bucket filters, changed input, and invalid input. |
roborev: Combined Review (
|
|
Fixed the two latest review findings in
I added a real SQLite regression test for the grouped-row scope and an HTTP round-trip test for the saved filter details. The full test suite, vet, lint, and generated-client consistency check pass. |
roborev: Combined Review (
|
8eef0b3 to
9944314
Compare
|
Fixed the two latest bulk-deletion findings in
I added real SQLite coverage for every empty group and for the |
roborev: Combined Review (
|
|
Fixed and pushed in What changed:
I added regression tests for these cases. The query and TUI test suites, lint, and vet pass. |
roborev: Combined Review (
|
roborev: Combined Review (
|
|
Fixed the aggregate deletion scope issue. When an aggregate view has an active search, the rows, header totals, and deletion lookup now use the same body-aware search path, so a message cannot be staged because of a body match that was missing from the displayed row. I also added a regression test for that case and regenerated the browser API types that caused the linked CI failure. |
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
Add session search history, safe all-match deletion staging, and configurable attachment exports. Correct export-eml guidance and document Gmail deletion reconciliation. Follow-up fixes: - Keep aggregate statistics within the displayed search scope. - Preserve narrow deletion and search filters across local and remote paths. - Resolve deletion targets from authoritative live state. - Align aggregate deletion with body-aware search results. - Avoid fabricated totals on empty body-search pages. - Preserve aggregate-key-only matches and their statistics. - Follow the repository's testify helper policy in new tests. - Gate complete fast-search filters on daemon API schema 2.16. Generated with Codex Co-authored-by: Wes McKinney <wesmckinn+git@gmail.com> Co-authored-by: Codex <noreply@openai.com>
89970a8 to
8ec3cba
Compare
roborev: Combined Review (
|
Repeated label filters select matching aggregate rows as alternatives. The statistics path instead required every label on each message, so header totals could disagree with the displayed rows. Apply the grouped-label predicate before generic search processing so both paths count the same message population. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Recipient and label aggregate rows search both message metadata and the grouping key. Their header statistics searched only the grouping key, so a subject or sender match could appear with a zero total. Use the same message-level text scope for rows and statistics. Keep the recipient or label key as an additional match for its view. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Name aggregate rows can match a per-message display name or a phone fallback. Cache-only statistics omitted those fields, so the header could report zero while matching sender or recipient rows were visible. Use one field list for name-row filtering and statistics so their scopes stay aligned. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Label aggregate rows require structured and free-text label matches on the same label. Statistics matched them on separate labels, so header totals could include messages with no visible matching row. Keep both predicates in one label-row scope across SQLite and cached analytics. Also align the affected CI expectation and documentation route with current search behavior and site layout. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
Current main and this branch both add API schema 2.16 features. Preserve the complete search contracts and the new asynchronous import contracts so the PR can build and test against the current base branch. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
All-match staging already uses an exact List-ID filter to select messages, but the manifest dropped that filter. The saved audit record could not explain or reproduce the scope that produced its message IDs. Preserve the list ID in both the structured filters and raw match provenance. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Aggregate deletion could use a yearly predicate for a monthly key when the request omitted its granularity. Uppercase D also remained active while a new aggregate scope loaded, so it could combine fresh scope state with an old row. Infer omitted granularity from the selected time key and wait for fresh aggregate rows before resolving all matches. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Recipient operators checked only email addresses. Messages addressed to a phone number could disappear from search results, counts, and bulk deletion. Match exact recipient values against both email and phone fields. Keep domain suffix searches limited to email addresses. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
Phone-only recipients disappeared when a fast search used a view filter. Aggregate search could also commit a new query before its matching rows loaded, which made bulk deletion act on stale results. Match recipient filters against email or phone data. Keep deletion unavailable until rows for an unfinished aggregate search load. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
An explicit empty source list means that no sources match. Combining it with a complete filter erased that distinction, so statistics could include filtered messages from any source. Preserve the empty list when applying top-level statistics options to a filter. Generated with Codex Co-authored-by: Codex <noreply@openai.com>
roborev: Combined Review (
|
What changed
duses the selection/current row andDresolves every message-list filter or search match in the background before confirmation.[data].export_dirand routed TUI attachment ZIPs, downloads, and opened files through it.export-emlusage and default-filename guidance.Why
Search-heavy cleanup should not require retyping queries or selecting one loaded page at a time. Attachment exports should also have one predictable destination, while the CLI and sync docs should describe the behavior users actually get.
The all-match deletion path keeps source boundaries intact, rejects bounded semantic results, paginates fast and deep searches, stays responsive during resolution, and always presents the final count before a batch is staged.
Closes #40
Closes #41
Closes #44
Closes #72
Closes #88
Usage
dfor the current selection orDfor every filter/search match.export_dirunder[data]to choose where TUI attachment exports land. Relative paths resolve from the config directory; the default is<data_dir>/exports.msgvault export-eml <message-id> [source-message-id], optionally with-o -for stdout.