feat(sync-log): add per-mailbox timing to sync log (#104)

Track how long each mailbox takes to sync and display it in the
sync log expanded view (e.g. "2 new · 5 up-to-date · 1.3s").

- Add optional `duration` field to `MailboxSyncStats`
- Capture per-mailbox start/end time in both IMAP and JMAP sync loops
- Store as `duration_ms` in `sync_log_mailboxes` (schema v30 migration)
- Read back and reconstruct `Duration` in repository
- Show timing alongside fetch/skip counts in per-mailbox breakdown
- Extract `_fmtDuration` helper, reuse for the existing total duration

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Thomas SharedInbox
2026-05-15 22:03:36 +02:00
co-authored by Claude Sonnet 4.6
parent 1fd37cc966
commit 9763a1884a
7 changed files with 113 additions and 7 deletions
+6 -1
View File
@@ -204,6 +204,8 @@ class SyncLogMailboxes extends Table {
IntColumn get fetched => integer().withDefault(const Constant(0))();
IntColumn get skipped => integer().withDefault(const Constant(0))();
IntColumn get bytesTransferred => integer().withDefault(const Constant(0))();
// Added in schema v30: how long this mailbox took to sync, in milliseconds.
IntColumn get durationMs => integer().nullable()();
}
/// Stores the result of the periodic "ground truth" verification.
@@ -290,7 +292,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase([QueryExecutor? executor]) : super(executor ?? _openConnection());
@override
int get schemaVersion => 29;
int get schemaVersion => 30;
Future<void> _createEmailFts() async {
await customStatement('''
@@ -522,6 +524,9 @@ class AppDatabase extends _$AppDatabase {
if (from < 29) {
await m.createTable(localSieveScripts);
}
if (from >= 12 && from < 30) {
await m.addColumn(syncLogMailboxes, syncLogMailboxes.durationMs);
}
},
);
}
@@ -49,6 +49,7 @@ class SyncLogRepositoryImpl implements SyncLogRepository {
fetched: Value(s.fetched),
skipped: Value(s.skipped),
bytesTransferred: Value(s.bytesTransferred),
durationMs: Value(s.duration?.inMilliseconds),
),
);
}
@@ -90,6 +91,9 @@ class SyncLogRepositoryImpl implements SyncLogRepository {
fetched: m.fetched,
skipped: m.skipped,
bytesTransferred: m.bytesTransferred,
duration: m.durationMs != null
? Duration(milliseconds: m.durationMs!)
: null,
),
)
.toList(),