firmware: upgrade sets into updatelist #4500

While here the API now tells the page what it should do.
We always consume updates first and then tell the user
it is all well or that an upgrade is available.

Errors are shown as well although when the API has a
fatal issue we don't want to try to force a reaction
and instead just log to console.

The major upgrade needs another fold to be made even
quicker than before but for today that is enough.
This commit is contained in:
Franco Fichtner 2021-02-15 16:43:14 +01:00
parent a22981977a
commit 91d6fa9dab
2 changed files with 132 additions and 73 deletions

View File

@ -99,6 +99,7 @@ class FirmwareController extends ApiControllerBase
}
$packages_size = !empty($response['download_size']) ? $response['download_size'] : 0;
$upgrade_size = 0;
$sets_size = 0;
if (!empty($response['upgrade_packages'])) {
@ -131,7 +132,7 @@ class FirmwareController extends ApiControllerBase
$download_size = $this->formatBytes($packages_size + $sets_size);
$sorted = array();
$sorted = [];
foreach (
array('new_packages', 'reinstall_packages', 'upgrade_packages',
@ -200,6 +201,32 @@ class FirmwareController extends ApiControllerBase
$response['all_packages'] = $sorted;
$sorted = [];
if (isset($response['upgrade_sets'])) {
foreach ($response['upgrade_sets'] as $value) {
if (!empty($value['size'])) {
$upgrade_size += $value['size'];
}
$sorted[$value['name']] = array(
'reason' => gettext('upgrade'),
'old' => empty($value['current_version']) ?
gettext('N/A') : $value['current_version'],
'new' => $value['new_version'],
'repository' => $value['repository'],
'name' => $value['name'],
);
}
}
$upgrade_size = $this->formatBytes($upgrade_size);
uksort($sorted, function ($a, $b) {
return strnatcasecmp($a, $b);
});
$response['all_sets'] = $sorted;
if (array_key_exists('connection', $response) && $response['connection'] == 'unresolved') {
$response['status_msg'] = gettext('No address record found for the selected mirror.');
$response['status'] = 'error';
@ -262,7 +289,24 @@ class FirmwareController extends ApiControllerBase
gettext('This update requires a reboot.')
);
}
$response['status'] = 'ok';
$response['status'] = 'update';
} elseif (array_key_exists('upgrade_sets', $response) && count($response['upgrade_sets'])) {
if (count($response['upgrade_sets']) == 1) {
/* keep this dynamic for template translation even though %s is always '1' */
$response['status_msg'] = sprintf(
gettext('There is %s update available, total download size is %s.'),
count($response['upgrade_sets']),
$upgrade_size
);
} else {
$response['status_msg'] = sprintf(
gettext('There are %s updates available, total download size is %s.'),
count($response['upgrade_sets']),
$upgrade_size
);
}
$response['status_msg'] = sprintf( '%s %s', $response['status_msg'], gettext('This update requires multiple reboots.'));
$response['status'] = 'upgrade';
} elseif (array_key_exists('updates', $response) && $response['updates'] == 0) {
$response['status_msg'] = gettext('There are no updates available on the selected mirror.');
$response['status'] = 'none';

View File

@ -61,19 +61,27 @@
* retrieve update status from backend
*/
function updateStatus() {
// update UI
$('#major-upgrade').hide();
$('#upgrade_maj').prop('disabled', true);
$.upgrade_major_message = '';
$.upgrade_major_version = '';
$('#upgrade_maj').hide();
$('#upgrade').hide();
// request status
ajaxGet('/api/core/firmware/status', {}, function (data, status){
if (data['status'] == "ok") {
let upgrade_major_message = '';
let upgrade_major_version = '';
if ('upgrade_major_message' in data) {
upgrade_major_message = data['upgrade_major_message'];
}
if ('upgrade_major_version' in data) {
upgrade_major_version = data['upgrade_major_version'];
}
if (data['status'] == "update") {
let show_log = '';
$.upgrade_needs_reboot = data['upgrade_needs_reboot'];
$.upgrade_show_log = '';
// show upgrade list
$('#upgrade').show();
$('#updatestatus').html(data['status_msg']);
$('#updatelist > tbody').empty();
$('#updatetab > a').tab('show');
@ -83,23 +91,64 @@
row['reason']+'</td><td>'+row['repository'] + '</td></tr>');
if (row['name'] == data['product_target'] && row['new'] != 'N/A') {
$.upgrade_show_log = row['new'].replace(/[_-].*/, '');
show_log = row['new'].replace(/[_-].*/, '');
}
});
$('#update_status_container').hide();
$('#updatelist').show();
// display the current changelog if one was found
if ($.upgrade_show_log != '') {
changelog($.upgrade_show_log);
if (show_log != '') {
changelog(show_log);
}
// update list so plugins sync as well (no logs)
packagesInfo(false);
} else {
// ok or an error of some sort: make this official
} else if (data['status'] == "upgrade") {
if (upgrade_major_message == '') {
upgrade_major_message = '{{ lang._('This software release has reached its designated end of life.') }}';
upgrade_major_message += ' {{ lang._('The next major release is:') }} ' + upgrade_major_version;
}
BootstrapDialog.show({
type: data['status'] != "error" ? BootstrapDialog.TYPE_SUCCESS : BootstrapDialog.TYPE_DANGER,
type: BootstrapDialog.TYPE_WARNING,
title: '{{ lang._('Upgrade instructions') }}',
/* we trust this data, it was signed by us and secured by csrf */
message: htmlDecode(upgrade_major_message),
buttons: [{
label: "{{ lang._('Unlock') }}",
cssClass: 'btn-warning',
action: function (dialogRef) {
dialogRef.close();
// show upgrade list
$('#upgrade_maj').show();
$('#updatestatus').html(data['status_msg']);
$('#updatelist > tbody').empty();
$('#updatetab > a').tab('show');
$.each(data['all_sets'], function (index, row) {
$('#updatelist > tbody').append('<tr><td>'+row['name']+'</td>' +
'<td>'+row['old']+'</td><td>'+row['new']+'</td><td>' +
row['reason']+'</td><td>'+row['repository'] + '</td></tr>');
});
$('#update_status_container').hide();
$('#updatelist').show();
changelog(upgrade_major_version);
}
},{
label: "{{ lang._('Cancel') }}",
action: function (dialogRef) {
dialogRef.close();
}
}]
});
// update list so plugins sync as well (all)
packagesInfo(true);
} else if (data['status'] == "error") {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_DANGER,
title: "{{ lang._('Status') }}",
onshow:function(dialogRef){
dialogRef.getModalBody().html(data['status_msg']);
@ -114,17 +163,27 @@
// update list so plugins sync as well (all)
packagesInfo(true);
}
} else if (data['status'] == "none") {
BootstrapDialog.show({
type: BootstrapDialog.TYPE_SUCCESS,
title: "{{ lang._('Status') }}",
onshow:function(dialogRef){
dialogRef.getModalBody().html(data['status_msg']);
},
buttons: [{
label: "{{ lang._('Close') }}",
action: function(dialogRef){
dialogRef.close();
}
}]
});
if ('upgrade_major_message' in data) {
$.upgrade_major_message = data['upgrade_major_message'];
}
if ('upgrade_major_version' in data) {
$.upgrade_major_version = data['upgrade_major_version'];
}
if ($.upgrade_major_version != '') {
$('#upgrade-version').text($.upgrade_major_version);
$('#major-upgrade').show();
// update list so plugins sync as well (all)
packagesInfo(true);
} else {
// in case new responses are added
console.log('Unknown check response');
console.log(data);
}
});
}
@ -134,8 +193,7 @@
*/
function backend(type) {
if ($.upgrade_action == 'maj') {
$("#upgrade_maj").attr("style","");
$('#updatetab_progress').addClass("fa fa-spinner fa-pulse");
// leave upgrade action as is
} else if (type == 'check') {
$.upgrade_action = 'check';
} else {
@ -308,8 +366,6 @@
}
if (data['status'] == 'done') {
$('#updatetab_progress').removeClass("fa fa-spinner fa-pulse");
$('#major-upgrade').hide();
$('#upgrade_maj').prop('disabled', true);
if ($.upgrade_action == 'check') {
updateStatus();
} else {
@ -608,34 +664,6 @@
$.upgrade_action = 'maj';
upgrade_ui();
});
$('#checkupdate_maj').click(function () {
if ($.upgrade_major_message == "") {
$('#upgrade_maj').prop('disabled', false);
changelog($.upgrade_major_version);
} else {
BootstrapDialog.show({
type:BootstrapDialog.TYPE_WARNING,
title: "{{ lang._('Upgrade instructions') }}",
/* we trust this data, it was signed by us and secured by csrf */
message: htmlDecode($.upgrade_major_message),
buttons: [{
label: "{{ lang._('Unlock') }}",
cssClass: 'btn-warning',
action: function (dialogRef) {
dialogRef.close();
$('#upgrade_maj').prop('disabled', false);
changelog($.upgrade_major_version);
}
},{
label: "{{ lang._('Cancel') }}",
action: function (dialogRef) {
dialogRef.close();
}
}]
});
packagesInfo(true);
}
});
// populate package information
packagesInfo(true);
@ -794,20 +822,6 @@
}
</style>
<div class="container-fluid">
<div class="row">
<div id="major-upgrade" class="alert alert-warning alert-dismissible" role="alert" style="min-height:65px;display:none;">
<button type="button" class="close pull-right" style="margin-top: 8px;" data-dismiss="alert" aria-label="{{ lang._('Close') }}">
<span aria-hidden="true">&times;</span>
</button>
<button class='btn btn-primary pull-right' id="upgrade_maj" disabled="disabled"><i class="fa fa-check"></i> {{ lang._('Upgrade') }}</button>
<button class='btn pull-right' id="checkupdate_maj" style="margin-right: 8px;"><i class="fa fa-unlock-alt"></i> {{ lang._('Unlock') }}</button>
<div style="margin-top: 8px;">
{{ lang._('This software release has reached its designated end of life.') }}
{{ lang._('The next major release is:') }}
<span id="upgrade-version"></span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12" id="content">
<ul class="nav nav-tabs" data-tabs="tabs">
@ -835,7 +849,8 @@
<tr>
<td></td>
<td style="white-space:nowrap;vertical-align:middle;">
<button class="btn btn-primary" id="upgrade"><i class="fa fa-check"></i> {{ lang._('Update') }}</button>
<button class="btn btn-info" id="upgrade"><i class="fa fa-check"></i> {{ lang._('Update') }}</button>
<button class='btn btn-warning' id="upgrade_maj"><i class="fa fa-check"></i> {{ lang._('Upgrade') }}</button>
<button class="btn btn-default" id="upgrade_dismiss"><i class="fa fa-times"></i> {{ lang._('Dismiss') }}</button>
</td>
<td colspan="2" style="vertical-align:middle">