diff --git a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js index 392a526..a638da6 100644 --- a/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js +++ b/containers/libreportal/frontend/components/apps/overview/js/overview-manager.js @@ -306,6 +306,7 @@ class OverviewManager { case 'update': this.updater.applyUpdate(app); break; case 'update-all': this.updater.applyAll(); break; case 'rollback': this.updater.rollback(app); break; + case 'upgrade': this.updater.upgrade(app, ua.dataset.version); break; case 'apply-artifact': this.updater.applyArtifact(ua.dataset.id); break; case 'revert-artifact': this.updater.revertArtifact(ua.dataset.id); break; } diff --git a/containers/libreportal/frontend/components/tasks/js/tasks-format.js b/containers/libreportal/frontend/components/tasks/js/tasks-format.js index 6520cb7..04996a8 100644 --- a/containers/libreportal/frontend/components/tasks/js/tasks-format.js +++ b/containers/libreportal/frontend/components/tasks/js/tasks-format.js @@ -145,6 +145,7 @@ Object.assign(TasksManager.prototype, { 'system_health_heal': 'Fix System Issues', 'system_network_heal': 'Heal Network', 'updater_check': 'Check for Updates', 'updater_apply': 'Update', 'updater_apply_all': 'Update All', 'updater_rollback': 'Roll Back', + 'updater_upgrade': 'Upgrade Version', 'artifact_apply': 'Apply Hotfix', 'artifact_revert': 'Revert Hotfix', 'app_add': 'Add App', 'setup-config': 'Apply Configuration', diff --git a/containers/libreportal/frontend/components/tasks/js/tasks-list-render.js b/containers/libreportal/frontend/components/tasks/js/tasks-list-render.js index 7980263..1166ca6 100644 --- a/containers/libreportal/frontend/components/tasks/js/tasks-list-render.js +++ b/containers/libreportal/frontend/components/tasks/js/tasks-list-render.js @@ -328,6 +328,7 @@ Object.assign(TasksManager.prototype, { 'updater_apply': { icon: '⬆️', class: 'update' }, 'updater_apply_all': { icon: '⬆️', class: 'update' }, 'updater_rollback': { icon: '↩️', class: 'restore' }, + 'updater_upgrade': { icon: '⏫', class: 'update' }, 'artifact_apply': { icon: '⚡', class: 'update' }, 'artifact_revert': { icon: '↩️', class: 'restore' }, 'custom': { icon: '⚙️', class: 'custom' } diff --git a/containers/libreportal/frontend/components/updater/js/updater-page.js b/containers/libreportal/frontend/components/updater/js/updater-page.js index f7837ea..ffe1ad3 100644 --- a/containers/libreportal/frontend/components/updater/js/updater-page.js +++ b/containers/libreportal/frontend/components/updater/js/updater-page.js @@ -109,6 +109,7 @@ class UpdaterPage { case 'update': this.applyUpdate(app); break; case 'update-all': this.applyAll(); break; case 'rollback': this.rollback(app); break; + case 'upgrade': this.upgrade(app, action.dataset.version); break; case 'apply-artifact': this.applyArtifact(action.dataset.id); break; case 'revert-artifact': this.revertArtifact(action.dataset.id); break; case 'goto': this.switchTab(action.dataset.tab); break; @@ -301,6 +302,33 @@ class UpdaterPage { if (!app) return; this.dispatch('updater_rollback', { app }, `Rolling ${app} back to its pre-update snapshot…`); } + // Cross-version upgrade. Always confirmed, and never quietly: this walks + // real migrations one release at a time and can take a long while, so the + // dialog states the plan and the guarantee rather than asking "are you sure?". + upgrade(app, version) { + if (!app) return; + const a = this.apps.find((x) => x.name === app) || {}; + const from = a.channel || a.current_version || 'the current version'; + const to = version || a.newer_version || 'the newest release'; + const body = ` +
${this.escape(app)} will move from ${this.escape(from)} + to ${this.escape(to)}, one release at a time.
+ + +