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