Merge branch 'unstable' into enh_change_label

This commit is contained in:
Laurent Peuch 2018-01-14 00:38:42 +01:00 committed by GitHub
commit 0d2fe76fe7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 647 additions and 199 deletions

60
debian/changelog vendored
View file

@ -1,3 +1,63 @@
yunohost-admin (2.7.5) stable; urgency=low
(Bumping version number for stable release)
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 02 Dec 2017 12:34:45 -0500
yunohost-admin (2.7.4) testing; urgency=low
* [i18n] Improve French. German translations
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 28 Nov 2017 18:58:04 -0500
yunohost-admin (2.7.3) testing; urgency=low
* [i18n] Improve french translation (#170)
* [fix] Add "OK" in translatable strings (#171)
* [enh] Be able to upgrade single apps (#172)
* [enh] Reboot/shutdown from admin interface (#173)
Thanks to all contributors <3 ! (opi, ljf, ariasuni, Jibec)
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 12 Oct 2017 16:51:24 -0400
yunohost-admin (2.7.2) stable; urgency=low
Releasing as stable
-- Alexandre Aubin <alex.aubin@mailoo.org> Tue, 22 Aug 2017 21:36:35 -0400
yunohost-admin (2.7.1) testing; urgency=low
[ Alexandre Aubin ]
* [fix] Tell user that domain dns-conf shows a recommendation only
[ Translations ]
* Added translation using Weblate (Russian) (Evgeniy Ozhiganov)
* [i18n] Translated using Weblate (Esperanto) (MCMic)
Thanks to all contributors (MCMic, Aleks, Ozhiganov) <3 !
-- Laurent Peuch <cortex@worlddomination.be> Sat, 19 Aug 2017 22:43:15 +0000
yunohost-admin (2.7.0) testing; urgency=low
* [enh] Variable assignment code cleanup. (#161)
* [fix] Friendlier and more meaningful 'error 500' (#166)
* [i18n] Started Russian translation (#167)
Thanks to all contributors (opi, Aleks, Ozhiganov) <3 !
-- Alexandre Aubin <alex.aubin@mailoo.org> Mon, 07 Aug 2017 12:49:55 -0400
yunohost-admin (2.6.2) stable; urgency=low
## Minor fix
* 'hooks' key is now 'system' in backup info (#165)
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 26 Jul 2017 12:09:03 -0400
yunohost-admin (2.6.1) stable; urgency=low
Major changes since 2.6.0

2
debian/control vendored
View file

@ -12,7 +12,7 @@ Architecture: all
Conflicts: yunohost-apps-admin
Replaces: yunohost-apps-admin
Depends: ${misc:Depends}
, yunohost (>= 2.3.6)
, yunohost (>= 2.7.1)
Description: web administration interface for yunohost
YunoHost aims to make self-hosting accessible to everyone. It configures
an email, Web and IM server alongside a LDAP base. It also provides

View file

@ -11,7 +11,7 @@
// List installed apps
app.get('#/apps', function (c) {
c.api('/apps?installed', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
apps = data['apps'];
var apps = data['apps'];
c.arraySortById(apps);
c.view('app/app_list', {apps: apps});
});
@ -21,7 +21,7 @@
app.get('#/apps/install', function (c) {
c.api('/apps', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
c.api('/apps?raw', function(dataraw) { // http://api.yunohost.org/#!/app/app_list_get_8
apps = [];
var apps = [];
$.each(data['apps'], function(k, v) {
// Keep only uninstalled apps, or multi-instance apps
if ((!v['installed'] || dataraw[v['id']].manifest.multi_instance) && !v['id'].match(/__[0-9]{1,5}$/)) {
@ -169,7 +169,7 @@
// Helper function that build app installation form
app.helper('appInstallForm', function(appId, manifest, params) {
data = {
var data = {
id: appId,
manifest: manifest
};
@ -286,10 +286,11 @@
// Clone a hidden input with empty value
// https://stackoverflow.com/questions/476426/submit-an-html-form-with-empty-checkboxes
inputClone = {};
inputClone.name = data.manifest.arguments.install[k].name;
inputClone.inputType = 'hidden';
inputClone.default = 0;
var inputClone = {
name : data.manifest.arguments.install[k].name,
inputType : 'hidden',
default : 0
};
data.manifest.arguments.install.push(inputClone);
}
@ -319,13 +320,11 @@
// App installation form
app.get('#/apps/install/:app', function (c) {
c.api('/apps?raw', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
c.appInstallForm(
c.params['app'],
data[c.params['app']].manifest,
c.params
);
});
});
@ -333,11 +332,14 @@
app.post('#/apps', function(c) {
// Warn admin if app is going to be installed on domain root.
if (c.params['path'] !== '/' || confirm(y18n.t('confirm_install_domain_root', [c.params['domain']]))) {
params = { 'label': c.params['label'], 'app': c.params['app'] };
delete c.params['label'];
delete c.params['app'];
var params = {
label: c.params['label'],
app: c.params['app']
};
// Check for duplicate arg produced by empty checkbox. (See inputClone)
delete c.params['label'];
delete c.params['app'];
$.each(c.params, function(k, v) {
if (typeof(v) === 'object' && Array.isArray(v)) {
// And return only first value
@ -346,6 +348,7 @@
});
params['args'] = c.serialize(c.params.toHash());
// Do not pass empty args.
if (params['args'] === "") {
delete params['args'];
@ -365,7 +368,10 @@
// Install custom app from github
app.post('#/apps/install/custom', function(c) {
params = { 'label': c.params['label'], 'app': c.params['url'] };
var params = {
label: c.params['label'],
app: c.params['url']
};
delete c.params['label'];
delete c.params['url'];
@ -475,7 +481,10 @@
y18n.t('applications'),
y18n.t('confirm_access_remove_all', [c.params['app']]),
function() {
params = {'apps': c.params['app'], 'users':[]};
var params = {
apps: c.params['app'],
users: []
};
c.api('/access?'+c.serialize(params), function(data) { // http://api.yunohost.org/#!/app/app_removeaccess_delete_12
store.clear('slide');
c.redirect('#/apps/'+ c.params['app']+ '/access');
@ -494,7 +503,10 @@
y18n.t('applications'),
y18n.t('confirm_access_remove_user', [c.params['app'], c.params['user']]),
function() {
params = {'apps': c.params['app'], 'users': c.params['user']};
var params = {
apps: c.params['app'],
users: c.params['user']
};
c.api('/access?'+c.serialize(params), function(data) { // http://api.yunohost.org/#!/app/app_removeaccess_delete_12
store.clear('slide');
c.redirect('#/apps/'+ c.params['app']+ '/access');
@ -513,7 +525,10 @@
y18n.t('applications'),
y18n.t('confirm_access_add', [c.params['app']]),
function() {
params = {'apps': c.params['app'], 'users': null};
var params = {
apps: c.params['app'],
users: null
};
c.api('/access', function() { // http://api.yunohost.org/#!/app/app_addaccess_put_13
store.clear('slide');
c.redirect('#/apps/'+ c.params['app'] +'/access');
@ -528,7 +543,10 @@
// Grant access for a specific user
app.post('#/apps/:app/access/add', function (c) {
params = {'users': c.params['user'], 'apps': c.params['app']};
var params = {
users: c.params['user'],
apps: c.params['app']
};
c.api('/access', function() { // http://api.yunohost.org/#!/app/app_addaccess_put_13
store.clear('slide');
c.redirect('#/apps/'+ c.params['app'] +'/access');
@ -541,7 +559,9 @@
y18n.t('applications'),
y18n.t('confirm_access_clear', [c.params['app']]),
function() {
params = {'apps': c.params['app']};
var params = {
apps: c.params['app']
};
c.api('/access', function() { //
store.clear('slide');
c.redirect('#/apps/'+ c.params['app'] +'/access');
@ -592,4 +612,50 @@
}, 'PUT', params);
});
// Get app change URL page
app.get('#/apps/:app/changeurl', function (c) {
c.api('/apps/'+c.params['app']+'?raw', function(app_data) {
c.api('/domains', function(domain_data) { // http://api.yunohost.org/#!/domain/domain_list_get_2
// Display a list of available domains
var domains = [];
$.each(domain_data.domains, function(k, domain) {
domains.push({
value: domain,
label: domain,
// Select current domain
selected: (domain == app_data.settings.domain ? true : false)
});
});
data = {
id: c.params['app'],
label: app_data.manifest.name,
domains: domains,
// Pre-fill with current path
path: app_data.settings.path
};
c.view('app/app_changeurl', data);
});
});
});
// Change app URL
app.post('#/apps/:app/changeurl', function (c) {
c.confirm(
y18n.t('applications'),
y18n.t('confirm_app_change_url', [c.params['app']]),
function() {
params = {'domain': c.params['domain'], 'path': c.params['path']};
c.api('/apps/' + c.params['app'] + '/changeurl', function(data) { // Call changeurl API
store.clear('slide');
c.redirect('#/apps/'+ c.params['app']);
}, 'PUT', params);
},
function() {
store.clear('slide');
c.redirect('#/apps/'+ c.params['app'] + '/changeurl');
}
);
});
})();

View file

@ -18,14 +18,15 @@
'system_yunohost',
'system_nginx'
];
// Storage list
app.get('#/backup', function (c) {
var storages = [];
var item = {
id: 'local',
name: y18n.t('local_archives'),
uri: '/home/yunohost.backup/'
};
id: 'local',
name: y18n.t('local_archives'),
uri: '/home/yunohost.backup/'
};
storages.push(item);
c.view('backup/backup', {'storages':storages});
@ -44,14 +45,14 @@
// Create a backup
app.get('#/backup/:storage/create', function (c) {
var data=[];
data['storage']={
var data = [];
data['storage'] = {
id:c.params['storage'],
name:y18n.t('local_archives')
};
c.api('/hooks/backup', function(hooks) {
data['hooks']=c.groupHooks(hooks['hooks']);
data['apps']={};
data['hooks'] = c.groupHooks(hooks['hooks']);
data['apps'] = {};
c.api('/apps?with_backup', function(apps_list) {
data['apps'] = apps_list.apps;
c.view('backup/backup_create', data);
@ -74,13 +75,13 @@
y18n.t('backup'),
y18n.t('confirm_restore', [c.params['archive']]),
$.proxy(function(c){
var params=c.ungroupHooks(c.params['hooks'],c.params['apps']);
params['force']='';
var params = c.ungroupHooks(c.params['hooks'],c.params['apps']);
params['force'] = '';
c.api('/backup/restore/'+c.params['archive'], function(data) {
store.clear('slide');
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
}, 'POST', params);
},this,c),
}, this, c),
function(){
store.clear('slide');
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
@ -127,14 +128,14 @@
// Get archive info
app.get('#/backup/:storage/:archive', function (c) {
c.api('/backup/archives/'+c.params['archive']+'?with_details', function(data) {
data['storage']={
id:c.params['storage'],
name:y18n.t('local_archives')
data.storage = {
id: c.params['storage'],
name: y18n.t('local_archives')
};
data['other_storages']=[];
data['name']=c.params['archive'];
data['hooks']=c.groupHooks(Object.keys(data['system']));
data['items']=(data['hooks']!={} || data['apps']!=[]);
data.other_storages = [];
data.name = c.params['archive'];
data.hooks = c.groupHooks(Object.keys(data['system']));
data.items = (data['hooks']!={} || data['apps']!=[]);
c.view('backup/backup_info', data);
});
});
@ -142,16 +143,16 @@
// Archive list
app.get('#/backup/:storage', function (c) {
c.api('/backup/archives?with_info', function(data) {
data['storage']={
id:'local',
name:y18n.t('local_archives')
data.storage = {
id: 'local',
name: y18n.t('local_archives')
};
data['archives2']=[];
data.archives2 = [];
$.each(data['archives'], function(name, info) {
info['name']=name;
data['archives2'].unshift(info)
info.name = name;
data.archives2.unshift(info)
});
data['archives']=data['archives2'];
data.archives = data.archives2;
c.view('backup/backup_list', data);
});
});

View file

@ -12,7 +12,7 @@
app.get('#/domains', function (c) {
c.api('/domains', function(data) { // http://api.yunohost.org/#!/domain/domain_list_get_2
c.api('/domains/main', function(data2) {
domains = [];
var domains = [];
$.each(data.domains, function(k, domain) {
domains.push({
url: domain,
@ -21,11 +21,14 @@
});
// Do not show main domain form if we have only 1 domain
main_domain_form = (domains.length > 1) ? true: false;
var main_domain_form = (domains.length > 1) ? true: false;
// Sort domains with main domain first
domains.sort(function(a, b){ return -2*(a.main) + 1; });
c.view('domain/domain_list', {domains: domains, main_domain_form: main_domain_form});
c.view('domain/domain_list', {
domains: domains,
main_domain_form: main_domain_form
});
}, 'PUT');
});
});
@ -40,10 +43,10 @@
c.params.ddomains = ['.nohost.me', '.noho.st'];
})
.always(function() {
data = {
ddomains : c.params.ddomains,
domains : c.params.domains,
allowDyndnsDomain : true
var data = {
ddomains: c.params.ddomains,
domains: c.params.domains,
allowDyndnsDomain: true
};
// Allow only 1 DynDns domain.
@ -60,17 +63,18 @@
// Add domain (POST)
app.post('#/domains/add', function (c) {
var params = {};
var endurl = '';
if (c.params['domain'] === '') {
if (c.params['ddomain'] === '') {
c.flash('fail', y18n.t('error_select_domain'));
store.clear('slide');
c.redirect('#/domains/add');
}
params = {'domain': c.params['ddomain'] + c.params['ddomain-ext']};
params.domain = c.params['ddomain'] + c.params['ddomain-ext'];
endurl = 'dyndns';
} else {
params = { 'domain': c.params['domain'] };
endurl = '';
params.domain = c.params['domain'];
}
c.api('/domains?'+endurl, function(data) { // http://api.yunohost.org/#!/domain/domain_add_post_1
@ -87,16 +91,15 @@
// for apps installed) should be removed once letsencrypt_ynh
// is not used by many people anymore. Probably around 07/2017
// or end of 2017...
enable_cert_management_ = true;
var enable_cert_management_ = true;
$.each(data['apps'], function(k, v) {
if (v.id == "letsencrypt")
{
if (v.id == "letsencrypt") {
enable_cert_management_ = false;
}
});
domain = {
var domain = {
name: c.params['domain'],
main: (c.params['domain'] == dataMain.current_main_domain) ? true : false,
url: "https://"+c.params['domain'],
@ -110,10 +113,10 @@
// Domain DNS
app.get('#/domains/:domain/dns', function (c) {
c.api('/domains/' + c.params['domain'] + '/dns', function(data) {
domain = {
var domain = {
name: c.params['domain'],
dns: data
}
};
c.view('domain/domain_dns', domain);
});
});
@ -122,16 +125,15 @@
app.get('#/domains/:domain/cert-management', function (c) {
c.api('/domains/cert-status/' + c.params['domain'] + '?full', function(data) {
s = data["certificates"][c.params['domain']]
var s = data["certificates"][c.params['domain']];
var status_ = {
CA_type: s.CA_type.verbose,
CA_name: s.CA_name,
validity: s.validity,
ACME_eligible: s.ACME_eligible
};
status_ = {}
status_.CA_type = s.CA_type.verbose
status_.CA_name = s.CA_name
status_.validity = s.validity
status_.ACME_eligible = s.ACME_eligible
switch (s.summary.code)
{
switch (s.summary.code) {
case "critical" :
status_.alert_type = "danger";
status_.alert_icon = "exclamation-circle" ;
@ -143,14 +145,12 @@
status_.alert_message = y18n.t('certificate_alert_selfsigned');
break;
case "attention" :
if (status_.CA_type == "lets-encrypt")
{
if (status_.CA_type == "lets-encrypt") {
status_.alert_type = "warning";
status_.alert_icon = "clock-o";
status_.alert_message = y18n.t('certificate_alert_letsencrypt_about_to_expire');
}
else
{
else {
status_.alert_type = "danger";
status_.alert_icon = "clock-o";
status_.alert_message = y18n.t('certificate_alert_about_to_expire');
@ -173,14 +173,14 @@
break;
}
actions_enabled = {};
actions_enabled.install_letsencrypt = false;
actions_enabled.manual_renew_letsencrpt = false;
actions_enabled.regen_selfsigned = false;
actions_enabled.replace_with_selfsigned = false;
var actions_enabled = {
install_letsencrypt: false,
manual_renew_letsencrpt: false,
regen_selfsigned: false,
replace_with_selfsigned: false
};
switch (s.CA_type.code)
{
switch (s.CA_type.code) {
case "self-signed" :
actions_enabled.install_letsencrypt = true;
actions_enabled.regen_selfsigned = true;
@ -305,14 +305,16 @@
y18n.t('domains'),
y18n.t('confirm_change_maindomain'),
function(){
params = {'new_domain': c.params['domain']};
var params = {
new_domain: c.params['domain']
};
c.api('/domains/main', function(data) { // http://api.yunohost.org/#!/tools/tools_maindomain_put_1
store.clear('slide');
c.redirect('#/domains');
}, 'PUT', params);
// Wait 15s and refresh the page
refreshDomain = window.setTimeout(function(){
var refreshDomain = window.setTimeout(function(){
store.clear('slide');
c.redirect('#/domains');
}, 15000);

View file

@ -12,8 +12,8 @@
app.get('#/tools/firewall', function (c) {
c.api('/firewall?raw', function(data) {
var firewall = {
ports : {},
upnp : false
ports: {},
upnp: false
};
// Reorganize ports
@ -41,7 +41,9 @@
// confirm_upnp_enable and confirm_upnp_disable
y18n.t('confirm_upnp_' + c.params['action'].toLowerCase()),
function(){
params = {'action' : c.params['action']};
var params = {
action : c.params['action']
};
c.api('/firewall/upnp', function(data) {
store.clear('slide');
c.redirect('#/tools/firewall');
@ -57,8 +59,8 @@
// Toggle port status helper (available in every controller)
app.helper('togglePort', function(port, protocol, connection, action) {
var method = null,
endurl = [],
c = this
endurl = [],
c = this
;
if (port != parseInt(port) || port < 0 || port > 65535) {
@ -110,8 +112,8 @@
// --ipv6-only:
// --no-upnp:
var params = {
'port' : port,
'protocol' : protocol,
port : port,
protocol : protocol
};
c.api('/firewall/port?'+endurl, function(data) {
store.clear('slide');

View file

@ -35,9 +35,10 @@
// Loop through items in a reverse order (older first)
$($('item', xml).get().reverse()).each(function(k, v) {
var link=$('link', v).text();
if (typeof link == 'string' && link !== '' && link.charAt(0) == '/')
link=forumUrl+link;
var link = $('link', v).text();
if (typeof link == 'string' && link !== '' && link.charAt(0) == '/') {
link = forumUrl+link;
}
// var description=$('description', v).text();
// description=description.replace('href="/','href="'+forumUrl+'/');
@ -70,6 +71,13 @@
c.flash('fail', y18n.t('error_retrieve_feed', [securityFeed]));
});
c.api("/diagnosis", function(data) {
console.log(data);
if (data.security["CVE-2017-5754"].vulnerable) {
c.flash('danger', y18n.t('meltdown'));
}
});
c.view('home');
});
});
@ -138,8 +146,8 @@
// Store url from params, it could have change form 'run' state
store.set('url', c.params['domain'] +'/yunohost/api');
params = {
'password': c.params['password']
var params = {
password: c.params['password']
};
c.api('/login', function(data) {
store.set('connected', true);

View file

@ -10,7 +10,7 @@
// Server monitoring
app.get('#/tools/monitor', function (c) {
monitorData = {};
var monitorData = {};
// Why this method ?
c.api('/services/glances', function(data) { // ?

View file

@ -25,10 +25,10 @@
$('#masthead').hide();
$.get('https://dyndns.yunohost.org/domains', function() {})
.done(function(data){
c.params.ddomains = data.map(function(dom){return '.'+dom;});
c.params['ddomains'] = data.map(function(dom){return '.'+dom;});
})
.fail(function() {
c.params.ddomains = ['.nohost.me', '.noho.st'];
c.params['ddomains'] = ['.nohost.me', '.noho.st'];
})
.always(function() {
c.view('postinstall/postinstall_2', c.params, function() {
@ -77,14 +77,16 @@
store.clear('slide');
c.redirect('#/postinstall/domain');
} else {
params = { 'domain': c.params['domain'].toLowerCase() };
var params = {
domain: c.params['domain'].toLowerCase()
};
}
c.confirm(
y18n.t('postinstall'),
y18n.t('confirm_postinstall', [c.params['domain']]),
function(){
params['password'] = c.params['password'];
params.password = c.params['password'];
store.set('url', window.location.hostname +'/yunohost/api');
store.set('user', 'admin');

View file

@ -11,7 +11,9 @@
// All services status
app.get('#/services', function (c) {
c.api('/services', function(data) { // ?
data2 = { 'services': [] };
var data2 = {
services: []
};
$.each(data, function(k, v) {
v.name = k;
// Handlebars want booleans
@ -29,7 +31,9 @@
// Status & actions for a service
app.get('#/services/:service', function (c) {
c.api('/services/'+ c.params['service'], function(data) { // ?
data2 = { 'service': data };
var data2 = {
service: data
};
data2.service.name = c.params['service'];
// Handlebars want booleans
data2.service.is_loaded = (data.loaded=='enabled') ? true : false;
@ -44,7 +48,9 @@
// Service log
app.get('#/services/:service/log', function (c) {
params = { 'number': 50 };
var params = {
number: 50
};
c.api('/services/'+ c.params['service'] +'/log', function(data) { // ?
data2 = { 'logs': [], 'name': c.params['service'] };
$.each(data, function(k, v) {
@ -62,7 +68,8 @@
// confirm_service_start, confirm_service_stop, confirm_service_enable and confirm_service_disable
y18n.t('confirm_service_' + c.params['action'].toLowerCase(), [c.params['service']]),
function(){
var method = null, endurl = c.params['service'];
var method = null,
endurl = c.params['service'];
switch (c.params['action']) {
case 'start':

View file

@ -20,7 +20,7 @@
// Update administration password (PUT)
app.put('#/tools/adminpw', function (c) {
params = {};
var params = {};
$.each(c.params.toHash(), function(key, value) {
if (value !== '') { params[key] = value; }
});
@ -49,7 +49,7 @@
// System update & upgrade
app.get('#/update', function (c) {
c.api('/update', function(data) {
packagesLength = data.packages.length;
var packagesLength = data.packages.length;
for(var i = 0; i < packagesLength; i++) {
data.packages[i].delayed = false;
data.packages[i].changelog = data.packages[i].changelog.replace(/\n/g, '<br />');
@ -77,7 +77,7 @@
// confirm_update_apps and confirm_update_packages
y18n.t('confirm_update_' + c.params['type'].toLowerCase()),
function(){
endurl = '';
var endurl = '';
if (c.params['type'] == 'packages') {endurl = 'ignore_apps';}
else if (c.params['type'] == 'apps') {endurl = 'ignore_packages';}
@ -96,6 +96,27 @@
}
});
// Upgrade a specific apps
app.get('#/upgrade/apps/:app', function (c) {
c.confirm(
y18n.t('tools'),
y18n.t('confirm_update_specific_app', [c.params['app']]),
function(){
c.api('/upgrade/apps?app='+c.params['app'].toLowerCase(),
function(data) {
// 'log' is a reserved name, maybe in handlebars
data.logs = data.log;
c.view('upgrade/upgrade', data);
}, 'PUT');
},
function(){
store.clear('slide');
c.redirect('#/update');
}
);
});
// Download SSL Certificate Authority
app.get('#/tools/ca', function (c) {
c.view('tools/tools_ca');
@ -103,7 +124,7 @@
// Security feed
app.get('#/tools/security-feed', function (c) {
data = {
var data = {
items: []
};
@ -125,11 +146,12 @@
.done(function(xml){
// Loop through items
$('item', xml).each(function(k, v) {
var link=$('link', v)[0].innerHTML;
if (typeof link == 'string' && link !== '' && link.charAt(0) == '/')
link=forumUrl+link;
var description=$('description', v)[0].textContent;
description=description.replace('href="/','href="'+forumUrl+'/');
var link = $('link', v)[0].innerHTML;
if (typeof link == 'string' && link !== '' && link.charAt(0) == '/') {
link = forumUrl+link;
}
var description = $('description', v)[0].textContent;
description = description.replace('href="/','href="'+forumUrl+'/');
var item = {
guid: $('guid', v)[0].innerHTML,
@ -156,12 +178,69 @@
});
});
// 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
app.get('#/tools/diagnosis(/:private)?', function (c) {
// See http://sammyjs.org/docs/routes for splat documentation
private = (c.params.splat[0] == 'private');
var private = (c.params.splat[0] == 'private');
endurl = (private) ? '?private' : '';
var endurl = (private) ? '?private' : '';
c.api('/diagnosis'+endurl, function(diagnosis) {
c.view('tools/tools_diagnosis', {
'diagnosis' : JSON.stringify(diagnosis, undefined, 4),

View file

@ -79,7 +79,7 @@
data.password_min_length = PASSWORD_MIN_LENGTH;
// User email use a fake splitted field
email = data.mail.split('@');
var email = data.mail.split('@');
data.email = {
username : email[0],
domain : email[1]
@ -156,7 +156,7 @@
c.params['mailalias'] = c.params['mailforward'] = '';
// Remove empty inputs
params = {};
var params = {};
$.each(c.params.toHash(), function(key, value) {
if (value.length > 0 && key !== 'user') { params[key] = value; }
});

View file

@ -9,7 +9,7 @@
*/
app.bind('login', function(e, data) {
this.api('/version', function(versions) {
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost]));
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost.version, versions.yunohost.repo]));
});
});

View file

@ -62,10 +62,10 @@
},
// API call
api: function(uri, callback, method, data, websocket) {
api: function(uri, callback, method, data, websocket, callbackOnFailure) {
c = this;
call = function(uri, callback, method, data) {
call = function(uri, callback, method, data, callbackOnFailure) {
method = typeof method !== 'undefined' ? method : 'GET';
data = typeof data !== 'undefined' ? data : {};
if (window.navigator && window.navigator.language && (typeof data.locale === 'undefined')) {
@ -80,10 +80,75 @@
}, 1500);
}
loaded = false;
app.loaded = false;
if ($('div.loader').length === 0) {
$('#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({
url: 'https://' + store.get('url') + uri,
@ -99,69 +164,14 @@
data = data || {};
callback(data);
})
.fail(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');
}
}
// 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');
}
});
.fail(callbackOnFailure);
};
websocket = typeof websocket !== 'undefined' ? websocket : true;
if (websocket) {
// Open a WebSocket connection to retrieve live messages from the moulinette
ws = new WebSocket('wss://'+ store.get('url') +'/messages');
var ws = new WebSocket('wss://'+ store.get('url') +'/messages');
ws.onmessage = function(evt) {
// console.log(evt.data);
$.each($.parseJSON(evt.data), function(k, v) {
@ -174,9 +184,9 @@
ws.onclose = function() {};
ws.onopen = call(uri, callback, method, data);
ws.onopen = call(uri, callback, method, data, callbackOnFailure);
} else {
call(uri, callback, method, data);
call(uri, callback, method, data, callbackOnFailure);
}
},
@ -189,14 +199,14 @@
callback = typeof callback !== 'undefined' ? callback : function() {};
enableSlide = (typeof enableSlide !== 'undefined') ? enableSlide : true; // Change to false to disable animation
loaded = true;
app.loaded = true;
// Hide loader and modal
$('div.loader').remove();
$('#modal').modal('hide');
// Render content
rendered = this.render('views/'+ view +'.ms', data);
var rendered = this.render('views/'+ view +'.ms', data);
// Update content helper
var leSwap = function() {
@ -254,7 +264,7 @@
cancelCallback = typeof cancelCallback !== 'undefined' ? cancelCallback : function() {};
// Get modal element
box = $('#modal');
var box = $('#modal');
// Modal title
if (typeof title === 'string' && title.length) {
@ -312,8 +322,8 @@
},
groupHooks: function(hooks) {
data={};
var rules=[
var data = {};
var rules = [
{
id:'configuration',
isIn:function (hook) {
@ -350,7 +360,7 @@
},
ungroupHooks: function(hooks,apps) {
var data={};
var data = {};
data['apps'] = apps || [];
data['hooks'] = hooks || [];

View file

@ -42,6 +42,23 @@
return new Handlebars.SafeString(result);
});
// Block helper to add a tooltip to any element
Handlebars.registerHelper('tooltip', function(tooltip, options) {
return new Handlebars.SafeString(
'<span data-toggle="tooltip" title="' + tooltip + '" data-placement="right">'
+ options.fn(this)
+ '</span>');
});
// Load tooltips on the page; needed if using tooltips
Handlebars.registerHelper('load_tooltips', function() {
return new Handlebars.SafeString(
'<script>'
+ '$(document).ready(function(){'
+ '$(\'[data-toggle="tooltip"]\').tooltip();'
+ '});'
+ '</script>');
});
// Look for supported type of storage to use
/**
@ -77,7 +94,7 @@
// Get YunoHost version
if (sam.store.get('connected')) {
this.api('/version', function(versions) {
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost]));
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost.version, versions.yunohost.repo]));
});
}

View file

@ -6,7 +6,7 @@
defaultLocale: "en",
locale: "en",
placeholder: /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm,
translations: {},
translations: {}
};
/**

View file

@ -335,5 +335,34 @@
"confirm_upnp_enable": "Möchtest du wirklich UPnP aktivieren?",
"confirm_upnp_disable": "Möchtest du wirklich UPnP deaktivieren?",
"confirm_firewall_open": "Möchtest du wirklich Port %s1 öffnen? (Protokoll: %s2, Verbindung: %s3)",
"confirm_firewall_close": "Möchtest du wirklich Port %s1 schließen? (Protokoll: %s2, Verbindung: %s3)"
"confirm_firewall_close": "Möchtest du wirklich Port %s1 schließen? (Protokoll: %s2, Verbindung: %s3)",
"remove": "Entfernen",
"confirm_update_specific_app": "Möchtest du wirklich %s aktualisieren?",
"confirm_reboot_action_reboot": "Möchtest du wirklich den Server neustarten?",
"confirm_reboot_action_shutdown": "Möchtest du wirklich den Server herunterfahren?",
"domain_dns_conf_is_just_a_recommendation": "Diese Seite zeigt dir die *empfohlene* Konfiguration. Sie konfiguriert *nicht* den DNS für dich. Es liegt in deiner Verantwortung, deine Zone bei deinem Registrar entsprechend dieser Empfehlung zu konfigurieren.",
"ok": "OK",
"system_upgrade_all_applications_btn": "Aktualisiere alle Applikationen",
"system_upgrade_all_packages_btn": "Aktualisiere alle Pakete",
"tools_reboot": "Starte deine Server neu",
"tools_reboot_btn": "Neustart",
"tools_reboot_done": "Starte neu...",
"tools_rebooting": "Dein Server startet neu. Um zur Verwaltungsoberfläche zurückzukehren, musst du warten bis der Server hochgefahren ist. Feststellen kannst du es, in dem du die Seite neu lädst.",
"tools_shutdown": "Fahre deinen Server herunter",
"tools_shutdown_btn": "Herunterfahren",
"tools_shutdown_done": "Fahre herunter...",
"tools_shuttingdown": "Dein Server wird heruntergefahren. Solange dein Server ausgeschaltet ist, kannst du das Verwaltungsoberfläche nicht benutzen.",
"tools_shutdown_reboot": "Herunterfahren/Neustarten",
"appslists": "Applikationslisten",
"appslists_no_lists": "Keine Applikationslisten",
"appslists_custom": "Eigene Applikationslisten",
"appslists_manage": "Verwalte Applikationslisten",
"appslists_confirm_remove": "Möchtest du wirklich diese Applikationsliste entfernen?",
"appslists_info_refresh_desc": "Aktualisiere die Paketinformationen für diese Liste.",
"appslists_info_remove_desc": "Applikationen aus dieser Liste werden nicht mehr verfügbar sein.",
"appslists_last_update": "Letzte Aktualisierung",
"appslists_unknown_list": "Die Liste %s ist unbekannt",
"appslists_community_list": "Applikationsliste der Community",
"name": "Name",
"install_community_appslists_warning": "Nimm zur Kenntnis, dass diese Applikationen <strong>nicht</strong> offiziell sind und nicht von YunoHost gepflegt werden.<br /> Diese Applikationen sind auf eigenes Risiko zu installieren und können dein System demolieren."
}

View file

@ -14,12 +14,15 @@
"app_access_removeall_desc": "No users will have access to %s.",
"app_access_title": "%s access",
"app_change_label": "Change Label",
"app_change_url": "Change URL",
"app_debug_no_logs": "Application's logs are not available",
"app_debug_tab": "Display debug information",
"app_info_access_desc": "Manage user access. Allowed users: %s",
"app_info_changelabel_desc": "Change app label in the portal.",
"app_info_debug_desc": "Display debugging information for this application.",
"app_info_default_desc": "Redirect domain root to this application (%s).",
"app_info_changeurl_desc": "Change the access URL of this application (domain and/or path).",
"app_info_change_url_disabled_tooltip": "This feature hasn't been implemented in this app yet",
"app_info_uninstall_desc": "Remove this application.",
"app_install_cancel": "Installation cancelled.",
"app_install_custom_no_manifest": "No manifest.json file",
@ -62,6 +65,7 @@
"confirm_access_clear": "Are you sure you want to clear all access to %s ?",
"confirm_access_remove_all": "Are you sure you want to remove all access to %s ?",
"confirm_access_remove_user": "Are you sure you want to remove access to %s for %s ?",
"confirm_app_change_url": "Are you sure you want to change the app access URL ?",
"confirm_app_default": "Are you sure you want to make this app default ?",
"confirm_change_maindomain": "Are you sure you want to change the main domain ?",
"confirm_delete": "Are you sure you want to delete %s ?",
@ -78,8 +82,11 @@
"confirm_uninstall": "Are you sure you want to uninstall %s ?",
"confirm_update_apps": "Are you sure you want to update all applications?",
"confirm_update_packages": "Are you sure you want to update all packages?",
"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_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",
"copy": "Copy",
"count_min": "%s min",
@ -91,6 +98,7 @@
"default": "Default",
"delete": "Delete",
"description": "Description",
"domain_dns_conf_is_just_a_recommendation": "This page shows you the *recommended* configuration. It does *not* configure the DNS for you. It is your responsability to configure your DNS zone in your DNS registrar according to this recommendation.",
"diagnosis": "Diagnosis",
"diagnosis_hide_private": "Show diagnostic information without private data",
"diagnosis_view_private": "Show diagnostic information including private data",
@ -129,7 +137,7 @@
"everyone_has_access": "Everyone has access.",
"filesystem": "Filesystem",
"firewall": "Firewall",
"footer_version" : "Powered by <a href='https://yunohost.org'>YunoHost</a> %s.",
"footer_version" : "Powered by <a href='https://yunohost.org'>YunoHost</a> %s (%s).",
"form_input_example" : "Example: %s",
"free": "Free",
"fs_type": "FS Type",
@ -161,6 +169,7 @@
"installed_apps": "Installed apps",
"installing": "Installing",
"interface": "Interface",
"internal_exception": "<strong>Yunohost encountered an internal error :/</strong><br><em>Really sorry about that.<br>You should look for help on <a href=\"https://forum.yunohost.org/\">the forum</a> or <a href=\"https://chat.yunohost.org/\">the chat</a> to fix the situation, or report the bug on <a href=\"https://dev.yunohost.org/projects/yunohost/issues\">the bugtracker</a>.</em><br>The following information might be useful for the person helping you :<h3>Action</h3><pre>%s%s</pre><h3>Traceback</h3><pre>%s</pre>",
"io": "I/O",
"ipv4": "IPv4",
"ipv6": "IPv6",
@ -197,6 +206,7 @@
"no_log": "No log.",
"no_user_to_add": "No more users to add.",
"non_compatible_api": "Non-compatible API",
"ok": "OK",
"open": "Open",
"operations": "Operations",
"os": "OS",
@ -208,6 +218,7 @@
"passwords_dont_match": "Passwords don't match",
"passwords_too_short": "Password is too short",
"path": "Path",
"path_url": "Path",
"port": "Port",
"ports": "Ports",
"postinstall": "Post-installation",
@ -254,6 +265,8 @@
"system_update": "System update",
"system_upgrade": "System upgrade",
"system_upgrade_btn": "Upgrade",
"system_upgrade_all_applications_btn": "Upgrade all applications",
"system_upgrade_all_packages_btn": "Upgrade all packages",
"tcp": "TCP",
"time_since_update": "Time since update: ",
"tools": "Tools",
@ -268,6 +281,15 @@
"tools_security_feed_no_items": "No security notifications",
"tools_security_feed_subscribe_rss": "Subscribe to security notifications RSS",
"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",
"transmission": "Transmission",
"udp": "UDP",
@ -328,6 +350,7 @@
"install_letsencrypt_cert" : "Install a Let's Encrypt certificate",
"manually_renew_letsencrypt_message" : "Certificate will be automatically renewed during the last 15 days of validity. You can manually renew it if you want to. (Not recommended).",
"manually_renew_letsencrypt" : "Manually renew now",
"meltdown" : "You are vulnerable to the <a target=\"_blank\" href=\"https://meltdownattack.com/\">meltdown</a> critical security vulnerability. To fix that, you need to <a href=\"#/update\">update your system</a> then <a href=\"#/tools/reboot\">reboot it</a> to load the new linux kernel.",
"regenerate_selfsigned_cert_message" : "If you want, you can regenerate the self-signed certificate.",
"regenerate_selfsigned_cert" : "Regenerate self-signed certificate",
"revert_to_selfsigned_cert_message" : "If you really want to, you can reinstall a self-signed certificate. (Not recommended)",
@ -347,4 +370,3 @@
"install_community_appslists_warning" : "Note that these applications packages are <strong>not</strong> official and not maintained by the YunoHost team.<br />Installing these applications is at your own risk and could break your system.",
"install_custom_app_appslists_info" : "Note that you can use alternative applications lists to install some other apps maintained by the YunoHost community."
}

View file

@ -1 +1,6 @@
{}
{
"password": "Pasvorto",
"login": "Ensaluti",
"logout": "Elsaluti",
"cancel": "Nuligi"
}

View file

@ -296,7 +296,7 @@
"wrong_password": "Mot de passe incorrect",
"yes": "Oui",
"form_input_example": "Exemple : %s",
"footer_version": "Propulsé par <a href='https://yunohost.org'>YunoHost</a> %s.",
"footer_version": "Propulsé par <a href='https://yunohost.org'>YunoHost</a> %s (%s).",
"certificate_alert_not_valid": "Critique : le certificat actuel est invalide ! Le HTTPS ne fonctionnera pas du tout !",
"certificate_alert_selfsigned": "Attention : le certification actuel est auto-signé. Les navigateurs afficheront une alerte effrayante aux nouveaux visiteurs !",
"certificate_alert_letsencrypt_about_to_expire": "Le certificat actuel est sur le point dexpirer. Il doit être renouvelé automatiquement prochainement.",
@ -349,5 +349,22 @@
"name": "Nom",
"install_community_appslists_info": "La liste des applications communautaires vous permet dinstaller les applications maintenues par la communauté. <br />Parcourez la liste complète sur <a href='https://yunohost.org/apps_in_progress'>yunohost.org/apps_in_progress_fr</a>.",
"install_community_appslists_warning": "Ces applications <strong>ne sont ni</strong> officielles, ni maintenues par léquipe YunoHost. <br />Installer ces applications est à vos risques et périls, et peut casser votre système.",
"install_custom_app_appslists_info": "Vous pouvez utiliser des listes alternatives dapplications pour installer dautres applications maintenues par la communauté YunoHost."
"install_custom_app_appslists_info": "Vous pouvez utiliser des listes alternatives dapplications pour installer dautres applications maintenues par la communauté YunoHost.",
"domain_dns_conf_is_just_a_recommendation": "Cette page montre la configuration *recommandée*. Elle ne configure *pas* le DNS pour vous. Il est de votre responsabilité que de configurer votre zone DNS chez votre registrar DNS avec cette recommandation.",
"internal_exception": "<strong>YunoHost a rencontré une erreur interne :/</strong><br><em>Vraiment navré.<br>Vous devriez chercher de laide sur <a href=\"https://forum.yunohost.org/\">le forum</a> ou <a href=\"https://chat.yunohost.org/\">le salon</a> pour résoudre le problème, ou rapporter le bogue sur <a href=\"https://dev.yunohost.org/projects/yunohost/issues\">loutil de suivi</a>.</em><br>Les informations suivantes peuvent être utile à linterlocuteur vous aidant :<h3>Action</h3><pre>%s %s</pre><h3>Trace</h3><pre>%s</pre>",
"confirm_reboot_action_reboot": "Êtes vous sûr de vouloir redémarrer votre serveur ?",
"confirm_reboot_action_shutdown": "Êtes vous sûr de vouloir éteindre votre serveur ?",
"confirm_update_specific_app": "Êtes vous sûr de vouloir mettre à jour %s ?",
"ok": "OK",
"system_upgrade_all_applications_btn": "Mettre à jour toutes les applications",
"system_upgrade_all_packages_btn": "Mettre à jour tous les paquets",
"tools_reboot": "Redémarrer votre serveur",
"tools_reboot_btn": "Redémarrer",
"tools_reboot_done": "Redémarrage...",
"tools_rebooting": "Votre serveur redémarre. Pour retourner sur l'interface d'administration vous devez attendre que votre serveur soit démarré. Pour pouvez vérifier cela en actualisant cette page (F5).",
"tools_shutdown": "Eteindre votre serveur",
"tools_shutdown_btn": "Eteindre",
"tools_shutdown_done": "Arrêt en cours...",
"tools_shuttingdown": "Votre serveur est éteint. Tant que votre serveur est éteint vous ne pouvez plus utiliser l'interface d'administration.",
"tools_shutdown_reboot": "Arrêter/Redémarrer"
}

31
src/locales/ru.json Normal file
View file

@ -0,0 +1,31 @@
{
"action": "Действие",
"add": "Добавить",
"administration_password": "Пароль администратора",
"allowed_users": "Разрешенные пользователи",
"api_not_responding": "API не отвечает",
"app_access": "Доступ",
"app_access_addall_btn": "Включить доступ ко всем",
"app_access_addall_desc": "Все существующие пользователи будут иметь доступ к %s.",
"app_access_clearall_btn": "Очистить доступы",
"app_access_clearall_desc": "Каждый пользователь будет иметь доступ к %s.",
"app_access_removeall_btn": "Удалить все доступы",
"app_access_removeall_desc": "Пользователи не получат доступа к %s.",
"app_access_title": "%s доступ",
"app_debug_no_logs": "Журналы приложений недоступны",
"app_debug_tab": "Отображать отладочную информацию",
"app_info_access_desc": "Управление доступом пользователей. Разрешенные пользователи: %s",
"remove": "Удалить",
"app_info_default_desc": "Перенаправить домен root в это приложение (%s).",
"app_info_uninstall_desc": "Удалите это приложение.",
"app_install_cancel": "Установка отменена.",
"app_install_custom_no_manifest": "Нет файла manifest.json",
"app_list": "Нет файла manifest.json",
"app_make_default": "Использовать по умолчанию",
"app_repository": "Происхождение приложения: ",
"app_state": "Состояние приложения: ",
"app_state_inprogress": "Выполняется",
"app_state_validated": "Проверенный",
"app_state_working": "Работает",
"password": "Пароль"
}

View file

@ -0,0 +1,38 @@
<div class="btn-breadcrumb">
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
<a href="#/apps" class="hidden-xs">{{t 'applications'}}</a>
<a href="#/apps" class="visible-xs">&hellip;</a>
<a href="#/apps/{{id}}">{{label}}</a>
<a href="#/apps/{{id}}/changeurl">{{t 'app_change_url'}}</a>
</div>
<div class="separator"></div>
<form action="#/apps/{{id}}/changeurl" method="POST" class="form-horizontal form-app-install">
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title"><span class="fa-fw fa-exchange"></span> {{t 'app_change_url'}}</h2>
</div>
<div class="panel-body">
<div class="form-group">
<label for="domain" class="col-sm-12">{{t 'domain'}}</label>
<div class="col-sm-12">
<select id="domain" name="domain" required class="form-control" {{{attributes}}}>
{{#each domains}}<option value="{{this.value}}" {{#if selected}}selected{{/if}}>{{this.label}}</option>{{/each}}
</select>
<span class="help-block help-block--link"><a href='#/domains'>{{t 'manage_domains'}}</a></span>
</div>
<label for="path" class="col-sm-12">{{t 'path_url'}}</label>
<div class="col-sm-12">
<input class="col-sm-12" type="text" id="path" name="path" class="form-control" value="{{path}}" required="required">
</div>
</div>
<hr>
<input type="hidden" name="app" value="{{id}}">
<div class="text-center">
<input type="submit" class="btn btn-success slide back" value="{{t 'app_change_url'}}">
</div>
</div>
</div>
</form>

View file

@ -57,6 +57,21 @@
</a>
</div>
<hr>
<div class="container">
<p>{{t 'app_info_changeurl_desc' settings.domain}}</p>
{{#if change_url}}
<a href="#/apps/{{settings.id}}/changeurl" class="btn btn-info slide">
<span class="fa-exchange"></span> {{t 'app_change_url'}}
</a>
{{else}}
{{#tooltip (t 'app_info_change_url_disabled_tooltip') }}
<a href="#/apps/{{settings.id}}/changeurl" class="btn btn-info slide disabled">
<span class="fa-exchange"></span> {{t 'app_change_url'}}
</a>
{{/tooltip}}
{{/if}}
</div>
<hr>
<div class="container">
<p>{{t 'app_info_uninstall_desc'}}</p>
<a href="#/apps/{{settings.id}}/uninstall" class="btn btn-danger slide back">
@ -72,3 +87,4 @@
</div>
</div>
</div>
{{load_tooltips}}

View file

@ -4,9 +4,12 @@
<a href="#/domains/{{name}}">{{name}}</a>
<a href="#/domains/{{name}}/dns">{{t 'dns'}}</a>
</div>
<div class="separator"></div>
<div class="alert alert-warning">
<span class="fa-fw fa-warning"></span> {{t 'domain_dns_conf_is_just_a_recommendation' }}
</div>
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">

View file

@ -31,6 +31,10 @@
<span class="fa-chevron-right pull-right"></span>
<h2 class="list-group-item-heading">{{t 'tools_security_feed'}}</h2>
</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">
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading">{{t 'versions'}}</h2>

View 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>

View file

@ -26,7 +26,7 @@
{{/packages}}
</div>
<div class="panel-footer">
<a href="#/upgrade/packages" class="btn btn-success">{{t 'system_upgrade_btn'}}</a>
<a href="#/upgrade/packages" class="btn btn-success">{{t 'system_upgrade_all_packages_btn'}}</a>
</div>
{{else}}
<div class="panel-body">
@ -42,13 +42,14 @@
{{#if apps}}
<div class="list-group">
{{#apps}}
<div class="list-group-item">
<div class="list-group-item clearfix">
<a href="#/upgrade/apps/{{id}}" class="btn btn-success pull-right">{{t 'system_upgrade_btn'}}</a>
<h3 class="list-group-item-heading">{{label}} <small>{{id}}</small></h3>
</div>
{{/apps}}
</div>
<div class="panel-footer">
<a href="#/upgrade/apps" class="btn btn-success">{{t 'system_upgrade_btn'}}</a>
<a href="#/upgrade/apps" class="btn btn-success">{{t 'system_upgrade_all_applications_btn'}}</a>
</div>
{{else}}
<div class="panel-body">