diff --git a/extension/chrome/elements/compose-modules/compose-input-module.ts b/extension/chrome/elements/compose-modules/compose-input-module.ts index 93c5dbeea34..d3f2b7b4750 100644 --- a/extension/chrome/elements/compose-modules/compose-input-module.ts +++ b/extension/chrome/elements/compose-modules/compose-input-module.ts @@ -54,7 +54,9 @@ export class ComposeInputModule extends ViewModule { }; public removeRichTextFormatting = () => { - this.initSquire(false, true); + if (this.view.inputModule.isRichText()) { + this.initSquire(false, true); + } }; public inputTextHtmlSetSafely = (html: string) => { diff --git a/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts b/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts index 78dc5cd9ddb..bea9023fcc8 100644 --- a/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts +++ b/extension/chrome/settings/inbox/inbox-modules/inbox-list-threads-module.ts @@ -7,7 +7,7 @@ import { Catch } from '../../../../js/common/platform/catch.js'; import { GmailParser } from '../../../../js/common/api/email-provider/gmail/gmail-parser.js'; import { InboxView } from '../inbox.js'; import { Lang } from '../../../../js/common/lang.js'; -import { Str } from '../../../../js/common/core/common.js'; +import { Str, promiseAllWithLimit } from '../../../../js/common/core/common.js'; import { Ui } from '../../../../js/common/browser/ui.js'; import { ViewModule } from '../../../../js/common/view-module.js'; import { Xss } from '../../../../js/common/platform/xss.js'; @@ -18,7 +18,10 @@ export class InboxListThreadsModule extends ViewModule { try { const { threads } = await this.view.gmail.threadList(labelId); if (threads?.length) { - await Promise.all(threads.map(t => this.renderInboxItem(t.id))); + await promiseAllWithLimit( + 30, + threads.map(t => () => this.renderInboxItem(t.id)) + ); } else { Xss.sanitizeRender('.threads', `

No encrypted messages in ${Xss.escape(labelId)} yet. ${Ui.retryLink()}

`); } @@ -39,7 +42,7 @@ export class InboxListThreadsModule extends ViewModule { } }; - private renderInboxItem = async (threadId: string) => { + private renderInboxItem = async (threadId: string): Promise => { this.inboxThreadItemAdd(threadId); const threadItem = $('.threads #' + this.threadListItemId(threadId)); try { diff --git a/extension/js/common/api/email-provider/gmail/gmail.ts b/extension/js/common/api/email-provider/gmail/gmail.ts index 7d70241f58b..8d4949d5bf7 100644 --- a/extension/js/common/api/email-provider/gmail/gmail.ts +++ b/extension/js/common/api/email-provider/gmail/gmail.ts @@ -4,7 +4,7 @@ import { AddrParserResult, BrowserWindow } from '../../../browser/browser-window.js'; import { ChunkedCb, ProgressCb, EmailProviderContact } from '../../shared/api.js'; -import { Dict, Str, Value } from '../../../core/common.js'; +import { Dict, Str, Value, promiseAllWithLimit } from '../../../core/common.js'; import { EmailProviderApi, EmailProviderInterface, Backups } from '../email-provider-api.js'; import { GMAIL_GOOGLE_API_HOST, gmailBackupSearchQuery } from '../../../core/const.js'; import { GmailParser, GmailRes } from './gmail-parser.js'; @@ -136,7 +136,10 @@ export class Gmail extends EmailProviderApi implements EmailProviderInterface { }; public msgsGet = async (msgIds: string[], format: GmailResponseFormat): Promise => { - return await Promise.all(msgIds.map(id => this.msgGet(id, format))); + return await promiseAllWithLimit( + 30, + msgIds.map(id => () => this.msgGet(id, format)) + ); }; public labelsGet = async (): Promise => { diff --git a/extension/js/common/core/common.ts b/extension/js/common/core/common.ts index fab1cbb39a8..8c63bcc582d 100644 --- a/extension/js/common/core/common.ts +++ b/extension/js/common/core/common.ts @@ -517,3 +517,20 @@ export const checkValidURL = (url: string): boolean => { const pattern = /(http|https):\/\/([a-z0-9-]+((\.[a-z0-9-]+)+)?)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@\-\/]))?/; return pattern.test(url); }; + +/** + * Executes multiple promises concurrently with a limit to the number of promises running simultaneously. + * Resolves when all promises are resolved or rejects when any promise is rejected. + * + * @param concurrency - The maximum number of promises to run at the same time. + * @param tasks - An array of functions that return promises. + * @returns A Promise that resolves to an array of the resolved values of the input promises. + */ +export const promiseAllWithLimit = async (concurrency: number, tasks: (() => Promise)[]): Promise => { + let results: V[] = []; + while (tasks.length) { + const currentTasks = tasks.splice(0, concurrency).map(task => task()); + results = results.concat(await Promise.all(currentTasks)); + } + return results; +}; diff --git a/extension/js/common/core/crypto/pgp/openpgp-key.ts b/extension/js/common/core/crypto/pgp/openpgp-key.ts index d6cce086b1c..098f1591e0d 100644 --- a/extension/js/common/core/crypto/pgp/openpgp-key.ts +++ b/extension/js/common/core/crypto/pgp/openpgp-key.ts @@ -268,6 +268,7 @@ export class OpenPGPKey { const message = await opgp.createMessage({ text }); return await opgp.sign({ message, format: 'armored', signingKeys: [signingPrv], detached }); } + text = text ? text : '\n'; const message = await opgp.createCleartextMessage({ text }); return await opgp.sign({ message, signingKeys: [signingPrv] }); }