mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
[enh] Reboot/shutdown from admin interface (#173)
* [enh] Add reboot/shutdown action in tools section. * [enh] Use icon in front of reboot buttons. * [enh] Improve reboot string. * Enhance shutdown/reboot page with a header * Enhance wording * [fix] Indicate to users server is rebooting/shutting down * [fix] Dead code
This commit is contained in:
parent
713a3d59a5
commit
26ad22df9e
5 changed files with 170 additions and 67 deletions
|
@ -178,6 +178,63 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Reboot or shutdown button
|
||||||
|
app.get('#/tools/reboot', function (c) {
|
||||||
|
c.view('tools/tools_reboot');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reboot or shutdown actions
|
||||||
|
app.get('#/tools/reboot/:action', function (c) {
|
||||||
|
var action = c.params['action'].toLowerCase();
|
||||||
|
if (action == 'reboot' || action == 'shutdown') {
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('tools_' + action),
|
||||||
|
// confirm_reboot_action_reboot or confirm_reboot_action_shutdown
|
||||||
|
y18n.t('confirm_reboot_action_' + action),
|
||||||
|
function(){
|
||||||
|
c.api('/'+action+'?force', function(data) {
|
||||||
|
// This code is not executed due to 502 response (reboot or shutdown)
|
||||||
|
c.redirect('#/logout');
|
||||||
|
}, 'PUT', {}, false, function (xhr) {
|
||||||
|
c.flash('success', y18n.t('tools_' + action + '_done'))
|
||||||
|
// Disconnect from the webadmin
|
||||||
|
store.clear('url');
|
||||||
|
store.clear('connected');
|
||||||
|
store.set('path', '#/');
|
||||||
|
|
||||||
|
// Rename the page to allow refresh without ask for rebooting
|
||||||
|
window.location.href = window.location.href.split('#')[0] + '#/';
|
||||||
|
// Display reboot or shutdown info
|
||||||
|
// We can't use template because now the webserver is off
|
||||||
|
if (action == 'reboot') {
|
||||||
|
$('#main').replaceWith('<div id="main"><div class="alert alert-warning"><i class="fa-refresh"></i> ' + y18n.t('tools_rebooting') + '</div></div>');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#main').replaceWith('<div id="main"><div class="alert alert-warning"><i class="fa-power-off"></i> ' + y18n.t('tools_shuttingdown') + '</div></div>');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove loader if any
|
||||||
|
$('div.loader').remove();
|
||||||
|
|
||||||
|
// Force scrollTop on page load
|
||||||
|
$('html, body').scrollTop(0);
|
||||||
|
store.clear('slide');
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
function(){
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/tools/reboot');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
c.flash('fail', y18n.t('unknown_action', [action]));
|
||||||
|
store.clear('slide');
|
||||||
|
c.redirect('#/tools/reboot');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Diagnosis
|
// Diagnosis
|
||||||
app.get('#/tools/diagnosis(/:private)?', function (c) {
|
app.get('#/tools/diagnosis(/:private)?', function (c) {
|
||||||
// See http://sammyjs.org/docs/routes for splat documentation
|
// See http://sammyjs.org/docs/routes for splat documentation
|
||||||
|
|
|
@ -62,10 +62,10 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
// API call
|
// API call
|
||||||
api: function(uri, callback, method, data, websocket) {
|
api: function(uri, callback, method, data, websocket, callbackOnFailure) {
|
||||||
c = this;
|
c = this;
|
||||||
|
|
||||||
call = function(uri, callback, method, data) {
|
call = function(uri, callback, method, data, callbackOnFailure) {
|
||||||
method = typeof method !== 'undefined' ? method : 'GET';
|
method = typeof method !== 'undefined' ? method : 'GET';
|
||||||
data = typeof data !== 'undefined' ? data : {};
|
data = typeof data !== 'undefined' ? data : {};
|
||||||
if (window.navigator && window.navigator.language && (typeof data.locale === 'undefined')) {
|
if (window.navigator && window.navigator.language && (typeof data.locale === 'undefined')) {
|
||||||
|
@ -84,6 +84,71 @@
|
||||||
if ($('div.loader').length === 0) {
|
if ($('div.loader').length === 0) {
|
||||||
$('#main').append('<div class="loader loader-content"></div>');
|
$('#main').append('<div class="loader loader-content"></div>');
|
||||||
}
|
}
|
||||||
|
if (typeof callbackOnFailure !== 'function') {
|
||||||
|
callbackOnFailure = function(xhr) {
|
||||||
|
// Postinstall is a custom case, we have to wait that
|
||||||
|
// operation is done before doing anything
|
||||||
|
if (uri === '/postinstall') {
|
||||||
|
if (installing) {
|
||||||
|
interval = window.location.hostname === args.domain ? 20000 : 5000;
|
||||||
|
checkInstall = setInterval(function () {
|
||||||
|
c.checkInstall(function(isInstalled) {
|
||||||
|
if (isInstalled || typeof isInstalled === 'undefined') {
|
||||||
|
c.flash('success', y18n.t('installation_complete'));
|
||||||
|
clearInterval(checkInstall);
|
||||||
|
window.location.href = 'https://'+ window.location.hostname +'/yunohost/admin/';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, interval);
|
||||||
|
} else {
|
||||||
|
c.flash('fail', y18n.t('error_occured'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Regular errors
|
||||||
|
else {
|
||||||
|
if (xhr.status == 200) {
|
||||||
|
// Fail with 200, WTF
|
||||||
|
callback({});
|
||||||
|
}
|
||||||
|
// Unauthorized or wrong password
|
||||||
|
else if (xhr.status == 401) {
|
||||||
|
if (uri === '/login') {
|
||||||
|
c.flash('fail', y18n.t('wrong_password'));
|
||||||
|
} else {
|
||||||
|
c.flash('fail', y18n.t('unauthorized'));
|
||||||
|
c.redirect('#/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 500
|
||||||
|
else if (xhr.status == 500) {
|
||||||
|
error_log = JSON.parse(xhr.responseText);
|
||||||
|
error_log.route = error_log.route.join(' ') + '\n';
|
||||||
|
error_log.arguments = JSON.stringify(error_log.arguments);
|
||||||
|
c.flash('fail', y18n.t('internal_exception', [error_log.route, error_log.arguments, error_log.traceback]));
|
||||||
|
}
|
||||||
|
// 502 Bad gateway means API is down
|
||||||
|
else if (xhr.status == 502) {
|
||||||
|
c.flash('fail', y18n.t('api_not_responding'));
|
||||||
|
}
|
||||||
|
// More verbose error messages first
|
||||||
|
else if (typeof xhr.responseText !== 'undefined') {
|
||||||
|
c.flash('fail', xhr.responseText);
|
||||||
|
}
|
||||||
|
// Return HTTP error code at least
|
||||||
|
else {
|
||||||
|
var errorMessage = xhr.status+' '+xhr.statusText;
|
||||||
|
c.flash('fail', y18n.t('error_server_unexpected', [errorMessage]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove loader if any
|
||||||
|
$('div.loader').remove();
|
||||||
|
|
||||||
|
// Force scrollTop on page load
|
||||||
|
$('html, body').scrollTop(0);
|
||||||
|
store.clear('slide');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
jQuery.ajax({
|
jQuery.ajax({
|
||||||
url: 'https://' + store.get('url') + uri,
|
url: 'https://' + store.get('url') + uri,
|
||||||
|
@ -99,69 +164,7 @@
|
||||||
data = data || {};
|
data = data || {};
|
||||||
callback(data);
|
callback(data);
|
||||||
})
|
})
|
||||||
.fail(function(xhr) {
|
.fail(callbackOnFailure);
|
||||||
// Postinstall is a custom case, we have to wait that
|
|
||||||
// operation is done before doing anything
|
|
||||||
if (uri === '/postinstall') {
|
|
||||||
if (installing) {
|
|
||||||
interval = window.location.hostname === args.domain ? 20000 : 5000;
|
|
||||||
checkInstall = setInterval(function () {
|
|
||||||
c.checkInstall(function(isInstalled) {
|
|
||||||
if (isInstalled || typeof isInstalled === 'undefined') {
|
|
||||||
c.flash('success', y18n.t('installation_complete'));
|
|
||||||
clearInterval(checkInstall);
|
|
||||||
window.location.href = 'https://'+ window.location.hostname +'/yunohost/admin/';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, interval);
|
|
||||||
} else {
|
|
||||||
c.flash('fail', y18n.t('error_occured'));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Regular errors
|
|
||||||
else {
|
|
||||||
if (xhr.status == 200) {
|
|
||||||
// Fail with 200, WTF
|
|
||||||
callback({});
|
|
||||||
}
|
|
||||||
// Unauthorized or wrong password
|
|
||||||
else if (xhr.status == 401) {
|
|
||||||
if (uri === '/login') {
|
|
||||||
c.flash('fail', y18n.t('wrong_password'));
|
|
||||||
} else {
|
|
||||||
c.flash('fail', y18n.t('unauthorized'));
|
|
||||||
c.redirect('#/login');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 500
|
|
||||||
else if (xhr.status == 500) {
|
|
||||||
error_log = JSON.parse(xhr.responseText);
|
|
||||||
error_log.route = error_log.route.join(' ') + '\n';
|
|
||||||
error_log.arguments = JSON.stringify(error_log.arguments);
|
|
||||||
c.flash('fail', y18n.t('internal_exception', [error_log.route, error_log.arguments, error_log.traceback]));
|
|
||||||
}
|
|
||||||
// 502 Bad gateway means API is down
|
|
||||||
else if (xhr.status == 502) {
|
|
||||||
c.flash('fail', y18n.t('api_not_responding'));
|
|
||||||
}
|
|
||||||
// More verbose error messages first
|
|
||||||
else if (typeof xhr.responseText !== 'undefined') {
|
|
||||||
c.flash('fail', xhr.responseText);
|
|
||||||
}
|
|
||||||
// Return HTTP error code at least
|
|
||||||
else {
|
|
||||||
var errorMessage = xhr.status+' '+xhr.statusText;
|
|
||||||
c.flash('fail', y18n.t('error_server_unexpected', [errorMessage]));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove loader if any
|
|
||||||
$('div.loader').remove();
|
|
||||||
|
|
||||||
// Force scrollTop on page load
|
|
||||||
$('html, body').scrollTop(0);
|
|
||||||
store.clear('slide');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
websocket = typeof websocket !== 'undefined' ? websocket : true;
|
websocket = typeof websocket !== 'undefined' ? websocket : true;
|
||||||
|
@ -181,9 +184,9 @@
|
||||||
|
|
||||||
ws.onclose = function() {};
|
ws.onclose = function() {};
|
||||||
|
|
||||||
ws.onopen = call(uri, callback, method, data);
|
ws.onopen = call(uri, callback, method, data, callbackOnFailure);
|
||||||
} else {
|
} else {
|
||||||
call(uri, callback, method, data);
|
call(uri, callback, method, data, callbackOnFailure);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
|
@ -79,6 +79,8 @@
|
||||||
"confirm_update_specific_app": "Are you sure you want to update %s?",
|
"confirm_update_specific_app": "Are you sure you want to update %s?",
|
||||||
"confirm_upnp_enable": "Are you sure you want to enable UPnP?",
|
"confirm_upnp_enable": "Are you sure you want to enable UPnP?",
|
||||||
"confirm_upnp_disable": "Are you sure you want to disable UPnP?",
|
"confirm_upnp_disable": "Are you sure you want to disable UPnP?",
|
||||||
|
"confirm_reboot_action_reboot": "Are you sure you want to reboot your server?",
|
||||||
|
"confirm_reboot_action_shutdown": "Are you sure you want to shutdown your server?",
|
||||||
"connection": "Connection",
|
"connection": "Connection",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"count_min": "%s min",
|
"count_min": "%s min",
|
||||||
|
@ -272,6 +274,15 @@
|
||||||
"tools_security_feed_no_items": "No security notifications",
|
"tools_security_feed_no_items": "No security notifications",
|
||||||
"tools_security_feed_subscribe_rss": "Subscribe to security notifications RSS",
|
"tools_security_feed_subscribe_rss": "Subscribe to security notifications RSS",
|
||||||
"tools_security_feed_view_items": "View all security notifications",
|
"tools_security_feed_view_items": "View all security notifications",
|
||||||
|
"tools_reboot": "Reboot your server",
|
||||||
|
"tools_reboot_btn": "Reboot",
|
||||||
|
"tools_reboot_done": "Rebooting...",
|
||||||
|
"tools_rebooting": "Your server is rebooting. To return on the web administration interface you need to wait your server to be up. You can check that by refreshing regularly this page (F5).",
|
||||||
|
"tools_shutdown": "Shutdown your server",
|
||||||
|
"tools_shutdown_btn": "Shutdown",
|
||||||
|
"tools_shutdown_done": "Shutting down...",
|
||||||
|
"tools_shuttingdown": "Your server is powerring off. As long as your server is off, you won't be able to use the web administration.",
|
||||||
|
"tools_shutdown_reboot": "Shutdown/Reboot",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"transmission": "Transmission",
|
"transmission": "Transmission",
|
||||||
"udp": "UDP",
|
"udp": "UDP",
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
<span class="fa-chevron-right pull-right"></span>
|
||||||
<h2 class="list-group-item-heading">{{t 'tools_security_feed'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'tools_security_feed'}}</h2>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="#/tools/reboot" class="list-group-item slide clearfix">
|
||||||
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
|
<h2 class="list-group-item-heading">{{t 'tools_shutdown_reboot'}}</h2>
|
||||||
|
</a>
|
||||||
<a href="#/tools/versions" class="list-group-item slide clearfix">
|
<a href="#/tools/versions" class="list-group-item slide clearfix">
|
||||||
<span class="pull-right fa-chevron-right"></span>
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
<h2 class="list-group-item-heading">{{t 'versions'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'versions'}}</h2>
|
||||||
|
|
28
src/views/tools/tools_reboot.ms
Normal file
28
src/views/tools/tools_reboot.ms
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/tools">{{t 'tools'}}</a>
|
||||||
|
<a href="#/tools/reboot">{{t 'tools_shutdown_reboot'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title">
|
||||||
|
<span class="fa-fw fa-wrench"></span> {{t 'operations'}}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
<a href="#/tools/reboot/reboot" class="btn btn-danger">
|
||||||
|
<i class="fa-refresh"></i> {{t 'tools_reboot_btn'}}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<a href="#/tools/reboot/shutdown" class="btn btn-danger">
|
||||||
|
<i class="fa-power-off"></i> {{t 'tools_shutdown_btn'}}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
Add table
Reference in a new issue