Batch extension version checks
| @@ -586,7 +586,6 @@ function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, | |||
| 586 | const isUserAdmin = isAdmin(); | 586 | const isUserAdmin = isAdmin(); |
| 587 | const extensionIcon = getExtensionIcon(); | 587 | const extensionIcon = getExtensionIcon(); |
| 588 | const displayName = manifest.display_name; | 588 | const displayName = manifest.display_name; |
| 589 | let displayVersion = manifest.version ? ` v${manifest.version}` : ''; | ||
| 590 | const externalId = name.replace('third-party', ''); | 589 | const externalId = name.replace('third-party', ''); |
| 591 | let originHtml = ''; | 590 | let originHtml = ''; |
| 592 | if (isExternal) { | 591 | if (isExternal) { |
| @@ -632,7 +631,7 @@ function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal, | |||
| 632 | ${originHtml} | 631 | ${originHtml} |
| 633 | <span class="${isActive ? 'extension_enabled' : isDisabled ? 'extension_disabled' : 'extension_missing'}"> | 632 | <span class="${isActive ? 'extension_enabled' : isDisabled ? 'extension_disabled' : 'extension_missing'}"> |
| 634 | <span class="extension_name">${DOMPurify.sanitize(displayName)}</span> | 633 | <span class="extension_name">${DOMPurify.sanitize(displayName)}</span> |
| 635 | <span class="extension_version">${displayVersion}</span> | 634 | <span class="extension_version"></span> |
| 636 | ${modulesInfo} | 635 | ${modulesInfo} |
| 637 | </span> | 636 | </span> |
| 638 | ${isExternal ? '</a>' : ''} | 637 | ${isExternal ? '</a>' : ''} |
| @@ -1032,6 +1031,29 @@ export function doDailyExtensionUpdatesCheck() { | |||
| 1032 | }, 1); | 1031 | }, 1); |
| 1033 | } | 1032 | } |
| 1034 | 1033 | ||
| 1034 | const concurrencyLimit = 5; | ||
| 1035 | let activeRequestsCount = 0; | ||
| 1036 | const versionCheckQueue = []; | ||
| 1037 | |||
| 1038 | function enqueueVersionCheck(fn) { | ||
| 1039 | return new Promise((resolve, reject) => { | ||
| 1040 | versionCheckQueue.push(() => fn().then(resolve).catch(reject)); | ||
| 1041 | processVersionCheckQueue(); | ||
| 1042 | }); | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | function processVersionCheckQueue() { | ||
| 1046 | if (activeRequestsCount >= concurrencyLimit || versionCheckQueue.length === 0) { | ||
| 1047 | return; | ||
| 1048 | } | ||
| 1049 | activeRequestsCount++; | ||
| 1050 | const fn = versionCheckQueue.shift(); | ||
| 1051 | fn().finally(() => { | ||
| 1052 | activeRequestsCount--; | ||
| 1053 | processVersionCheckQueue(); | ||
| 1054 | }); | ||
| 1055 | } | ||
| 1056 | |||
| 1035 | /** | 1057 | /** |
| 1036 | * Performs a manual check for updates on all 3rd-party extensions. | 1058 | * Performs a manual check for updates on all 3rd-party extensions. |
| 1037 | * @param {AbortSignal} abortSignal Signal to abort the operation | 1059 | * @param {AbortSignal} abortSignal Signal to abort the operation |
| @@ -1041,7 +1063,7 @@ async function checkForUpdatesManual(abortSignal) { | |||
| 1041 | const promises = []; | 1063 | const promises = []; |
| 1042 | for (const id of Object.keys(manifests).filter(x => x.startsWith('third-party'))) { | 1064 | for (const id of Object.keys(manifests).filter(x => x.startsWith('third-party'))) { |
| 1043 | const externalId = id.replace('third-party', ''); | 1065 | const externalId = id.replace('third-party', ''); |
| 1044 | const promise = new Promise(async (resolve, reject) => { | 1066 | const promise = enqueueVersionCheck(async () => { |
| 1045 | try { | 1067 | try { |
| 1046 | const data = await getExtensionVersion(externalId, abortSignal); | 1068 | const data = await getExtensionVersion(externalId, abortSignal); |
| 1047 | const extensionBlock = document.querySelector(`.extension_block[data-name="${externalId}"]`); | 1069 | const extensionBlock = document.querySelector(`.extension_block[data-name="${externalId}"]`); |
| @@ -1072,10 +1094,8 @@ async function checkForUpdatesManual(abortSignal) { | |||
| 1072 | versionElement.textContent += ` (${branch}-${commitHash.substring(0, 7)})`; | 1094 | versionElement.textContent += ` (${branch}-${commitHash.substring(0, 7)})`; |
| 1073 | } | 1095 | } |
| 1074 | } | 1096 | } |
| 1075 | resolve(); | ||
| 1076 | } catch (error) { | 1097 | } catch (error) { |
| 1077 | console.error('Error checking for extension updates', error); | 1098 | console.error('Error checking for extension updates', error); |
| 1078 | reject(); | ||
| 1079 | } | 1099 | } |
| 1080 | }); | 1100 | }); |
| 1081 | promises.push(promise); | 1101 | promises.push(promise); |
| @@ -1111,17 +1131,16 @@ async function checkForExtensionUpdates(force) { | |||
| 1111 | console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`); | 1131 | console.debug(`Skipping global extension: ${manifest.display_name} (${id}) for non-admin user`); |
| 1112 | continue; | 1132 | continue; |
| 1113 | } | 1133 | } |
| 1134 | |||
| 1114 | if (manifest.auto_update && id.startsWith('third-party')) { | 1135 | if (manifest.auto_update && id.startsWith('third-party')) { |
| 1115 | const promise = new Promise(async (resolve, reject) => { | 1136 | const promise = enqueueVersionCheck(async () => { |
| 1116 | try { | 1137 | try { |
| 1117 | const data = await getExtensionVersion(id.replace('third-party', '')); | 1138 | const data = await getExtensionVersion(id.replace('third-party', '')); |
| 1118 | if (data.isUpToDate === false) { | 1139 | if (!data.isUpToDate) { |
| 1119 | updatesAvailable.push(manifest.display_name); | 1140 | updatesAvailable.push(manifest.display_name); |
| 1120 | } | 1141 | } |
| 1121 | resolve(); | ||
| 1122 | } catch (error) { | 1142 | } catch (error) { |
| 1123 | console.error('Error checking for extension updates', error); | 1143 | console.error('Error checking for extension updates', error); |
| 1124 | reject(); | ||
| 1125 | } | 1144 | } |
| 1126 | }); | 1145 | }); |
| 1127 | promises.push(promise); | 1146 | promises.push(promise); |