Skip to content

Add hide-deleted filter and revamp filter modal#109

Merged
wesm merged 8 commits intomainfrom
filter-deleted-mail
Feb 8, 2026
Merged

Add hide-deleted filter and revamp filter modal#109
wesm merged 8 commits intomainfrom
filter-deleted-mail

Conversation

@wesm
Copy link
Owner

@wesm wesm commented Feb 8, 2026

Summary

  • New "Hide deleted from source" filter — excludes messages where deleted_from_source_at IS NOT NULL from aggregates, sub-aggregates, search results, and stats across both SQLite and DuckDB query engines
  • Revamped filter modal — replaces the old radio-button attachment filter with a checkbox-style modal supporting two independent toggles: "Only with attachments" and "Hide deleted from source"
  • Quieter batch fetch logs — expected 404s (messages deleted between list and fetch) are now logged at debug level instead of warn

Close #27, close #99

Filter modal UX

Filter Messages

▶ [x] Only with attachments
  [ ] Hide deleted from source

[↑/↓] Navigate  [Space/x] Toggle  [Enter/Esc] Apply
  • Space / x toggle individual checkboxes
  • Enter / Esc apply current filters and close the modal
  • Title bar shows active filters: [Attachments], [Hide Deleted]

Query layer changes

  • Added HideDeletedFromSource bool to MessageFilter, AggregateOptions, and StatsOptions
  • Applied deleted_from_source_at IS NULL condition in all relevant query paths:
    • SQLite: optsToFilterConditions, buildFilterJoinsAndConditions, GetTotalStats, SearchFast, SearchFastCount
    • DuckDB: buildWhereClause, buildFilterConditions, SubAggregate, GetTotalStats, buildSearchConditions
  • Extracted executeSearchQuery shared by Search and SearchFast to prevent drift

TUI changes

  • Replaced attachmentFilter bool with filters struct containing attachmentsOnly and hideDeletedFromSource
  • Filter toggles are resynced into drillFilter on modal close for both message list and sub-aggregate levels
  • Updated help text and title bar indicators

Test plan

  • TestHideDeletedFromSourceAggregate — SQLite aggregate + sub-aggregate with hide-deleted
  • TestHideDeletedFromSourceStats — SQLite stats with hide-deleted
  • TestHideDeletedFromSourceSearchFast — SQLite SearchFast/SearchFastCount with hide-deleted
  • TestDuckDBEngine_HideDeletedFromSource — DuckDB aggregate, sub-aggregate, search, count, and stats
  • TestFilterToggleModal — checkbox toggle and apply behavior
  • TestFilterToggleInMessageList — filter apply in message list context
  • TestFilterToggleInDrillDown — drillFilter resync on modal close during sub-aggregate
  • TestGetMessagesRawBatch_LogLevels — debug vs warn log levels for batch fetch errors
  • All existing tests pass (make test && make lint)

🤖 Generated with Claude Code

wesm and others added 8 commits February 8, 2026 09:17
Re-apply the NotFoundError handling in GetMessagesRawBatch that was lost
during the squash merge of PR #108: messages deleted between history scan
and fetch are expected during incremental sync, so log at debug instead
of warn. Add TestGetMessagesRawBatch_LogLevels to verify 404s produce
debug logs while other errors produce warn logs.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…leted

Replace the old radio-button attachment filter modal with a checkbox-style
modal supporting two independent toggles: "Only with attachments" and
"Hide deleted from source". Both filters are independent (not mutually
exclusive). Enter/Space toggles a checkbox; Esc applies and closes.

Add HideDeletedFromSource to MessageFilter, AggregateOptions, and
StatsOptions with corresponding SQL conditions in both SQLite and DuckDB
query engines.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Capture log attributes (message ID) in testLogHandler and assert
per-message expectations: msg_404 must produce only debug logs,
msg_err must produce only warn logs. This catches regressions where
a 404 is logged at both levels.

Remove unused staticTokenSource and oauth2 import.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
- SQLite SearchFast/SearchFastCount now apply HideDeletedFromSource
  directly instead of losing it through MergeFilterIntoQuery
- Resync drillFilter toggles when closing filter modal during drill-down
- Add DuckDB test coverage for HideDeletedFromSource across aggregates,
  SubAggregate, search, and stats
- Add SQLite SearchFast/SearchFastCount test for HideDeletedFromSource

Co-Authored-By: Claude Opus 4.6 <[email protected]>
…rch logic

- Resync drillFilter toggles when closing filter modal in levelDrillDown
  (not just levelMessageList), preventing stale SubAggregate filters
- Extract executeSearchQuery to eliminate duplicated query execution
  between Search and SearchFast
- Add filterOptionCount constant for cursor bounds
- Add TestFilterToggleInDrillDown regression test

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Enter and Esc both apply filters and close the modal. Space and x
toggle individual checkboxes. This matches the intuitive expectation
that Enter confirms the current selection.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Add HideDeleted field to search.Query and carry it through
MergeFilterIntoQuery, so deep FTS search (which only receives a
search.Query, not a MessageFilter) also excludes deleted messages
when the filter is active.

- Added search.Query.HideDeleted bool
- MergeFilterIntoQuery now sets HideDeleted from filter
- buildSearchQueryParts (SQLite) applies the condition
- DuckDB fallback Search path applies the condition
- Removed duplicate condition appends from SearchFast/SearchFastCount
  (now flows through the merged query like all other filter fields)
- Added TestSearch_HideDeleted covering Search, MergeFilterIntoQuery

Co-Authored-By: Claude Opus 4.6 <[email protected]>
@github-actions
Copy link

github-actions bot commented Feb 8, 2026

Security Review: No High/Medium Issues Found

Claude's automated security review did not identify any high or medium severity security concerns in this PR.

Note: This is an automated review and should not replace human security review, especially for changes involving:

  • OAuth token handling
  • Email data access or export
  • Deletion operations (Gmail API)
  • Database queries (SQL injection surface)
  • File system operations (path traversal)
  • CGO or native dependencies

Powered by Claude 4.5 Sonnet

@wesm wesm merged commit 783a3ec into main Feb 8, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: TUI show sizes with/without what was deleted. Update stats on deletion

1 participant