Skip to content

feat: add thread archiving, unread filters, and pagination - #1025

Merged
AchoArnold merged 11 commits into
mainfrom
feat/thread-archive-unread-filters
Oct 27, 2026
Merged

AchoArnold merged 11 commits into
mainfrom
feat/thread-archive-unread-filters

Conversation

@AchoArnold

@AchoArnold AchoArnold commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Add an Archive New Outgoing Message Threads setting per phone, off by default, with a persistent explanation in the settings form.
  • Add All and Unread thread filters using the requested normal-button styling.
  • Add conditional Load More in 20-thread pages, with row-count-based pagination and polling/filter preservation.
  • Add API integration coverage for archiving, unread filtering, and pagination.
  • Resolve frontend type-check errors and restore the full Last Used login badge.

Behavior and scope

  • Use ArchiveNewOutgoingMessageThreads in Go and archive_new_outgoing_message_threads for JSON and the database column.

  • Archive only newly created outgoing conversations when the phone setting is enabled. Incoming conversations and existing conversations are unaffected.

  • Keep reply behavior controlled by the existing independent unarchive_thread setting.

  • Filter unread conversations on the server before pagination, scoped to the selected phone and inbox/archive view.

  • Remove conversations from Unread when marked read without interrupting the open conversation. Ignore stale polling responses after filter changes.

  • Keep the thread list scrollable with the taller header.

  • Retain strict type checking, add vue-tsc, and use Nuxt's generated TypeScript project configuration.

  • Deep links resolve individual conversations independently of pagination, including older/archived records and phone selection.

  • Pagination now uses only returned page counts: no has_more response field or extra-row fetch. A full page keeps Load More available until a shorter or empty page is returned.

  • The atomic message updater is named IncreaseSendAttemptCount. Phone lookup errors are warned and new conversations default to unarchived without failing creation.

Validation

  • API: go test ./... and go vet ./....
  • Frontend: pnpm exec nuxt typecheck, pnpm test (64 tests), production build, and lint/format checks for changed files.
  • Integration: current count-based pagination and unread tests passed on the real isolated API, including full/partial/empty pages and direct older/archived/cross-user lookups. The complete suite and 10 Excel bulk stress runs also passed earlier in this PR.
  • Browser: desktop/mobile filter interaction and selection retention; unclipped login badges for Google, GitHub, and email.

Deployment verification

The Firebase deployer was granted the missing read-only Service Usage Viewer role. Re-running the failed deployment for unchanged main succeeded: https://github.com/NdoleStudio/httpsms/actions/runs/39730796417

@AchoArnold

Copy link
Copy Markdown
Member Author

@greptileai review

@codacy-production

codacy-production Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 215 complexity · 28 duplication

Metric Results
Complexity 215
Duplication 28

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@greptile-apps

greptile-apps Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The changes appear safe to merge; no new blocking issues were found.

Summary

Adds per-phone outgoing conversation archiving, server-side Unread filters, and 20-conversation pages.

  • Phones can archive new conversations started by outgoing messages.
  • The thread list filters unread conversations and loads results 20 at a time.
  • Conversation links open the requested conversation even when it is not on the loaded pages.
  • Send-attempt counts increase without overwriting newer message data.
  • Frontend type checking uses Nuxt's generated project setup.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Open conversation] --> B{Already loaded?}
  B -->|Yes| E[Load messages]
  B -->|No| C[Fetch conversation by ID]
  C --> D[Restore phone and archive view]
  D --> E
  F[Choose All or Unread] --> G[Fetch filtered 20-row pages]
  G --> H{Last page full?}
  H -->|Yes| I[Show Load More]
  H -->|No| J[Hide Load More]
Loading

Reviews (6) · Last reviewed commit: "refactor: apply local thread lookup edit..." · Reviewed by Greptile

Comment thread api/pkg/services/phone_service.go
Comment thread web/app/stores/threads.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Phone creation drops the archive preference, and unread conversation handling has unresolved navigation, refresh, and polling consistency issues.

4 open issues
1 file not reviewed
  • api/docs/docs.go: Generated file
What changed in this PR

This PR adds per-phone automatic archiving for new outgoing conversations and server-side unread filtering to httpSMS, with frontend controls and regression coverage.

Changes:

  • Add the archive preference across phone settings, API models, persistence, and thread creation.
  • Add All/Unread filters, selected-conversation retention, and stale list-response protection.
  • Expand tests and update frontend typing, styles, and login badge visibility.
