improved safe upgrade modal

This commit is contained in:
Andy Miller
2025-10-17 22:15:39 -06:00
parent c24c13716b
commit 7bb6044e05
4 changed files with 95 additions and 24 deletions

View File

@@ -532,6 +532,7 @@ PLUGIN_ADMIN:
SAFE_UPGRADE_BLOCKERS_TITLE: "Action required before continuing"
SAFE_UPGRADE_BLOCKERS_DESC: "Resolve the following items to enable the upgrade."
SAFE_UPGRADE_START: "Start Safe Upgrade"
SAFE_UPGRADE_FINISH: "Finish"
SAFE_UPGRADE_STAGE_INITIALIZING: "Preparing upgrade"
SAFE_UPGRADE_STAGE_DOWNLOADING: "Downloading update"
SAFE_UPGRADE_STAGE_INSTALLING: "Installing update"

View File

@@ -43,7 +43,8 @@ export default class SafeUpgrade {
this.buttons = {
start: this.modalElement.find('[data-safe-upgrade-action="start"]'),
cancel: this.modalElement.find('[data-safe-upgrade-action="cancel"]'),
recheck: this.modalElement.find('[data-safe-upgrade-action="recheck"]')
recheck: this.modalElement.find('[data-safe-upgrade-action="recheck"]'),
finish: this.modalElement.find('[data-safe-upgrade-action="finish"]')
};
this.urls = this.buildUrls();
@@ -60,6 +61,7 @@ export default class SafeUpgrade {
this.stageEnteredAt = 0;
this.directStatusUrl = this.resolveDirectStatusUrl();
this.preferDirectStatus = !!this.directStatusUrl;
this.modalLocked = false;
this.registerEvents();
}
@@ -106,6 +108,17 @@ export default class SafeUpgrade {
this.startUpgrade();
});
this.modalElement.on('click', '[data-safe-upgrade-action="finish"]', (event) => {
event.preventDefault();
const button = $(event.currentTarget);
if (button.prop('disabled')) {
return;
}
this.modalLocked = false;
this.modal.close('finish');
setTimeout(() => window.location.reload(), 75);
});
this.modalElement.on('change', '[data-safe-upgrade-decision]', (event) => {
const target = $(event.currentTarget);
const decision = target.val();
@@ -113,6 +126,12 @@ export default class SafeUpgrade {
this.decisions[type] = decision;
this.updateStartButtonState();
});
this.modalElement.on('closing', (event) => {
if (this.modalLocked && event.reason !== 'finish') {
event.preventDefault();
}
});
}
setPayload(payload = {}) {
@@ -128,12 +147,15 @@ export default class SafeUpgrade {
this.statusIdleCount = 0;
this.currentStage = null;
this.stageEnteredAt = 0;
this.modalLocked = false;
this.renderLoading();
this.modal.open();
this.fetchPreflight();
}
renderLoading() {
this.modalLocked = false;
this.resetFooterButtons();
this.switchStep('preflight');
this.steps.preflight.html(`
<div class="safe-upgrade-loading">
@@ -484,6 +506,8 @@ export default class SafeUpgrade {
});
this.buttons.start.prop('disabled', true);
this.buttons.finish.addClass('hidden').prop('disabled', true);
this.modalLocked = false;
this.stopPolling();
this.jobId = null;
@@ -537,9 +561,6 @@ export default class SafeUpgrade {
target_version: data.version || (data.manifest && data.manifest.target_version) || null,
manifest: data.manifest || null
});
if (data.status === 'success') {
setTimeout(() => window.location.reload(), 2500);
}
return;
}
@@ -646,7 +667,6 @@ export default class SafeUpgrade {
let nextStage = null;
let jobComplete = false;
let jobFailed = false;
let shouldReload = false;
let handled = false;
let lastPayload = null;
@@ -721,10 +741,8 @@ export default class SafeUpgrade {
nextStage = 'complete';
}
jobComplete = true;
shouldReload = true;
} else if (!job.status && data.stage === 'complete') {
jobComplete = true;
shouldReload = true;
}
});
@@ -756,9 +774,6 @@ export default class SafeUpgrade {
} else if (jobComplete || nextStage === 'complete') {
this.stopPolling();
this.jobId = null;
if (shouldReload) {
setTimeout(() => window.location.reload(), 2500);
}
} else {
this.schedulePoll();
}
@@ -863,6 +878,8 @@ export default class SafeUpgrade {
if (this.updates) {
this.updates.fetch(true);
}
this.prepareCompletionFooter();
} else if (status === 'noop') {
this.steps.result.html(`
<div class="safe-upgrade-result neutral">
@@ -870,6 +887,7 @@ export default class SafeUpgrade {
</div>
`);
this.switchStep('result');
this.prepareCompletionFooter();
} else {
this.steps.result.html(`
<div class="safe-upgrade-result error">
@@ -878,6 +896,10 @@ export default class SafeUpgrade {
</div>
`);
this.switchStep('result');
this.modalLocked = false;
this.buttons.finish.addClass('hidden').prop('disabled', true);
this.buttons.cancel.removeClass('hidden').prop('disabled', false);
this.buttons.recheck.removeClass('hidden').prop('disabled', false);
}
}
@@ -889,6 +911,20 @@ export default class SafeUpgrade {
});
}
resetFooterButtons() {
this.buttons.cancel.removeClass('hidden').prop('disabled', false);
this.buttons.recheck.removeClass('hidden').prop('disabled', false);
this.buttons.finish.addClass('hidden').prop('disabled', true);
}
prepareCompletionFooter() {
this.modalLocked = true;
this.buttons.cancel.addClass('hidden').prop('disabled', true);
this.buttons.recheck.addClass('hidden').prop('disabled', true);
this.buttons.start.addClass('hidden').prop('disabled', true);
this.buttons.finish.removeClass('hidden').prop('disabled', false);
}
stopPolling() {
this.isPolling = false;
this.clearPollTimer();

View File

@@ -4611,7 +4611,8 @@ var SafeUpgrade = /*#__PURE__*/function () {
this.buttons = {
start: this.modalElement.find('[data-safe-upgrade-action="start"]'),
cancel: this.modalElement.find('[data-safe-upgrade-action="cancel"]'),
recheck: this.modalElement.find('[data-safe-upgrade-action="recheck"]')
recheck: this.modalElement.find('[data-safe-upgrade-action="recheck"]'),
finish: this.modalElement.find('[data-safe-upgrade-action="finish"]')
};
this.urls = this.buildUrls();
this.decisions = {};
@@ -4627,6 +4628,7 @@ var SafeUpgrade = /*#__PURE__*/function () {
this.stageEnteredAt = 0;
this.directStatusUrl = this.resolveDirectStatusUrl();
this.preferDirectStatus = !!this.directStatusUrl;
this.modalLocked = false;
this.registerEvents();
}
return safe_upgrade_createClass(SafeUpgrade, [{
@@ -4670,6 +4672,18 @@ var SafeUpgrade = /*#__PURE__*/function () {
}
_this.startUpgrade();
});
this.modalElement.on('click', '[data-safe-upgrade-action="finish"]', function (event) {
event.preventDefault();
var button = external_jQuery_default()(event.currentTarget);
if (button.prop('disabled')) {
return;
}
_this.modalLocked = false;
_this.modal.close('finish');
setTimeout(function () {
return window.location.reload();
}, 75);
});
this.modalElement.on('change', '[data-safe-upgrade-decision]', function (event) {
var target = external_jQuery_default()(event.currentTarget);
var decision = target.val();
@@ -4677,6 +4691,11 @@ var SafeUpgrade = /*#__PURE__*/function () {
_this.decisions[type] = decision;
_this.updateStartButtonState();
});
this.modalElement.on('closing', function (event) {
if (_this.modalLocked && event.reason !== 'finish') {
event.preventDefault();
}
});
}
}, {
key: "setPayload",
@@ -4695,6 +4714,7 @@ var SafeUpgrade = /*#__PURE__*/function () {
this.statusIdleCount = 0;
this.currentStage = null;
this.stageEnteredAt = 0;
this.modalLocked = false;
this.renderLoading();
this.modal.open();
this.fetchPreflight();
@@ -4702,6 +4722,8 @@ var SafeUpgrade = /*#__PURE__*/function () {
}, {
key: "renderLoading",
value: function renderLoading() {
this.modalLocked = false;
this.resetFooterButtons();
this.switchStep('preflight');
this.steps.preflight.html("\n <div class=\"safe-upgrade-loading\">\n <span class=\"fa fa-refresh fa-spin\"></span>\n <p>".concat(t('SAFE_UPGRADE_CHECKING', 'Running preflight checks...'), "</p>\n </div>\n "));
this.buttons.start.prop('disabled', true).addClass('hidden');
@@ -4903,6 +4925,8 @@ var SafeUpgrade = /*#__PURE__*/function () {
percent: 0
});
this.buttons.start.prop('disabled', true);
this.buttons.finish.addClass('hidden').prop('disabled', true);
this.modalLocked = false;
this.stopPolling();
this.jobId = null;
var decisionFields = {};
@@ -4954,11 +4978,6 @@ var SafeUpgrade = /*#__PURE__*/function () {
target_version: data.version || data.manifest && data.manifest.target_version || null,
manifest: data.manifest || null
});
if (data.status === 'success') {
setTimeout(function () {
return window.location.reload();
}, 2500);
}
return;
}
if (data.status === 'queued' && data.job_id) {
@@ -5066,7 +5085,6 @@ var SafeUpgrade = /*#__PURE__*/function () {
var nextStage = null;
var jobComplete = false;
var jobFailed = false;
var shouldReload = false;
var handled = false;
var lastPayload = null;
console.debug('[SafeUpgrade] poll status');
@@ -5132,10 +5150,8 @@ var SafeUpgrade = /*#__PURE__*/function () {
nextStage = 'complete';
}
jobComplete = true;
shouldReload = true;
} else if (!job.status && data.stage === 'complete') {
jobComplete = true;
shouldReload = true;
}
});
var finalize = function finalize() {
@@ -5164,11 +5180,6 @@ var SafeUpgrade = /*#__PURE__*/function () {
} else if (jobComplete || nextStage === 'complete') {
_this6.stopPolling();
_this6.jobId = null;
if (shouldReload) {
setTimeout(function () {
return window.location.reload();
}, 2500);
}
} else {
_this6.schedulePoll();
}
@@ -5258,12 +5269,18 @@ var SafeUpgrade = /*#__PURE__*/function () {
if (this.updates) {
this.updates.fetch(true);
}
this.prepareCompletionFooter();
} else if (status === 'noop') {
this.steps.result.html("\n <div class=\"safe-upgrade-result neutral\">\n <h3>".concat(t('SAFE_UPGRADE_RESULT_NOOP', 'Grav is already up to date.'), "</h3>\n </div>\n "));
this.switchStep('result');
this.prepareCompletionFooter();
} else {
this.steps.result.html("\n <div class=\"safe-upgrade-result error\">\n <h3>".concat(t('SAFE_UPGRADE_RESULT_FAILURE', 'Safe upgrade failed'), "</h3>\n <p>").concat(result.message || t('SAFE_UPGRADE_GENERIC_ERROR', 'Safe upgrade could not complete. See Grav logs for details.'), "</p>\n </div>\n "));
this.switchStep('result');
this.modalLocked = false;
this.buttons.finish.addClass('hidden').prop('disabled', true);
this.buttons.cancel.removeClass('hidden').prop('disabled', false);
this.buttons.recheck.removeClass('hidden').prop('disabled', false);
}
}
}, {
@@ -5276,6 +5293,22 @@ var SafeUpgrade = /*#__PURE__*/function () {
_this8.steps[handle].toggleClass('hidden', !isActive);
});
}
}, {
key: "resetFooterButtons",
value: function resetFooterButtons() {
this.buttons.cancel.removeClass('hidden').prop('disabled', false);
this.buttons.recheck.removeClass('hidden').prop('disabled', false);
this.buttons.finish.addClass('hidden').prop('disabled', true);
}
}, {
key: "prepareCompletionFooter",
value: function prepareCompletionFooter() {
this.modalLocked = true;
this.buttons.cancel.addClass('hidden').prop('disabled', true);
this.buttons.recheck.addClass('hidden').prop('disabled', true);
this.buttons.start.addClass('hidden').prop('disabled', true);
this.buttons.finish.removeClass('hidden').prop('disabled', false);
}
}, {
key: "stopPolling",
value: function stopPolling() {

View File

@@ -142,6 +142,7 @@
<button data-remodal-action="cancel" data-safe-upgrade-action="cancel" class="button secondary remodal-cancel"><i class="fa fa-fw fa-close"></i> {{ "PLUGIN_ADMIN.CANCEL"|t }}</button>
<button data-safe-upgrade-action="recheck" class="button secondary">{{ "PLUGIN_ADMIN.SAFE_UPGRADE_RECHECK"|t }}</button>
<button data-safe-upgrade-action="start" class="button primary hidden" disabled>{{ "PLUGIN_ADMIN.SAFE_UPGRADE_START"|t }}</button>
<button data-safe-upgrade-action="finish" class="button primary hidden">{{ "PLUGIN_ADMIN.SAFE_UPGRADE_FINISH"|t }}</button>
</div>
</form>
</div>