From e9ab11023f80a031d8fd3ac179888dbf7d5ee673 Mon Sep 17 00:00:00 2001 From: Quinn Ftw Date: Tue, 30 Dec 2025 16:01:43 -0800 Subject: [PATCH] feat(conversation-assistant): add contacts count to webapp stats display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add totalContacts to sync stats API and display in macOS client webapp, showing Messages Synced, Conversations, Contacts, and Last Sync. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../conversation-assistant/frontend-macos-client/app.js | 4 ++++ .../conversation-assistant/frontend-macos-client/index.html | 4 ++++ .../macos/Sources/Services/APIClient.swift | 2 ++ .../macos/Sources/Services/LocalWebServer.swift | 1 + .../macos/Sources/Services/SyncManager.swift | 6 ++++-- .../server/src/modules/sync/sync.service.ts | 5 +++++ 6 files changed, 20 insertions(+), 2 deletions(-) diff --git a/features/conversation-assistant/frontend-macos-client/app.js b/features/conversation-assistant/frontend-macos-client/app.js index e7599611c..157fcde5d 100644 --- a/features/conversation-assistant/frontend-macos-client/app.js +++ b/features/conversation-assistant/frontend-macos-client/app.js @@ -16,6 +16,7 @@ let state = { syncErrorMessage: null, messageCount: 0, conversationCount: 0, + contactCount: 0, lastSync: null, needsFullDiskAccess: false, isSyncing: false, @@ -62,6 +63,7 @@ function cacheElements() { elements.activitySection = document.getElementById('activity-section'); elements.statMessages = document.getElementById('stat-messages'); elements.statConversations = document.getElementById('stat-conversations'); + elements.statContacts = document.getElementById('stat-contacts'); elements.statLastSync = document.getElementById('stat-last-sync'); elements.activityLog = document.getElementById('activity-log'); @@ -252,6 +254,7 @@ function updateFromStatus(status) { state.syncErrorMessage = status.syncErrorMessage; state.messageCount = status.messageCount || 0; state.conversationCount = status.conversationCount || 0; + state.contactCount = status.contactCount || 0; state.lastSync = status.lastSync; state.needsFullDiskAccess = status.needsFullDiskAccess || false; state.isSyncing = status.isSyncing || false; @@ -431,6 +434,7 @@ function renderConnectedView() { // Stats elements.statMessages.textContent = formatNumber(state.messageCount); elements.statConversations.textContent = formatNumber(state.conversationCount); + elements.statContacts.textContent = formatNumber(state.contactCount); elements.statLastSync.textContent = formatRelativeTime(state.lastSync); // Activity log diff --git a/features/conversation-assistant/frontend-macos-client/index.html b/features/conversation-assistant/frontend-macos-client/index.html index 9912f654a..588ae4663 100644 --- a/features/conversation-assistant/frontend-macos-client/index.html +++ b/features/conversation-assistant/frontend-macos-client/index.html @@ -81,6 +81,10 @@ Conversations 0 +
+ Contacts + 0 +
Last Sync Never diff --git a/features/conversation-assistant/macos/Sources/Services/APIClient.swift b/features/conversation-assistant/macos/Sources/Services/APIClient.swift index 165c1587c..86d61f710 100644 --- a/features/conversation-assistant/macos/Sources/Services/APIClient.swift +++ b/features/conversation-assistant/macos/Sources/Services/APIClient.swift @@ -200,6 +200,7 @@ class APIClient { return SyncStatsResponse( totalMessages: json["data"]["totalMessages"].intValue, totalConversations: json["data"]["totalConversations"].intValue, + totalContacts: json["data"]["totalContacts"].intValue, lastSyncAt: lastSyncAt ) } @@ -391,6 +392,7 @@ struct SyncMessagePayload: Encodable { struct SyncStatsResponse { let totalMessages: Int let totalConversations: Int + let totalContacts: Int let lastSyncAt: Date? } diff --git a/features/conversation-assistant/macos/Sources/Services/LocalWebServer.swift b/features/conversation-assistant/macos/Sources/Services/LocalWebServer.swift index 4c566ccb6..94ec1b646 100644 --- a/features/conversation-assistant/macos/Sources/Services/LocalWebServer.swift +++ b/features/conversation-assistant/macos/Sources/Services/LocalWebServer.swift @@ -193,6 +193,7 @@ class LocalWebServer { "syncErrorMessage": syncErrorMessage as Any, "messageCount": syncManager.stats.messageCount, "conversationCount": syncManager.stats.conversationCount, + "contactCount": syncManager.stats.contactCount, "lastSync": syncManager.lastSync.map { ISO8601DateFormatter().string(from: $0) } as Any, "needsFullDiskAccess": syncManager.syncError == .fullDiskAccessRequired, "isSyncing": syncManager.isSyncing, diff --git a/features/conversation-assistant/macos/Sources/Services/SyncManager.swift b/features/conversation-assistant/macos/Sources/Services/SyncManager.swift index a14a4bf20..bf22b6e52 100644 --- a/features/conversation-assistant/macos/Sources/Services/SyncManager.swift +++ b/features/conversation-assistant/macos/Sources/Services/SyncManager.swift @@ -5,6 +5,7 @@ import Foundation struct SyncStats { var messageCount: Int = 0 var conversationCount: Int = 0 + var contactCount: Int = 0 } enum SyncError: Equatable { @@ -313,12 +314,13 @@ class SyncManager: ObservableObject { NSLog("SyncManager: fetchStats starting") do { let response = try await apiClient.getStats() - NSLog("SyncManager: fetchStats - got totalMessages: \(response.totalMessages), totalConversations: \(response.totalConversations)") + NSLog("SyncManager: fetchStats - got totalMessages: \(response.totalMessages), totalConversations: \(response.totalConversations), totalContacts: \(response.totalContacts)") // Update stats from server response let newStats = SyncStats( messageCount: response.totalMessages, - conversationCount: response.totalConversations + conversationCount: response.totalConversations, + contactCount: response.totalContacts ) stats = newStats diff --git a/features/conversation-assistant/server/src/modules/sync/sync.service.ts b/features/conversation-assistant/server/src/modules/sync/sync.service.ts index 69a6b9d38..960901e7e 100644 --- a/features/conversation-assistant/server/src/modules/sync/sync.service.ts +++ b/features/conversation-assistant/server/src/modules/sync/sync.service.ts @@ -255,6 +255,7 @@ export class SyncService { async getStats(deviceId: string): Promise<{ totalMessages: number; totalConversations: number; + totalContacts: number; lastSyncAt: string | null; }> { // Count conversations for this device @@ -277,12 +278,16 @@ export class SyncService { .getCount(); } + // Count all contacts (global, not per-device) + const totalContacts = await this.contactRepository.count(); + // Get last sync time const lastSync = await this.getLastSync(deviceId); return { totalMessages, totalConversations, + totalContacts, lastSyncAt: lastSync?.toISOString() ?? null, }; }