fix: fix inconsistent behavior with threading email messages in the inbox/folders

This commit is contained in:
Max Hao
2026-06-15 23:00:30 +02:00
committed by Linus Rath
parent f7d4f9d53c
commit fd700f412e
8 changed files with 309 additions and 13 deletions
+10
View File
@@ -388,6 +388,16 @@ export class DemoJMAPClient implements IJMAPClient {
return { id: threadId, emailIds: emails.map(e => e.id) };
}
async getThreads(threadIds: string[]): Promise<Thread[]> {
return threadIds
.map(tid => {
const emails = this.data.emails.filter(e => e.threadId === tid);
if (emails.length === 0) return null;
return { id: tid, emailIds: emails.map(e => e.id) };
})
.filter((t): t is Thread => t !== null);
}
async getThreadEmails(threadId: string): Promise<Email[]> {
return this.data.emails
.filter(e => e.threadId === threadId)
+1
View File
@@ -117,6 +117,7 @@ export interface IJMAPClient {
// ── Threads ───────────────────────────────────────────────────
getThread(threadId: string, accountId?: string): Promise<Thread | null>;
getThreads(threadIds: string[], accountId?: string): Promise<Thread[]>;
getThreadEmails(threadId: string, accountId?: string): Promise<Email[]>;
// ── Compose / Send ────────────────────────────────────────────
+18
View File
@@ -1904,6 +1904,24 @@ export class JMAPClient implements IJMAPClient {
}
}
async getThreads(threadIds: string[], accountId?: string): Promise<Thread[]> {
if (threadIds.length === 0) return [];
try {
const targetAccountId = accountId || this.accountId;
const response = await this.request([
["Thread/get", { accountId: targetAccountId, ids: threadIds }, "0"],
]);
if (response.methodResponses?.[0]?.[0] === "Thread/get") {
return (response.methodResponses[0][1].list || []) as Thread[];
}
return [];
} catch (error) {
console.error('Failed to get threads:', error);
return [];
}
}
async getThreadEmails(threadId: string, accountId?: string): Promise<Email[]> {
try {
const targetAccountId = accountId || this.accountId;
+10 -2
View File
@@ -5,8 +5,16 @@ import type { Email, ThreadGroup } from "./jmap/types";
* Single-email threads are still returned as ThreadGroups with emailCount=1.
* When disableThreading is true, each email is placed into its own group using
* its message ID as the key, so the list shows individual messages.
*
* @param threadEmailCounts - Optional map of threadId → total email count across
* all folders (from Thread/get). When provided, emailCount reflects the full
* thread size rather than just the emails in the current folder.
*/
export function groupEmailsByThread(emails: Email[], disableThreading = false): ThreadGroup[] {
export function groupEmailsByThread(
emails: Email[],
disableThreading = false,
threadEmailCounts?: Map<string, number>,
): ThreadGroup[] {
if (!emails || emails.length === 0) {
return [];
}
@@ -53,7 +61,7 @@ export function groupEmailsByThread(emails: Email[], disableThreading = false):
hasAttachment,
hasAnswered,
hasForwarded,
emailCount: sortedEmails.length,
emailCount: threadEmailCounts?.get(threadId) ?? sortedEmails.length,
});
}