File Description
web/​tsconfig.json Use Nuxt-generated TypeScript project configuration.
web/​shared/​types/​api.ts Add archive-setting types and refresh generated documentation.
web/​package.json Add vue-tsc for frontend type checking.
web/​nuxt.config.ts Register phone-input styles globally.
web/​app/​utils/​errors.ts Use typed entry iteration for errors.
web/​app/​utils/​bag.ts Use typed entry iteration for collections.
web/​app/​stores/​threads.ts Add unread filtering and selected-thread retention.
web/​app/​stores/​threads.test.ts Test filtering, retention, and stale responses.
web/​app/​stores/​phones.ts Include the archive preference in updates.
web/​app/​stores/​app.ts Use inferred runtime configuration types.
web/​app/​plugins/​vPhoneInput.client.ts Remove the relocated stylesheet import.
web/​app/​pages/​settings/​index.vue Add the archive-setting switch and explanation.
web/​app/​pages/​search-messages/​index.vue Adjust error iteration for type safety.
web/​app/​pages/​phone-api-keys/​index.vue Adjust error iteration for type safety.
web/​app/​pages/​index.vue Read message counts from existing display labels.
web/​app/​pages/​bulk-messages/​index.vue Tighten error and filename handling types.
web/​app/​layouts/​default.vue Keep threads scrollable below the taller header.
web/​app/​composables/​useApi.ts Infer the API fetch wrapper’s return type.
web/​app/​components/​MessageThreadHeader.vue Add All/Unread filter controls.
web/​app/​components/​MessageThread.vue Render filtered threads and unread empty state.
web/​app/​components/​FirebaseAuth.vue Prevent Last Used badge clipping.
tests/​unread_filter_integration_test.go Test unread filtering, pagination, and validation.
tests/​unarchive_thread_integration_test.go Expose unread counts in test responses.
tests/​archive_new_outgoing_message_threads_integration_test.go Test archive preferences and reply behavior.
api/​pkg/​validators/​message_thread_handler_validator.go Validate the unread filter.
api/​pkg/​services/​phone_service.go Apply archive preferences during phone updates.
api/​pkg/​services/​phone_service_test.go Test archive-setting update semantics.
api/​pkg/​services/​message_thread_service.go Apply archiving on creation and forward unread filtering.
api/​pkg/​services/​message_thread_service_test.go Test creation rules and existing-thread behavior.
api/​pkg/​services/​message_thread_service_contacts_test.go Update repository stubs for unread filtering.
api/​pkg/​requests/​phone_update_request.go Preserve archive-setting field presence.
api/​pkg/​requests/​phone_update_request_test.go Test enabled, disabled, and omitted values.
api/​pkg/​requests/​message_thread_index_request.go Parse and default the unread filter.
api/​pkg/​repositories/​message_thread_repository.go Extend the thread-list interface.
api/​pkg/​repositories/​gorm_message_thread_repository.go Apply unread filtering before pagination.
api/​pkg/​repositories/​gorm_message_thread_repository_test.go Verify unread query construction.
api/​pkg/​listeners/​read_receipts_test_helpers_test.go Update the repository test helper signature.
api/​pkg/​handlers/​message_thread_handler.go Document the unread query parameter.
api/​pkg/​handlers/​message_thread_handler_test.go Update the repository stub signature.
api/​pkg/​handlers/​message_thread_handler_contacts_test.go Test unread query forwarding and rejection.
api/​pkg/​entities/​phone.go Add the default-off archive preference.
api/​docs/​swagger.yaml Publish updated API schemas and query documentation.
api/​docs/​swagger.json Publish updated API schemas and query documentation.
api/​docs/​docs.go Refresh embedded Swagger documentation.

Review effort: Balanced

Comment thread api/pkg/services/phone_service.go
Comment thread web/app/stores/threads.ts Outdated
Comment thread web/app/stores/threads.ts Outdated
Comment thread web/app/stores/threads.ts Outdated
@AchoArnold

Copy link
Copy Markdown
Member Author

@greptileai review

Add per-phone outgoing archiving and server-side unread filtering.

Include integration coverage, frontend type fixes, and login badge fixes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
@AchoArnold AchoArnold changed the title feat: add per-phone thread archiving and unread filters feat: add thread archiving, unread filters, and pagination Oct 27, 2026
@AchoArnold

Copy link
Copy Markdown
Member Author

@greptileai review

Comment thread web/app/stores/threads.ts Outdated
AchoArnold and others added 6 commits October 27, 2026 14:43
Persist the supplied outgoing-thread archive setting on first registration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Apply saved contact metadata when Unread excludes the open conversation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Refresh polls overlapping read mutations and retain scoped conversation history.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Increment send attempts atomically without overwriting concurrently scheduled state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Load 20 threads per page with server look-ahead and stable pagination ordering.

Preserve loaded pages across polling and reset pagination when filters change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Resolve conversations independently of paging and restore phone/archive context.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
@AchoArnold

Copy link
Copy Markdown
Member Author

@greptileai review

AchoArnold and others added 3 commits October 27, 2026 22:04
Remove has_more response metadata and internal extra-row look-ahead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
Log the phone lookup failure and continue saving the unarchived thread.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
@AchoArnold

Copy link
Copy Markdown
Member Author

@greptileai review

Pagination is intentionally count-based per the requested design: no has_more field and no extra-row look-ahead. A full page may leave Load More visible until a shorter or empty page is fetched.

Remove the phone-specific read check and adjust cancellation wording.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: aad7909a-5c34-42df-a4d2-ae6c83c22e7b
@AchoArnold

Copy link
Copy Markdown
Member Author

@greptileai review

@AchoArnold
AchoArnold merged commit 373be60 into main Oct 27, 2026
13 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.

2 participants