Update extension manager to use new popup

This commit is contained in:
Cohee 2024-06-25 11:54:59 +03:00
parent 0e0bd0d3d9
commit 6b716980be
3 changed files with 35 additions and 11 deletions

View File

@ -36,7 +36,9 @@ label[for="extensions_autoconnect"] {
.extensions_info { .extensions_info {
text-align: left; text-align: left;
margin: 0 1em; max-height: 100%;
overflow-y: auto;
padding-right: 1em;
} }
.extensions_info h3 { .extensions_info h3 {

View File

@ -1,5 +1,6 @@
import { callPopup, eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js'; import { eventSource, event_types, saveSettings, saveSettingsDebounced, getRequestHeaders, animation_duration } from '../script.js';
import { hideLoader, showLoader } from './loader.js'; import { hideLoader, showLoader } from './loader.js';
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
import { renderTemplate, renderTemplateAsync } from './templates.js'; import { renderTemplate, renderTemplateAsync } from './templates.js';
import { isSubsetOf, setValueByPath } from './utils.js'; import { isSubsetOf, setValueByPath } from './utils.js';
export { export {
@ -631,7 +632,18 @@ async function showExtensionsDetails() {
${htmlDefault} ${htmlDefault}
${htmlExternal} ${htmlExternal}
`; `;
popupPromise = callPopup(`<div class="extensions_info">${html}</div>`, 'text', '', { okButton: 'Close', wide: true, large: true }); /** @type {import('./popup.js').CustomPopupButton} */
const updateAllButton = {
text: 'Update all',
appendAtEnd: true,
action: async () => {
requiresReload = true;
await autoUpdateExtensions(true);
popup.complete(POPUP_RESULT.AFFIRMATIVE);
},
};
const popup = new Popup(`<div class="extensions_info">${html}</div>`, POPUP_TYPE.TEXT, '', { okButton: 'Close', wide: true, large: true, customButtons: [updateAllButton] });
popupPromise = popup.show();
} catch (error) { } catch (error) {
toastr.error('Error loading extensions. See browser console for details.'); toastr.error('Error loading extensions. See browser console for details.');
console.error(error); console.error(error);
@ -700,8 +712,8 @@ async function updateExtension(extensionName, quiet) {
async function onDeleteClick() { async function onDeleteClick() {
const extensionName = $(this).data('name'); const extensionName = $(this).data('name');
// use callPopup to create a popup for the user to confirm before delete // use callPopup to create a popup for the user to confirm before delete
const confirmation = await callPopup(`Are you sure you want to delete ${extensionName}?`, 'delete_extension'); const confirmation = await callGenericPopup(`Are you sure you want to delete ${extensionName}?`, POPUP_TYPE.CONFIRM, '', {});
if (confirmation) { if (confirmation === POPUP_RESULT.AFFIRMATIVE) {
await deleteExtension(extensionName); await deleteExtension(extensionName);
} }
} }
@ -797,7 +809,7 @@ async function loadExtensionSettings(settings, versionChanged) {
manifests = await getManifests(extensionNames); manifests = await getManifests(extensionNames);
if (versionChanged) { if (versionChanged) {
await autoUpdateExtensions(); await autoUpdateExtensions(false);
} }
await activateExtensions(); await activateExtensions();
@ -860,7 +872,12 @@ async function checkForExtensionUpdates(force) {
} }
} }
async function autoUpdateExtensions() { /**
* Updates all 3rd-party extensions that have auto-update enabled.
* @param {boolean} forceAll Force update all even if not auto-updating
* @returns {Promise<void>}
*/
async function autoUpdateExtensions(forceAll) {
if (!Object.values(manifests).some(x => x.auto_update)) { if (!Object.values(manifests).some(x => x.auto_update)) {
return; return;
} }
@ -868,7 +885,7 @@ async function autoUpdateExtensions() {
const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 }); const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 });
const promises = []; const promises = [];
for (const [id, manifest] of Object.entries(manifests)) { for (const [id, manifest] of Object.entries(manifests)) {
if (manifest.auto_update && id.startsWith('third-party')) { if ((forceAll || manifest.auto_update) && id.startsWith('third-party')) {
console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`); console.debug(`Auto-updating 3rd-party extension: ${manifest.display_name} (${id})`);
promises.push(updateExtension(id.replace('third-party', ''), true)); promises.push(updateExtension(id.replace('third-party', ''), true));
} }
@ -988,14 +1005,14 @@ jQuery(async function () {
<p><b>Disclaimer:</b> Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.</p> <p><b>Disclaimer:</b> Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.</p>
<br> <br>
<p>Example: <tt> https://github.com/author/extension-name </tt></p>`; <p>Example: <tt> https://github.com/author/extension-name </tt></p>`;
const input = await callPopup(html, 'input'); const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '');
if (!input) { if (!input) {
console.debug('Extension install cancelled'); console.debug('Extension install cancelled');
return; return;
} }
const url = input.trim(); const url = String(input).trim();
await installExtension(url); await installExtension(url);
}); });
}); });

View File

@ -46,7 +46,7 @@ export const POPUP_RESULT = {
/** /**
* @typedef {object} CustomPopupButton * @typedef {object} CustomPopupButton
* @property {string} text - The text of the button * @property {string} text - The text of the button
* @property {POPUP_RESULT|number?} result - The result of the button - can also be a custom result value to make be able to find out that this button was clicked. If no result is specified, this button will **not** close the popup. * @property {POPUP_RESULT|number?} [result] - The result of the button - can also be a custom result value to make be able to find out that this button was clicked. If no result is specified, this button will **not** close the popup.
* @property {string[]|string?} [classes] - Optional custom CSS classes applied to the button * @property {string[]|string?} [classes] - Optional custom CSS classes applied to the button
* @property {()=>void?} [action] - Optional action to perform when the button is clicked * @property {()=>void?} [action] - Optional action to perform when the button is clicked
* @property {boolean?} [appendAtEnd] - Whether to append the button to the end of the popup - by default it will be prepended * @property {boolean?} [appendAtEnd] - Whether to append the button to the end of the popup - by default it will be prepended
@ -169,6 +169,10 @@ export class Popup {
} else { } else {
this.controls.insertBefore(buttonElement, this.okButton); this.controls.insertBefore(buttonElement, this.okButton);
} }
if (typeof button.action === 'function') {
buttonElement.addEventListener('click', button.action);
}
}); });
// Set the default button class // Set the default button class
@ -247,6 +251,7 @@ export class Popup {
this.dlg.querySelectorAll('[data-result]').forEach(resultControl => { this.dlg.querySelectorAll('[data-result]').forEach(resultControl => {
if (!(resultControl instanceof HTMLElement)) return; if (!(resultControl instanceof HTMLElement)) return;
const result = Number(resultControl.dataset.result); const result = Number(resultControl.dataset.result);
if (String(undefined) === String(resultControl.dataset.result)) return;
if (isNaN(result)) throw new Error('Invalid result control. Result must be a number. ' + resultControl.dataset.result); if (isNaN(result)) throw new Error('Invalid result control. Result must be a number. ' + resultControl.dataset.result);
const type = resultControl.dataset.resultEvent || 'click'; const type = resultControl.dataset.resultEvent || 'click';
resultControl.addEventListener(type, () => this.complete(result)); resultControl.addEventListener(type, () => this.complete(result));