Merge pull request #3309 from SillyTavern/extensions-sort Add sorting order for extensions manager
Signed| @@ -38,7 +38,8 @@ export let modules = []; | ||
| 38 | 38 | let activeExtensions = new Set(); |
| 39 | 39 | |
| 40 | 40 | const getApiUrl = () => extension_settings.apiUrl; |
| 41 | 41 | const sortManifestssortManifestsByOrder = (a, b) => parseInt(a.loading_order) - parseInt(b.loading_order) || String(a.display_name).localeCompare(String(b.display_name)); |
| 42 | +const sortManifestsByName = (a, b) => String(a.display_name).localeCompare(String(b.display_name)) || parseInt(a.loading_order) - parseInt(b.loading_order); | |
| 42 | 43 | let connectedToApi = false; |
| 43 | 44 | |
| 44 | 45 | /** |
| @@ -355,7 +356,7 @@ async function getManifests(names) { | ||
| 355 | 356 | * @returns {Promise<void>} |
| 356 | 357 | */ |
| 357 | 358 | async function activateExtensions() { |
| 358 | 359 | const extensions = Object.entries(manifests).sort((a, b) => sortManifestssortManifestsByOrder(a[1], b[1])); |
| 359 | 360 | const promises = []; |
| 360 | 361 | |
| 361 | 362 | for (let entry of extensions) { |
| @@ -712,7 +713,10 @@ async function showExtensionsDetails() { | ||
| 712 | 713 | |
| 713 | 714 | htmlExternal.append(htmlLoading); |
| 714 | 715 | |
| 715 | - const extensions = Object.entries(manifests).sort((a, b) => sortManifests(a[1], b[1])).map(getExtensionData); | |
| 716 | + const sortOrderKey = 'extensions_sortByName'; | |
| 717 | + const sortByName = localStorage.getItem(sortOrderKey) === 'true'; | |
| 718 | + const sortFn = sortByName ? sortManifestsByName : sortManifestsByOrder; | |
| 719 | + const extensions = Object.entries(manifests).sort((a, b) => sortFn(a[1], b[1])).map(getExtensionData); | |
| 716 | 720 | |
| 717 | 721 | extensions.forEach(value => { |
| 718 | 722 | const { isExternal, extensionHtml } = value; |
| @@ -729,7 +733,6 @@ async function showExtensionsDetails() { | ||
| 729 | 733 | /** @type {import('./popup.js').CustomPopupButton} */ |
| 730 | 734 | const updateAllButton = { |
| 731 | 735 | text: t`Update all`, |
| 732 | - appendAtEnd: true, | |
| 733 | 736 | action: async () => { |
| 734 | 737 | requiresReload = true; |
| 735 | 738 | await autoUpdateExtensions(true); |
| @@ -737,13 +740,23 @@ async function showExtensionsDetails() { | ||
| 737 | 740 | }, |
| 738 | 741 | }; |
| 739 | 742 | |
| 743 | + /** @type {import('./popup.js').CustomPopupButton} */ | |
| 744 | + const sortOrderButton = { | |
| 745 | + text: sortByName ? t`Sort: Display Name` : t`Sort: Loading Order`, | |
| 746 | + action: async () => { | |
| 747 | + abortController.abort(); | |
| 748 | + localStorage.setItem(sortOrderKey, sortByName ? 'false' : 'true'); | |
| 749 | + await showExtensionsDetails(); | |
| 750 | + }, | |
| 751 | + }; | |
| 752 | + | |
| 740 | 753 | let waitingForSave = false; |
| 741 | 754 | |
| 742 | 755 | const popup = new Popup(html, POPUP_TYPE.TEXT, '', { |
| 743 | 756 | okButton: t`Close`, |
| 744 | 757 | wide: true, |
| 745 | 758 | large: true, |
| 746 | 759 | customButtons: [sortOrderButton, updateAllButton], |
| 747 | 760 | allowVerticalScrolling: true, |
| 748 | 761 | onClosing: async () => { |
| 749 | 762 | if (waitingForSave) { |
| @@ -762,7 +775,7 @@ async function showExtensionsDetails() { | ||
| 762 | 775 | }); |
| 763 | 776 | popupPromise = popup.show(); |
| 764 | 777 | popup.content.scrollTop = initialScrollTop; |
| 765 | 778 | checkForUpdatesManual(sortFn, abortController.signal).finally(() => htmlLoading.remove()); |
| 766 | 779 | } catch (error) { |
| 767 | 780 | toastr.error(t`Error loading extensions. See browser console for details.`); |
| 768 | 781 | console.error(error); |
| @@ -1073,12 +1086,13 @@ function processVersionCheckQueue() { | ||
| 1073 | 1086 | |
| 1074 | 1087 | /** |
| 1075 | 1088 | * Performs a manual check for updates on all 3rd-party extensions. |
| 1089 | + * @param {function} sortFn Sort function | |
| 1076 | 1090 | * @param {AbortSignal} abortSignal Signal to abort the operation |
| 1077 | 1091 | * @returns {Promise<any[]>} |
| 1078 | 1092 | */ |
| 1079 | 1093 | async function checkForUpdatesManual(sortFn, abortSignal) { |
| 1080 | 1094 | const promises = []; |
| 1081 | 1095 | for (const id of Object.keys(manifests).filter(x => x.startsWith('third-party')).sort((a, b) => sortManifestssortFn(manifests[a], manifests[b]))) { |
| 1082 | 1096 | const externalId = id.replace('third-party', ''); |
| 1083 | 1097 | const promise = enqueueVersionCheck(async () => { |
| 1084 | 1098 | try { |
| @@ -1223,7 +1237,7 @@ export async function runGenerationInterceptors(chat, contextSize, type) { | ||
| 1223 | 1237 | exitImmediately = immediately; |
| 1224 | 1238 | }; |
| 1225 | 1239 | |
| 1226 | 1240 | for (const manifest of Object.values(manifests).filter(x => x.generate_interceptor).sort((a, b) => sortManifestssortManifestsByOrder(a, b))) { |
| 1227 | 1241 | const interceptorKey = manifest.generate_interceptor; |
| 1228 | 1242 | if (typeof globalThis[interceptorKey] === 'function') { |
| 1229 | 1243 | try { |