feat: add onEmailsFetched and onSearchResults hook + new JMAP method getSomeEmails
This commit is contained in:
committed by
Linus Rath
parent
c1acf58c5f
commit
622adc34de
@@ -166,6 +166,19 @@ export class DemoJMAPClient implements IJMAPClient {
|
|||||||
return { emails, hasMore: position + limit < total, total };
|
return { emails, hasMore: position + limit < total, total };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSomeEmails(emailsId: string[], _accountId?: string): Promise<Email[]> {
|
||||||
|
if (!emailsId || emailsId.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const filtered = this.data.emails.filter(e => emailsId.includes(e.id));
|
||||||
|
|
||||||
|
filtered.sort((a, b) =>
|
||||||
|
new Date(b.receivedAt).getTime() - new Date(a.receivedAt).getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
async getEmailsInMailbox(mailboxId: string): Promise<Email[]> {
|
async getEmailsInMailbox(mailboxId: string): Promise<Email[]> {
|
||||||
return this.data.emails.filter(e => e.mailboxIds[mailboxId]);
|
return this.data.emails.filter(e => e.mailboxIds[mailboxId]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ export interface IJMAPClient {
|
|||||||
getEmails(mailboxId?: string, accountId?: string, limit?: number, position?: number, hasKeyword?: string, pinnedFirst?: boolean): Promise<{ emails: Email[]; hasMore: boolean; total: number }>;
|
getEmails(mailboxId?: string, accountId?: string, limit?: number, position?: number, hasKeyword?: string, pinnedFirst?: boolean): Promise<{ emails: Email[]; hasMore: boolean; total: number }>;
|
||||||
getEmailsInMailbox(mailboxId: string): Promise<Email[]>;
|
getEmailsInMailbox(mailboxId: string): Promise<Email[]>;
|
||||||
getEmail(emailId: string, accountId?: string): Promise<Email | null>;
|
getEmail(emailId: string, accountId?: string): Promise<Email | null>;
|
||||||
|
getSomeEmails(emailsId: string[], accountId?: string): Promise<Email[]>
|
||||||
getTagCounts(tagIds: string[]): Promise<Record<string, { total: number; unread: number }>>;
|
getTagCounts(tagIds: string[]): Promise<Record<string, { total: number; unread: number }>>;
|
||||||
searchEmails(query: string, mailboxId?: string, accountId?: string, limit?: number, position?: number): Promise<{ emails: Email[]; hasMore: boolean; total: number }>;
|
searchEmails(query: string, mailboxId?: string, accountId?: string, limit?: number, position?: number): Promise<{ emails: Email[]; hasMore: boolean; total: number }>;
|
||||||
advancedSearchEmails(
|
advancedSearchEmails(
|
||||||
|
|||||||
@@ -550,6 +550,43 @@ export class JMAPClient implements IJMAPClient {
|
|||||||
this.authHeader = `Bearer ${token}`;
|
this.authHeader = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getSomeEmails(emailsId: string[], accountId?: string): Promise<Email[]> {
|
||||||
|
try {
|
||||||
|
const targetAccountId = accountId || this.accountId;
|
||||||
|
if (!emailsId || emailsId.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await this.request([
|
||||||
|
["Email/get", {
|
||||||
|
accountId: targetAccountId,
|
||||||
|
ids: emailsId,
|
||||||
|
properties: [...EMAIL_LIST_PROPERTIES],
|
||||||
|
}, "0"],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const getResponse = response.methodResponses?.[0]?.[1];
|
||||||
|
|
||||||
|
if (response.methodResponses?.[0]?.[0] === "Email/get" && getResponse) {
|
||||||
|
const emails = (getResponse.list || []) as Email[];
|
||||||
|
|
||||||
|
emails.sort((a: Email, b: Email) =>
|
||||||
|
new Date(b.receivedAt).getTime() - new Date(a.receivedAt).getTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (accountId && accountId !== this.accountId) {
|
||||||
|
namespaceMailboxIds(emails, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return emails;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to get specific emails:', error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
/** Upgrade an existing basic-auth client to bearer-token auth (e.g. after TOTP token exchange). */
|
/** Upgrade an existing basic-auth client to bearer-token auth (e.g. after TOTP token exchange). */
|
||||||
upgradeToBearer(accessToken: string, onRefresh?: () => Promise<string | null>): void {
|
upgradeToBearer(accessToken: string, onRefresh?: () => Promise<string | null>): void {
|
||||||
this.authMode = 'bearer';
|
this.authMode = 'bearer';
|
||||||
|
|||||||
@@ -272,6 +272,10 @@ export const emailHooks = {
|
|||||||
// normally. This is the send-takeover hook used by the S/MIME plugin to
|
// normally. This is the send-takeover hook used by the S/MIME plugin to
|
||||||
// replace the former native sign+encrypt+sendRaw pipeline.
|
// replace the former native sign+encrypt+sendRaw pipeline.
|
||||||
onComposeSend: new HookBus(),
|
onComposeSend: new HookBus(),
|
||||||
|
// Transform hook - receive Email[] or ScheduledEmail[] just after there are fetched to
|
||||||
|
// lets plugin edit emails before they are shown in row. Used to populate preview
|
||||||
|
// field for encryption plugins.
|
||||||
|
onEmailsFetched: new HookBus(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// §7.2 Calendar Hooks
|
// §7.2 Calendar Hooks
|
||||||
|
|||||||
+98
-80
@@ -918,8 +918,9 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
for (const email of result.emails) {
|
for (const email of result.emails) {
|
||||||
email.sourceFolder = resolveSourceFolderName(email, allMailMailboxes);
|
email.sourceFolder = resolveSourceFolderName(email, allMailMailboxes);
|
||||||
}
|
}
|
||||||
|
const enrichedEmails = await emailHooks.onEmailsFetched.transform(result.emails);
|
||||||
set({
|
set({
|
||||||
emails: annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId),
|
emails: annotateScheduledEmails(enrichedEmails, get().scheduledSubmissionByEmailId),
|
||||||
hasMoreEmails: result.hasMore,
|
hasMoreEmails: result.hasMore,
|
||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
@@ -946,8 +947,9 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
// When filtering by tag, omit the mailbox constraint so emails across
|
// When filtering by tag, omit the mailbox constraint so emails across
|
||||||
// all folders that carry the tag are returned.
|
// all folders that carry the tag are returned.
|
||||||
const result = await effectiveClient.getEmails(selectedKeyword ? undefined : jmapMailboxId, accountId, emailsPerPage, 0, keywordFilter, true);
|
const result = await effectiveClient.getEmails(selectedKeyword ? undefined : jmapMailboxId, accountId, emailsPerPage, 0, keywordFilter, true);
|
||||||
|
const enrichedEmails = await emailHooks.onEmailsFetched.transform(result.emails);
|
||||||
set({
|
set({
|
||||||
emails: annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId),
|
emails: annotateScheduledEmails(enrichedEmails, get().scheduledSubmissionByEmailId),
|
||||||
hasMoreEmails: result.hasMore,
|
hasMoreEmails: result.hasMore,
|
||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
// Clear thread caches since the email list was fully replaced
|
// Clear thread caches since the email list was fully replaced
|
||||||
@@ -991,8 +993,9 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
const currentEmails = get().emails;
|
const currentEmails = get().emails;
|
||||||
const existingIds = new Set(currentEmails.map(e => e.id));
|
const existingIds = new Set(currentEmails.map(e => e.id));
|
||||||
const newEmails = result.emails.filter(e => !existingIds.has(e.id));
|
const newEmails = result.emails.filter(e => !existingIds.has(e.id));
|
||||||
|
const enrichedNewEmails = await emailHooks.onEmailsFetched.transform(newEmails);
|
||||||
set({
|
set({
|
||||||
emails: [...currentEmails, ...newEmails],
|
emails: [...currentEmails, ...enrichedNewEmails],
|
||||||
hasMoreEmails: result.hasMore,
|
hasMoreEmails: result.hasMore,
|
||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
isLoadingMore: false,
|
isLoadingMore: false,
|
||||||
@@ -1034,8 +1037,9 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
const currentEmails = get().emails;
|
const currentEmails = get().emails;
|
||||||
const existingIds = new Set(currentEmails.map(e => e.id));
|
const existingIds = new Set(currentEmails.map(e => e.id));
|
||||||
const newEmails = result.emails.filter(e => !existingIds.has(e.id));
|
const newEmails = result.emails.filter(e => !existingIds.has(e.id));
|
||||||
|
const enrichedNewEmails = await emailHooks.onEmailsFetched.transform(newEmails);
|
||||||
set({
|
set({
|
||||||
emails: [...currentEmails, ...newEmails],
|
emails: [...currentEmails, ...enrichedNewEmails],
|
||||||
hasMoreEmails: result.hasMore,
|
hasMoreEmails: result.hasMore,
|
||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
isLoadingMore: false,
|
isLoadingMore: false,
|
||||||
@@ -1127,14 +1131,15 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
const existingIds = new Set(currentEmails.map(e => e.id));
|
const existingIds = new Set(currentEmails.map(e => e.id));
|
||||||
const newEmails = annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId).filter((e: Email) => !existingIds.has(e.id));
|
const newEmails = annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId).filter((e: Email) => !existingIds.has(e.id));
|
||||||
|
|
||||||
|
const enrichedNewEmails = await emailHooks.onEmailsFetched.transform(newEmails);
|
||||||
set({
|
set({
|
||||||
emails: [...currentEmails, ...newEmails],
|
emails: [...currentEmails, ...enrichedNewEmails],
|
||||||
hasMoreEmails: result.hasMore,
|
hasMoreEmails: result.hasMore,
|
||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
isLoadingMore: false
|
isLoadingMore: false
|
||||||
});
|
});
|
||||||
// Fetch full thread counts for newly loaded threads in the background
|
// Fetch full thread counts for newly loaded threads in the background
|
||||||
if (newEmails.length > 0) {
|
if (enrichedNewEmails.length > 0) {
|
||||||
void get().fetchThreadEmailCounts(client);
|
void get().fetchThreadEmailCounts(client);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -1754,60 +1759,66 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
searchEmails: async (client, query) => {
|
searchEmails: async (client, query) => {
|
||||||
set({ isLoading: true, error: null, searchQuery: query, emails: [], hasMoreEmails: false, totalEmails: 0 }); // Clear emails for loading state
|
set({ isLoading: true, error: null, searchQuery: query, emails: [], hasMoreEmails: false, totalEmails: 0 }); // Clear emails for loading state
|
||||||
try {
|
try {
|
||||||
const { isUnifiedView, unifiedRole, crossView } = get();
|
const { isUnifiedView, unifiedRole, crossView, selectedMailbox, searchFilters } = get();
|
||||||
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
||||||
|
|
||||||
|
let result;
|
||||||
|
let accountId;
|
||||||
|
let unifiedErrors;
|
||||||
|
|
||||||
if (isUnifiedView && crossView) {
|
if (isUnifiedView && crossView) {
|
||||||
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
||||||
const built = await buildUnifiedAccountClients({ includeGroup });
|
const built = await buildUnifiedAccountClients({ includeGroup });
|
||||||
const result = await searchCrossViewEmails(built, crossView, query, emailsPerPage, 0);
|
result = await searchCrossViewEmails(built, crossView, query, emailsPerPage, 0);
|
||||||
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], { query, filters: get().searchFilters });
|
unifiedErrors = result.errors;
|
||||||
set({
|
|
||||||
emails: result.emails,
|
|
||||||
externalSearchResults: externals,
|
|
||||||
hasMoreEmails: result.hasMore,
|
|
||||||
totalEmails: result.total,
|
|
||||||
isLoading: false,
|
|
||||||
unifiedErrors: result.errors,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUnifiedView && unifiedRole) {
|
} else if (isUnifiedView && unifiedRole) {
|
||||||
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
||||||
const built = await buildUnifiedAccountClients({ includeGroup });
|
const built = await buildUnifiedAccountClients({ includeGroup });
|
||||||
const result = await searchUnifiedEmails(built, unifiedRole, query, emailsPerPage, 0);
|
result = await searchUnifiedEmails(built, unifiedRole, query, emailsPerPage, 0);
|
||||||
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], { query, filters: get().searchFilters });
|
unifiedErrors = result.errors;
|
||||||
set({
|
|
||||||
emails: result.emails,
|
} else {
|
||||||
externalSearchResults: externals,
|
// Get the current mailbox to scope the search. In the All Mail view the
|
||||||
hasMoreEmails: result.hasMore,
|
// search spans every folder of the account (no inMailbox constraint).
|
||||||
totalEmails: result.total,
|
const isAllMail = selectedMailbox === ALL_MAIL_MAILBOX_ID;
|
||||||
isLoading: false,
|
const mailboxes = resolveActionMailboxes();
|
||||||
unifiedErrors: result.errors,
|
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox);
|
||||||
});
|
// Use originalId for shared mailboxes
|
||||||
return;
|
const jmapMailboxId = isAllMail ? undefined : (mailbox?.originalId || selectedMailbox);
|
||||||
|
// Only pass accountId for shared mailboxes, not for primary account
|
||||||
|
accountId = isAllMail ? undefined : (mailbox?.isShared ? mailbox.accountId : undefined);
|
||||||
|
|
||||||
|
result = await resolveActionClient(client).searchEmails(query, jmapMailboxId, accountId, emailsPerPage, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current mailbox to scope the search. In the All Mail view the
|
const hookEdit = await emailHooks.onSearchResults.transform({
|
||||||
// search spans every folder of the account (no inMailbox constraint).
|
newEmailIds: [] as string[],
|
||||||
const selectedMailbox = get().selectedMailbox;
|
result: result,
|
||||||
const isAllMail = selectedMailbox === ALL_MAIL_MAILBOX_ID;
|
query: query,
|
||||||
const mailboxes = resolveActionMailboxes();
|
filters: searchFilters
|
||||||
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox);
|
});
|
||||||
// Use originalId for shared mailboxes
|
|
||||||
const jmapMailboxId = isAllMail ? undefined : (mailbox?.originalId || selectedMailbox);
|
|
||||||
// Only pass accountId for shared mailboxes, not for primary account
|
|
||||||
const accountId = isAllMail ? undefined : (mailbox?.isShared ? mailbox.accountId : undefined);
|
|
||||||
|
|
||||||
const result = await resolveActionClient(client).searchEmails(query, jmapMailboxId, accountId, emailsPerPage, 0);
|
result = hookEdit.result;
|
||||||
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], { query, filters: get().searchFilters });
|
if (hookEdit.newEmailIds.length > 0) {
|
||||||
|
// in unified, accountId will be undefined and we will use the default.
|
||||||
|
const newEmails = await resolveActionClient(client).getSomeEmails(hookEdit.newEmailIds, accountId);
|
||||||
|
result.emails.push(...newEmails);
|
||||||
|
result.total += newEmails.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], {
|
||||||
|
query,
|
||||||
|
filters: searchFilters
|
||||||
|
});
|
||||||
|
result.emails = await emailHooks.onEmailsFetched.transform(result.emails);
|
||||||
set({
|
set({
|
||||||
emails: annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId),
|
emails: annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId),
|
||||||
externalSearchResults: externals,
|
externalSearchResults: externals,
|
||||||
hasMoreEmails: result.hasMore,
|
hasMoreEmails: result.hasMore,
|
||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
isLoading: false
|
isLoading: false,
|
||||||
|
...(unifiedErrors ? { unifiedErrors } : {})
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
set({
|
set({
|
||||||
@@ -1841,60 +1852,64 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
||||||
|
let result;
|
||||||
|
let accountId;
|
||||||
|
let unifiedErrors;
|
||||||
|
|
||||||
if (isUnifiedView && crossView) {
|
if (isUnifiedView && crossView) {
|
||||||
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
||||||
const built = await buildUnifiedAccountClients({ includeGroup });
|
const built = await buildUnifiedAccountClients({ includeGroup });
|
||||||
const result = await searchCrossViewEmails(built, crossView, searchQuery, emailsPerPage, 0);
|
result = await searchCrossViewEmails(built, crossView, searchQuery, emailsPerPage, 0);
|
||||||
if (controller.signal.aborted) return;
|
unifiedErrors = result.errors;
|
||||||
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], { query: searchQuery, filters: searchFilters });
|
|
||||||
set({
|
|
||||||
emails: result.emails,
|
|
||||||
externalSearchResults: externals,
|
|
||||||
hasMoreEmails: result.hasMore,
|
|
||||||
totalEmails: result.total,
|
|
||||||
isLoading: false,
|
|
||||||
unifiedErrors: result.errors,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUnifiedView && unifiedRole) {
|
} else if (isUnifiedView && unifiedRole) {
|
||||||
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
const includeGroup = useSettingsStore.getState().includeGroupInUnified;
|
||||||
const built = await buildUnifiedAccountClients({ includeGroup });
|
const built = await buildUnifiedAccountClients({ includeGroup });
|
||||||
const result = await advancedSearchUnifiedEmails(
|
result = await advancedSearchUnifiedEmails(
|
||||||
built,
|
built,
|
||||||
unifiedRole,
|
unifiedRole,
|
||||||
(mailboxId) => buildJMAPFilter(searchQuery, searchFilters, mailboxId),
|
(mailboxId) => buildJMAPFilter(searchQuery, searchFilters, mailboxId),
|
||||||
emailsPerPage,
|
emailsPerPage,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
if (controller.signal.aborted) return;
|
unifiedErrors = result.errors;
|
||||||
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], { query: searchQuery, filters: searchFilters });
|
|
||||||
set({
|
} else {
|
||||||
emails: result.emails,
|
const isAllMail = selectedMailbox === ALL_MAIL_MAILBOX_ID;
|
||||||
externalSearchResults: externals,
|
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox);
|
||||||
hasMoreEmails: result.hasMore,
|
const jmapMailboxId = isAllMail ? undefined : (mailbox?.originalId || selectedMailbox);
|
||||||
totalEmails: result.total,
|
accountId = isAllMail ? undefined : (mailbox?.isShared ? mailbox.accountId : undefined);
|
||||||
isLoading: false,
|
|
||||||
searchAbortController: null,
|
const filter = buildJMAPFilter(searchQuery, searchFilters, jmapMailboxId);
|
||||||
unifiedErrors: result.errors,
|
result = await resolveActionClient(client).advancedSearchEmails(filter, accountId, emailsPerPage, 0);
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAllMail = selectedMailbox === ALL_MAIL_MAILBOX_ID;
|
|
||||||
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox);
|
|
||||||
const jmapMailboxId = isAllMail ? undefined : (mailbox?.originalId || selectedMailbox);
|
|
||||||
const accountId = isAllMail ? undefined : (mailbox?.isShared ? mailbox.accountId : undefined);
|
|
||||||
|
|
||||||
const filter = buildJMAPFilter(searchQuery, searchFilters, jmapMailboxId);
|
|
||||||
const result = await resolveActionClient(client).advancedSearchEmails(filter, accountId, emailsPerPage, 0);
|
|
||||||
|
|
||||||
if (controller.signal.aborted) return;
|
if (controller.signal.aborted) return;
|
||||||
|
|
||||||
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], { query: searchQuery, filters: searchFilters });
|
const hookEdit = await emailHooks.onSearchResults.transform({
|
||||||
|
newEmailIds: [] as string[],
|
||||||
|
result: result,
|
||||||
|
query: searchQuery,
|
||||||
|
filters: searchFilters
|
||||||
|
});
|
||||||
|
|
||||||
|
result = hookEdit.result;
|
||||||
|
|
||||||
|
if (hookEdit.newEmailIds.length > 0) {
|
||||||
|
const newEmails = await resolveActionClient(client).getSomeEmails(hookEdit.newEmailIds, accountId);
|
||||||
|
result.emails.push(...newEmails);
|
||||||
|
result.total += newEmails.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (controller.signal.aborted) return;
|
||||||
|
|
||||||
|
const externals = await emailHooks.onProvideSearchResults.transform([] as ExternalSearchResult[], {
|
||||||
|
query: searchQuery,
|
||||||
|
filters: searchFilters
|
||||||
|
});
|
||||||
|
|
||||||
|
if (controller.signal.aborted) return;
|
||||||
|
result.emails = await emailHooks.onEmailsFetched.transform(result.emails);
|
||||||
set({
|
set({
|
||||||
emails: annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId),
|
emails: annotateScheduledEmails(result.emails, get().scheduledSubmissionByEmailId),
|
||||||
externalSearchResults: externals,
|
externalSearchResults: externals,
|
||||||
@@ -1902,6 +1917,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
totalEmails: result.total,
|
totalEmails: result.total,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
searchAbortController: null,
|
searchAbortController: null,
|
||||||
|
...(unifiedErrors ? { unifiedErrors } : {})
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (controller.signal.aborted) return;
|
if (controller.signal.aborted) return;
|
||||||
@@ -3284,6 +3300,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
try {
|
try {
|
||||||
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
||||||
const result = await client.getScheduledEmails(emailsPerPage, 0);
|
const result = await client.getScheduledEmails(emailsPerPage, 0);
|
||||||
|
result.emails = await emailHooks.onEmailsFetched.transform(result.emails);
|
||||||
const scheduledEmailIds = new Set(result.emails.map(email => email.id));
|
const scheduledEmailIds = new Set(result.emails.map(email => email.id));
|
||||||
const scheduledSubmissionByEmailId = new Map(result.emails.map(email => [email.id, {
|
const scheduledSubmissionByEmailId = new Map(result.emails.map(email => [email.id, {
|
||||||
submissionId: email.emailSubmissionId,
|
submissionId: email.emailSubmissionId,
|
||||||
@@ -3324,6 +3341,7 @@ export const useEmailStore = create<EmailStore>((set, get) => ({
|
|||||||
try {
|
try {
|
||||||
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
const emailsPerPage = useSettingsStore.getState().emailsPerPage;
|
||||||
const result = await client.getScheduledEmails(emailsPerPage, scheduledNextPosition);
|
const result = await client.getScheduledEmails(emailsPerPage, scheduledNextPosition);
|
||||||
|
result.emails = await emailHooks.onEmailsFetched.transform(result.emails);
|
||||||
const merged = [...scheduledEmails, ...result.emails.filter(email => !scheduledEmails.some(existing => existing.id === email.id))];
|
const merged = [...scheduledEmails, ...result.emails.filter(email => !scheduledEmails.some(existing => existing.id === email.id))];
|
||||||
const pendingUndoSend = get().pendingUndoSend;
|
const pendingUndoSend = get().pendingUndoSend;
|
||||||
set({
|
set({
|
||||||
|
|||||||
Reference in New Issue
Block a user