mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
Merge branch 'stretch-testing' into stretch-stable
This commit is contained in:
commit
3f01bc51b5
70 changed files with 2187 additions and 2626 deletions
|
@ -38,4 +38,4 @@ https://example.com/yunohost/admin/views/domain/domain_list.ms)
|
||||||
* Font-Awesome 4.5.0
|
* Font-Awesome 4.5.0
|
||||||
* Handlebars 1.3.0
|
* Handlebars 1.3.0
|
||||||
* Sammy 0.7.6
|
* Sammy 0.7.6
|
||||||
* Jquery-Cookie 2.1.0
|
* JS-cookie 2.1.0
|
||||||
|
|
76
debian/changelog
vendored
76
debian/changelog
vendored
|
@ -1,3 +1,79 @@
|
||||||
|
yunohost-admin (3.8.3.1) testing; urgency=low
|
||||||
|
|
||||||
|
- Add tip about the diagnosis page if domain seems not ready for ACME (e7a4df1)
|
||||||
|
- Support raw string in 'ask' fields from manifest (for upcoming thing in core about default strings for install questions) (ee20f55)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Sat, 09 May 2020 20:24:00 +0200
|
||||||
|
|
||||||
|
yunohost-admin (3.8.3) testing; urgency=low
|
||||||
|
|
||||||
|
- [enh] Add a note and explanation about sharing the logs when viewing logs of shared operations
|
||||||
|
- [enh] Filter non-relevant line in operation log view
|
||||||
|
- [fix] Remove an unecessary call to app list on domain view
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 07 Apr 2020 04:15:00 +0000
|
||||||
|
|
||||||
|
yunohost-admin (3.8.2) testing; urgency=low
|
||||||
|
|
||||||
|
- [enh] Highlight error/warnings/... in tools > logs (#294)
|
||||||
|
- [enh] Hide stop button for critical services ? (#295)
|
||||||
|
- [fix] Stupid typo in upgrade controller prevented upgrading all apps (a3a0d8f)
|
||||||
|
- [fix] Custom app install + misc detail in regular app install (1592ab4)
|
||||||
|
- [fix] Make the 'all apps' button look like the others (9694d8a)
|
||||||
|
- [mod] Simplify log view (4480836)
|
||||||
|
- [enh] Save/restore collapse states when refreshing diagnosis view (a110e56)
|
||||||
|
- [enh] Add an explanation text on top of the diagnosis view (ccefdd6)
|
||||||
|
- [i18n] Improve translations for Esperanto, Spanish, French, Occitan, Polish, Nepali
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Quentí, Simon, amirale qt)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Wed, 29 Apr 2020 23:20:00 +0000
|
||||||
|
|
||||||
|
yunohost-admin (3.8.1.1) testing; urgency=low
|
||||||
|
|
||||||
|
- [hotfix] Pacman hanging forever after fetching version number..
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 19 Apr 2020 16:20:00 +0000
|
||||||
|
|
||||||
|
yunohost-admin (3.8.1) testing; urgency=low
|
||||||
|
|
||||||
|
- Many small cosmetic and mechanics improvements for the Diagnosis view
|
||||||
|
- Add a 'Restart' button for services
|
||||||
|
- Drop 'Security feed' and 'Download self-CA auth cert' features from the Tools section
|
||||||
|
- Move 'Share on Yunopaste' button to make it more obvious to users (dd2570e)
|
||||||
|
- Display 'All apps' button at the top in app category selector (#291)
|
||||||
|
- Improve translations for French, German, Catalan, Turkish
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Kay0u, Yasin S. T., Zeik0s, E.Gaspar, xaloc33)
|
||||||
|
|
||||||
|
-- Alexandre Aubin <alex.aubin@mailoo.org> Thu, 19 Apr 2020 06:22:00 +0000
|
||||||
|
|
||||||
|
yunohost-admin (3.8.0) testing; urgency=low
|
||||||
|
|
||||||
|
# Major stuff
|
||||||
|
|
||||||
|
- [enh] New diagnosis interface (#209, 109f542, 95f8503, 9e0f2f7, 79839b5)
|
||||||
|
- [enh] App categories (#279)
|
||||||
|
- [enh] Rework service views (#274)
|
||||||
|
|
||||||
|
# Refactoring, cleaning
|
||||||
|
|
||||||
|
- Code refactoring, readability improvements, use buttons instead of links when it's not about changing page (#262, 4f544de, 44c27a5, 6177044)
|
||||||
|
- Remove the whole monitoring / glances stuff (#263)
|
||||||
|
- Remove the appslist system from the webadmin (#264)
|
||||||
|
- Remove app debug button, follow-up of corresponding PR on yunohost core (#271)
|
||||||
|
- Fix slider effect (787204b)
|
||||||
|
- Propagate parameter name change from core when changing domain (#260)
|
||||||
|
|
||||||
|
# i18n
|
||||||
|
|
||||||
|
- String definition / usage tests + cleaning of stale strings (#288)
|
||||||
|
- Update translations for Spanish, Esperanto, Basque, Turkish, Catalan, Hindi, German, Greek, Dutch, Polish, Portuguese, Chinese (Simplified), Nepali, French, Occitan,Italian, Bengali (Bangladesh), Hungarian
|
||||||
|
|
||||||
|
Thanks to all contributors <3 ! (Abdulkadir F. Ş., Aeris One, Aleks, Armando F. Bram, Giovanni G. Gustavo M., Hem S., Jeroen F., Juan, Kay0u, Patrick B., Quentí, Yifei D., advocatux, amirale qt, Elie G., frju365, ppr, Romain R., xaloc3)
|
||||||
|
|
||||||
|
-- Kay0u <pierre@kayou.io> Thu, 09 Apr 2020 20:18:35 +0000
|
||||||
|
|
||||||
yunohost-admin (3.7.1.1) stable; urgency=low
|
yunohost-admin (3.7.1.1) stable; urgency=low
|
||||||
|
|
||||||
- [fix] Aleks forgot to properly fix the conflicts in oc.json ~.~
|
- [fix] Aleks forgot to properly fix the conflicts in oc.json ~.~
|
||||||
|
|
2
debian/control
vendored
2
debian/control
vendored
|
@ -12,7 +12,7 @@ Architecture: all
|
||||||
Conflicts: yunohost-apps-admin
|
Conflicts: yunohost-apps-admin
|
||||||
Replaces: yunohost-apps-admin
|
Replaces: yunohost-apps-admin
|
||||||
Depends: ${misc:Depends}
|
Depends: ${misc:Depends}
|
||||||
, yunohost (>= 3.7)
|
, yunohost (>= 3.8)
|
||||||
Description: web administration interface for yunohost
|
Description: web administration interface for yunohost
|
||||||
YunoHost aims to make self-hosting accessible to everyone. It configures
|
YunoHost aims to make self-hosting accessible to everyone. It configures
|
||||||
an email, Web and IM server alongside a LDAP base. It also provides
|
an email, Web and IM server alongside a LDAP base. It also provides
|
||||||
|
|
|
@ -81,7 +81,7 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn {
|
.btn {
|
||||||
& + .btn {margin-left: 8px;}
|
& + .btn {margin-left: 8px; margin-right: 8px;}
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
&:extend(.btn all);
|
&:extend(.btn all);
|
||||||
|
@ -101,10 +101,6 @@ button {
|
||||||
color: transparent;
|
color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
|
||||||
border-radius: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The top heading of the doc
|
* The top heading of the doc
|
||||||
*
|
*
|
||||||
|
@ -229,8 +225,7 @@ button {
|
||||||
.clearfix;
|
.clearfix;
|
||||||
.make-row(12);
|
.make-row(12);
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
padding-top: 20px;
|
padding-top: 10px;
|
||||||
margin-top: 40px;
|
|
||||||
border-top: 1px solid #eee;
|
border-top: 1px solid #eee;
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
@ -641,13 +636,18 @@ input[type='radio'].nice-radio {
|
||||||
background-color: darkorchid;
|
background-color: darkorchid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-category-card {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
// only one card for small screens
|
// only one card for small screens
|
||||||
.app-card {
|
.app-card, .app-category-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.btn-group {
|
.btn-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.btn{
|
.btn{
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -663,13 +663,16 @@ input[type='radio'].nice-radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-state {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.app-title {
|
.app-title, .app-category-title {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-card-desc {
|
.app-card-desc, .app-category-card-desc {
|
||||||
height: 6rem;
|
height: 6rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@ -680,6 +683,7 @@ input[type='radio'].nice-radio {
|
||||||
margin-bottom: 3px;
|
margin-bottom: 3px;
|
||||||
margin-right: 7px;
|
margin-right: 7px;
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
|
height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-width {
|
.auto-width {
|
||||||
|
@ -696,6 +700,7 @@ input[type='radio'].nice-radio {
|
||||||
|
|
||||||
.app-card .panel-body {
|
.app-card .panel-body {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
@ -707,19 +712,49 @@ input[type='radio'].nice-radio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-category-card .panel-body {
|
||||||
|
padding: 2em;
|
||||||
|
height: 10em;
|
||||||
|
color: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtag-selector {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-card {
|
||||||
|
text-decoration: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-card:hover {
|
||||||
|
border-color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-title {
|
||||||
|
line-height: 1em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-category-card-desc {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Groups View **/
|
/** Groups View **/
|
||||||
#view-groups {
|
#view-groups {
|
||||||
.panel-heading a {
|
.panel-heading a {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
&.group-delete {
|
}
|
||||||
|
.group-delete {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
padding: 0;
|
||||||
float:right;
|
float:right;
|
||||||
color:lighten(@label-danger-bg, 20%);
|
color:lighten(@label-danger-bg, 20%);
|
||||||
:hover {
|
:hover {
|
||||||
color:@label-danger-bg;
|
color:@label-danger-bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
.panel-body {
|
.panel-body {
|
||||||
h3 {
|
h3 {
|
||||||
margin-top:0;
|
margin-top:0;
|
||||||
|
@ -731,6 +766,10 @@ input[type='radio'].nice-radio {
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
max-height: 200px;
|
max-height: 200px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.label-removable {
|
.label-removable {
|
||||||
// The following match properties from regular btn's
|
// The following match properties from regular btn's
|
||||||
|
@ -749,15 +788,18 @@ input[type='radio'].nice-radio {
|
||||||
|
|
||||||
margin-right:7px; // Spacing between labels
|
margin-right:7px; // Spacing between labels
|
||||||
|
|
||||||
> a {
|
> button {
|
||||||
|
line-height: 12px;
|
||||||
margin-left:6px;
|
margin-left:6px;
|
||||||
|
padding: 0;
|
||||||
padding-left:6px;
|
padding-left:6px;
|
||||||
border-left: #ccc 1px solid;
|
border-left: #ccc 1px solid;
|
||||||
color:lighten(@label-info-bg,20);
|
color:lighten(@label-info-bg,20);
|
||||||
|
background-color:transparent;
|
||||||
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
> a:hover {
|
> button:hover {
|
||||||
color:@label-info-bg;
|
color:@label-info-bg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,7 +849,7 @@ input[type='radio'].nice-radio {
|
||||||
}
|
}
|
||||||
|
|
||||||
// display 2 cards between 640 and 992px
|
// display 2 cards between 640 and 992px
|
||||||
.app-card {
|
.app-card, .app-category-card {
|
||||||
width: 47.9%;
|
width: 47.9%;
|
||||||
margin: 1%;
|
margin: 1%;
|
||||||
}
|
}
|
||||||
|
@ -909,7 +951,7 @@ input[type='radio'].nice-radio {
|
||||||
|
|
||||||
// bootstrap breakpoint for large screen is 992px
|
// bootstrap breakpoint for large screen is 992px
|
||||||
@media screen and (min-width: 992px) {
|
@media screen and (min-width: 992px) {
|
||||||
.app-card {
|
.app-card, .app-category-card {
|
||||||
// display 3 cards by row
|
// display 3 cards by row
|
||||||
width: 31.3%;
|
width: 31.3%;
|
||||||
margin: 1%;
|
margin: 1%;
|
||||||
|
@ -931,3 +973,58 @@ input[type='radio'].nice-radio {
|
||||||
float: none !important;
|
float: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notransition {
|
||||||
|
-webkit-transition: none !important;
|
||||||
|
-moz-transition: none !important;
|
||||||
|
-o-transition: none !important;
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Diagnosis styles */
|
||||||
|
|
||||||
|
.alert-success-yo {
|
||||||
|
background-color: #dff0d8;
|
||||||
|
border-color: #d6e9c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-warning-yo {
|
||||||
|
background-color: #fcf8e3;
|
||||||
|
border-color: #faebcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-danger-yo {
|
||||||
|
background-color: #f2dede;
|
||||||
|
border-color: #ebccd1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-info-yo {
|
||||||
|
background-color: #d9edf7;
|
||||||
|
border-color: #bce8f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-ignored-yo {
|
||||||
|
background-color: ghostwhite;
|
||||||
|
border-color: lightgrey;
|
||||||
|
color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diagnosis-item {
|
||||||
|
|
||||||
|
code {
|
||||||
|
word-break: break-all;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding-top: 1px;
|
||||||
|
padding-bottom: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
code.cmd {
|
||||||
|
word-break: break-word;
|
||||||
|
color: white;
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul > li {
|
||||||
|
padding-top: 0.3em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -81,8 +81,8 @@
|
||||||
</header>
|
</header>
|
||||||
<div class="content"></div>
|
<div class="content"></div>
|
||||||
<footer>
|
<footer>
|
||||||
<button type="button" id="modal-cancel" data-action="cancel" data-y18n="cancel">Cancel</button>
|
<button type="button" id="modal-cancel" data-modal-action="cancel" data-y18n="cancel">Cancel</button>
|
||||||
<button type="button" id="modal-confirm" data-action="confirm" data-y18n="ok">OK</button>
|
<button type="button" id="modal-confirm" data-modal-action="confirm" data-y18n="ok">OK</button>
|
||||||
</footer>
|
</footer>
|
||||||
</div></div>
|
</div></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
// List installed apps
|
// List installed apps
|
||||||
app.get('#/apps', function (c) {
|
app.get('#/apps', function (c) {
|
||||||
c.api('/apps?installed', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
|
c.api('GET', '/apps?full', {}, function(data) {
|
||||||
var apps = data['apps'];
|
var apps = data['apps'];
|
||||||
c.arraySortById(apps);
|
c.arraySortById(apps);
|
||||||
c.view('app/app_list', {apps: apps});
|
c.view('app/app_list', {apps: apps});
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return 'success';
|
return 'info';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,13 +107,35 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List available apps
|
|
||||||
app.get('#/apps/install', function (c) {
|
// Display catalog home page where users chooses to browse a specific category
|
||||||
c.api('/apps', function (data) { // http://api.yunohost.org/#!/app/app_list_get_8
|
app.get('#/apps/catalog', function (c) {
|
||||||
c.api('/apps?raw', function (dataraw) { // http://api.yunohost.org/#!/app/app_list_get_8
|
c.api('GET', '/appscatalog?full&with_categories', {}, function (data) {
|
||||||
var apps = []
|
c.view('app/app_catalog_home', {categories: data["categories"]}, function() {
|
||||||
$.each(data['apps'], function(k, v) {
|
// Configure layout / rendering for app-category-cards
|
||||||
app = dataraw[v['id']];
|
$('#category-selector').isotope({
|
||||||
|
itemSelector: '.app-category-card',
|
||||||
|
layoutMode: 'fitRows',
|
||||||
|
transitionDuration: 200
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display app catalog for a specific category
|
||||||
|
app.get('#/apps/catalog/:category', function (c) {
|
||||||
|
var category_id = c.params['category'];
|
||||||
|
c.api('GET', '/appscatalog?full&with_categories', {}, function (data) {
|
||||||
|
var apps = [];
|
||||||
|
$.each(data['apps'], function(name, app) {
|
||||||
|
|
||||||
|
// Ignore not working apps
|
||||||
|
if (app.state === 'notworking') { return; }
|
||||||
|
|
||||||
|
// Ignore apps not in this category
|
||||||
|
if ((category_id !== "all") && (app.category !== category_id)) { return; }
|
||||||
|
|
||||||
|
app.id = app.manifest.id;
|
||||||
app.level = parseInt(app.level);
|
app.level = parseInt(app.level);
|
||||||
|
|
||||||
if (app.high_quality && app.level > 7)
|
if (app.high_quality && app.level > 7)
|
||||||
|
@ -132,10 +154,7 @@
|
||||||
app.manifest.maintainer = extractMaintainer(app.manifest);
|
app.manifest.maintainer = extractMaintainer(app.manifest);
|
||||||
var isWorking = (app.state === 'working' || app.state === "high-quality") && app.level > 0;
|
var isWorking = (app.state === 'working' || app.state === "high-quality") && app.level > 0;
|
||||||
|
|
||||||
// Keep only the first instance of each app and remove not working apps
|
app.installable = (!app.installed || app.manifest.multi_instance)
|
||||||
if (!v['id'].match(/__[0-9]{1,5}$/) && (app.state !== 'notworking')) {
|
|
||||||
|
|
||||||
app.installable = (!v.installed || app.manifest.multi_instance)
|
|
||||||
app.levelFormatted = isNaN(app.level) ? '?' : app.level;
|
app.levelFormatted = isNaN(app.level) ? '?' : app.level;
|
||||||
|
|
||||||
app.levelColor = levelToColor(app.level);
|
app.levelColor = levelToColor(app.level);
|
||||||
|
@ -149,60 +168,101 @@
|
||||||
app.isHighQuality = (app.state === "high-quality") ? "isHighQuality" : "";
|
app.isHighQuality = (app.state === "high-quality") ? "isHighQuality" : "";
|
||||||
app.decentQuality = (app.level > 4)?"decentQuality":"badQuality";
|
app.decentQuality = (app.level > 4)?"decentQuality":"badQuality";
|
||||||
|
|
||||||
jQuery.extend(app, v);
|
|
||||||
apps.push(app);
|
apps.push(app);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var category = undefined;
|
||||||
|
$.each(data['categories'], function(i, this_category) {
|
||||||
|
if (this_category.id === category_id) { category = this_category; }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (category_id === "all") {
|
||||||
|
category = {title: y18n.t("all_apps"), icon: "search"};
|
||||||
|
}
|
||||||
|
|
||||||
// Sort app list
|
// Sort app list
|
||||||
c.arraySortById(apps);
|
c.arraySortById(apps);
|
||||||
|
|
||||||
// setup filtering of apps once the view is loaded
|
// setup filtering of apps once the view is loaded
|
||||||
function setupFilterEvents () {
|
function setupFilterEvents () {
|
||||||
// Uses plugin isotope to filter apps (we could had ordering to)
|
// Uses plugin isotope to filter apps (we could had ordering to)
|
||||||
var cardGrid = jQuery('.grid').isotope({
|
var cardGrid = jQuery('#apps').isotope({
|
||||||
itemSelector: '.app-card',
|
itemSelector: '.app-card',
|
||||||
layoutMode: 'fitRows',
|
layoutMode: 'fitRows',
|
||||||
transitionDuration: 200
|
transitionDuration: 200
|
||||||
});
|
});
|
||||||
|
|
||||||
filterByClassAndName = function () {
|
|
||||||
var input = jQuery("#filter-app-cards").val().toLowerCase();
|
|
||||||
var inputMatch = (jQuery(this).find('.app-title').text().toLowerCase().indexOf(input) > -1);
|
|
||||||
|
|
||||||
var filterClass = jQuery("#dropdownFilter").attr("data-filter");
|
|
||||||
var classMatch = (filterClass === '*') ? true : jQuery(this).hasClass(filterClass);
|
|
||||||
return inputMatch && classMatch;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Default filter is 'decent quality apps'
|
// Default filter is 'decent quality apps'
|
||||||
cardGrid.isotope({ filter: '.decentQuality' });
|
cardGrid.isotope({ filter: '.decentQuality' });
|
||||||
|
|
||||||
|
$(".subtag-selector button").on("click", function() {
|
||||||
|
var selector = $(this).parent();
|
||||||
|
$("button", selector).removeClass("active");
|
||||||
|
$(this).addClass("active");
|
||||||
|
cardGrid.isotope({ filter: filterApps });
|
||||||
|
});
|
||||||
|
|
||||||
|
filterApps = function () {
|
||||||
|
|
||||||
|
// Check text search
|
||||||
|
var input = jQuery("#filter-app-cards").val().toLowerCase();
|
||||||
|
if (jQuery(this).find('.app-title').text().toLowerCase().indexOf(input) <= -1) return false;
|
||||||
|
|
||||||
|
// Check subtags
|
||||||
|
var subtag = $(".subtag-selector button.active").data("subtag");
|
||||||
|
var this_subtags = jQuery(this).data("subtags");
|
||||||
|
if ((subtag !== undefined) && (subtag !== "all")) {
|
||||||
|
if ((subtag === "others") && (this_subtags !== "")) return false;
|
||||||
|
if ((subtag !== "others") && (this_subtags.split(",").indexOf(subtag) <= -1)) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check quality criteria
|
||||||
|
var class_ = jQuery("#dropdownFilter").data("filter");
|
||||||
|
if ((class_ !== '*') && (! jQuery(this).hasClass(class_))) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
jQuery('.dropdownFilter').on('click', function() {
|
jQuery('.dropdownFilter').on('click', function() {
|
||||||
// change dropdown label
|
// change dropdown label
|
||||||
jQuery('#app-cards-list-filter-text').text(jQuery(this).find('.menu-item').text());
|
jQuery('#app-cards-list-filter-text').text(jQuery(this).find('.menu-item').text());
|
||||||
// change filter attribute
|
// change filter attribute
|
||||||
jQuery('#dropdownFilter').attr("data-filter", jQuery(this).attr("data-filter"));
|
jQuery('#dropdownFilter').data("filter", jQuery(this).data("filter"));
|
||||||
// filter !
|
// filter !
|
||||||
cardGrid.isotope({ filter: filterByClassAndName });
|
cardGrid.isotope({ filter: filterApps });
|
||||||
});
|
});
|
||||||
|
|
||||||
jQuery("#filter-app-cards").on("keyup", function() {
|
jQuery("#filter-app-cards").on("keyup", function() {
|
||||||
cardGrid.isotope({ filter: filterByClassAndName });
|
cardGrid.isotope({ filter: filterApps });
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#install-custom-app a[role='button']").on('click', function() {
|
||||||
|
|
||||||
|
var url = $("#install-custom-app input[name='url']")[0].value;
|
||||||
|
if (url.indexOf("github.com") < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('applications'),
|
||||||
|
y18n.t('confirm_install_custom_app'),
|
||||||
|
function(){
|
||||||
|
c.redirect_to('#/apps/install/custom/' + encodeURIComponent(url));
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// render
|
// render
|
||||||
c.view('app/app_list_install', {apps: apps}, setupFilterEvents);
|
c.view('app/app_catalog_category', {apps: apps, category: category}, setupFilterEvents);
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
// Get app information
|
// Get app information
|
||||||
app.get('#/apps/:app', function (c) {
|
app.get('#/apps/:app', function (c) {
|
||||||
c.api('/apps/'+c.params['app']+'?raw', function(data) { // http://api.yunohost.org/#!/app/app_info_get_9
|
c.api('GET', '/apps/'+c.params['app']+'?full', {}, function(data) {
|
||||||
c.api('/users/permissions', function(data_permissions) {
|
c.api('GET', '/users/permissions', {}, function(data_permissions) {
|
||||||
|
|
||||||
// Permissions
|
// Permissions
|
||||||
data.permissions = data_permissions.permissions[c.params['app']+".main"]["allowed"];
|
data.permissions = data_permissions.permissions[c.params['app']+".main"]["allowed"];
|
||||||
|
@ -217,21 +277,43 @@
|
||||||
data.manifest.multi_instance = data.manifest.multi_instance ? y18n.t('yes') : y18n.t('no');
|
data.manifest.multi_instance = data.manifest.multi_instance ? y18n.t('yes') : y18n.t('no');
|
||||||
data.install_time = new Date(data.settings.install_time * 1000);
|
data.install_time = new Date(data.settings.install_time * 1000);
|
||||||
|
|
||||||
c.view('app/app_info', data);
|
c.view('app/app_info', data, function() {
|
||||||
|
|
||||||
|
// Button to set the app as default
|
||||||
|
$('button[data-action="set-as-default"]').on("click", function() {
|
||||||
|
var app = $(this).data("app");
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('applications'),
|
||||||
|
y18n.t('confirm_app_default'),
|
||||||
|
function() { c.api('PUT', '/apps/'+app+'/default', {}, function() { c.refresh() }); }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Button to uninstall the app
|
||||||
|
$('button[data-action="uninstall"]').on("click", function() {
|
||||||
|
var app = $(this).data("app");
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('applications'),
|
||||||
|
y18n.t('confirm_uninstall', [app]),
|
||||||
|
function() {
|
||||||
|
c.api('DELETE', '/apps/'+ app, {}, function() {
|
||||||
|
c.redirect_to('#/apps');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get app debug page
|
//
|
||||||
app.get('#/apps/:app/debug', function (c) {
|
// App actions
|
||||||
c.api('/apps/'+c.params['app']+'/debug', function(data) {
|
//
|
||||||
c.view('app/app_debug', data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Get app actions list
|
// Get app actions list
|
||||||
app.get('#/apps/:app/actions', function (c) {
|
app.get('#/apps/:app/actions', function (c) {
|
||||||
c.api('/apps/'+c.params['app']+'/actions', function(data) {
|
c.api('GET', '/apps/'+c.params['app']+'/actions', {}, function(data) {
|
||||||
$.each(data.actions, function(_, action) {
|
$.each(data.actions, function(_, action) {
|
||||||
formatYunoHostStyleArguments(action.arguments, c.params);
|
formatYunoHostStyleArguments(action.arguments, c.params);
|
||||||
|
|
||||||
|
@ -249,7 +331,7 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Perform application
|
// Perform app action
|
||||||
app.put('#/apps/:app/actions/:action', function(c) {
|
app.put('#/apps/:app/actions/:action', function(c) {
|
||||||
// taken from app install
|
// taken from app install
|
||||||
$.each(c.params, function(k, v) {
|
$.each(c.params, function(k, v) {
|
||||||
|
@ -268,14 +350,18 @@
|
||||||
'args': c.serialize(c.params.toHash())
|
'args': c.serialize(c.params.toHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
c.api('/apps/'+app_id+'/actions/'+action_id, function() { // http://api.yunohost.org/#!/app/app_install_post_2
|
c.api('PUT', '/apps/'+app_id+'/actions/'+action_id, params, function() {
|
||||||
c.redirect('#/apps/'+app_id+'/actions');
|
c.redirect_to('#/apps/'+app_id+'/actions', {slide:false});
|
||||||
}, 'PUT', params);
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// App config panel
|
||||||
|
//
|
||||||
|
|
||||||
// Get app config panel
|
// Get app config panel
|
||||||
app.get('#/apps/:app/config-panel', function (c) {
|
app.get('#/apps/:app/config-panel', function (c) {
|
||||||
c.api('/apps/'+c.params['app']+'/config-panel', function(data) {
|
c.api('GET', '/apps/'+c.params['app']+'/config-panel', {}, function(data) {
|
||||||
$.each(data.config_panel.panel, function(_, panel) {
|
$.each(data.config_panel.panel, function(_, panel) {
|
||||||
$.each(panel.sections, function(_, section) {
|
$.each(panel.sections, function(_, section) {
|
||||||
formatYunoHostStyleArguments(section.options, c.params);
|
formatYunoHostStyleArguments(section.options, c.params);
|
||||||
|
@ -301,17 +387,10 @@
|
||||||
'args': c.serialize(c.params.toHash())
|
'args': c.serialize(c.params.toHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
c.api('/apps/'+app_id+'/config', function() { // http://api.yunohost.org/#!/app/app_install_post_2
|
c.api('POST', '/apps/'+app_id+'/config', params, function() {
|
||||||
c.redirect('#/apps/'+app_id+'/config-panel');
|
c.redirect_to('#/apps/'+app_id+'/config-panel', {slide:false});
|
||||||
}, 'POST', params);
|
|
||||||
})
|
|
||||||
|
|
||||||
// Special case for custom app installation.
|
|
||||||
app.get('#/apps/install/custom', function (c) {
|
|
||||||
// If we try to GET /apps/install/custom, it means that installation fail.
|
|
||||||
// Need to redirect to apps/install to get rid of pacamn and see the log.
|
|
||||||
c.redirect('#/apps/install');
|
|
||||||
});
|
});
|
||||||
|
})
|
||||||
|
|
||||||
// Helper function that formats YunoHost style arguments for generating a form
|
// Helper function that formats YunoHost style arguments for generating a form
|
||||||
function formatYunoHostStyleArguments(args, params) {
|
function formatYunoHostStyleArguments(args, params) {
|
||||||
|
@ -333,10 +412,16 @@
|
||||||
args[k].helpLink = "";
|
args[k].helpLink = "";
|
||||||
|
|
||||||
// Multilingual label
|
// Multilingual label
|
||||||
args[k].label = (typeof args[k].ask[y18n.locale] !== 'undefined') ?
|
if (typeof args[k].ask === "string")
|
||||||
args[k].ask[y18n.locale] :
|
{
|
||||||
args[k].ask['en']
|
args[k].label = args[k].ask;
|
||||||
;
|
}
|
||||||
|
else if (typeof args[k].ask[y18n.locale] !== 'undefined') {
|
||||||
|
args[k].label = args[k].ask[y18n.locale];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
args[k].label = args[k].ask['en'];
|
||||||
|
}
|
||||||
|
|
||||||
// Multilingual help text
|
// Multilingual help text
|
||||||
if (typeof args[k].help !== 'undefined') {
|
if (typeof args[k].help !== 'undefined') {
|
||||||
|
@ -463,16 +548,24 @@
|
||||||
displayLicense: (manifest['license'] !== undefined && manifest['license'] !== 'free')
|
displayLicense: (manifest['license'] !== undefined && manifest['license'] !== 'free')
|
||||||
};
|
};
|
||||||
|
|
||||||
formatYunoHostStyleArguments(data.manifest.arguments.install, params);
|
formatYunoHostStyleArguments(manifest.arguments.install, params);
|
||||||
|
|
||||||
// Multilingual description
|
// Multilingual description
|
||||||
data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
|
if (typeof manifest.description === 'string')
|
||||||
data.manifest.description[y18n.locale] :
|
{
|
||||||
data.manifest.description['en']
|
data.description = manifest.description;
|
||||||
;
|
}
|
||||||
|
else if (typeof manifest.description[y18n.locale] !== 'undefined')
|
||||||
|
{
|
||||||
|
data.description = manifest.description[y18n.locale];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.description = manifest.description['en'];
|
||||||
|
}
|
||||||
|
|
||||||
// Multi Instance settings boolean to text
|
// Multi Instance settings boolean to text
|
||||||
data.manifest.multi_instance = data.manifest.multi_instance ? y18n.t('yes') : y18n.t('no');
|
data.manifest.multi_instance = manifest.multi_instance ? y18n.t('yes') : y18n.t('no');
|
||||||
|
|
||||||
// View app install form
|
// View app install form
|
||||||
c.view('app/app_install', data);
|
c.view('app/app_install', data);
|
||||||
|
@ -481,9 +574,9 @@
|
||||||
|
|
||||||
// App installation form
|
// App installation form
|
||||||
app.get('#/apps/install/:app', function (c) {
|
app.get('#/apps/install/:app', function (c) {
|
||||||
c.api('/apps?raw', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
|
c.api('GET', '/appscatalog?full', {}, function(data) {
|
||||||
var app_name = c.params["app"];
|
var app_name = c.params["app"];
|
||||||
var app_infos = data[app_name];
|
var app_infos = data["apps"][app_name];
|
||||||
if (app_infos['state'] === "validated")
|
if (app_infos['state'] === "validated")
|
||||||
{
|
{
|
||||||
app_infos['state'] = "official";
|
app_infos['state'] = "official";
|
||||||
|
@ -505,16 +598,15 @@
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
$('div.loader').remove();
|
c.redirect_to('#/apps/catalog');
|
||||||
c.redirect('#/apps/install');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
c.appInstallForm(
|
c.appInstallForm(
|
||||||
c.params['app'],
|
app_name,
|
||||||
data[c.params['app']].manifest,
|
app_infos.manifest,
|
||||||
c.params
|
c.params
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -547,46 +639,32 @@
|
||||||
delete params['args'];
|
delete params['args'];
|
||||||
}
|
}
|
||||||
|
|
||||||
c.api('/apps', function() { // http://api.yunohost.org/#!/app/app_install_post_2
|
c.api('POST', '/apps', params, function() {
|
||||||
c.redirect('#/apps');
|
c.redirect_to('#/apps');
|
||||||
}, 'POST', params);
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
c.flash('warning', y18n.t('app_install_cancel'));
|
c.flash('warning', y18n.t('app_install_cancel'));
|
||||||
store.clear('slide');
|
c.refresh();
|
||||||
c.redirect('#/apps/install');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Install custom app from github
|
// Install custom app from github
|
||||||
app.post('#/apps/install/custom', function(c) {
|
app.get('#/apps/install/custom/:url', function(c) {
|
||||||
|
|
||||||
var params = {
|
|
||||||
label: c.params['label'],
|
|
||||||
app: c.params['url']
|
|
||||||
};
|
|
||||||
delete c.params['label'];
|
|
||||||
delete c.params['url'];
|
|
||||||
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('applications'),
|
|
||||||
y18n.t('confirm_install_custom_app'),
|
|
||||||
function(){
|
|
||||||
|
|
||||||
// Force trailing slash
|
// Force trailing slash
|
||||||
params.app = params.app.replace(/\/?$/, '/');
|
url = c.params['url'];
|
||||||
|
url = url.replace(/\/?$/, '/');
|
||||||
|
raw_manifest_url = url.replace('github.com', 'raw.githubusercontent.com') + 'master/manifest.json'
|
||||||
|
|
||||||
// Get manifest.json to get additional parameters
|
// Fetch manifest.json
|
||||||
jQuery.ajax({
|
jQuery.ajax({ url: raw_manifest_url, type: 'GET' })
|
||||||
url: params.app.replace('github.com', 'raw.githubusercontent.com') + 'master/manifest.json',
|
|
||||||
type: 'GET',
|
|
||||||
})
|
|
||||||
.done(function(manifest) {
|
.done(function(manifest) {
|
||||||
// raw.githubusercontent.com serve content as plain text
|
// raw.githubusercontent.com serve content as plain text
|
||||||
manifest = jQuery.parseJSON(manifest) || {};
|
manifest = jQuery.parseJSON(manifest) || {};
|
||||||
|
|
||||||
c.appInstallForm(
|
c.appInstallForm(
|
||||||
params.app,
|
url,
|
||||||
manifest,
|
manifest,
|
||||||
c.params
|
c.params
|
||||||
);
|
);
|
||||||
|
@ -594,56 +672,14 @@
|
||||||
})
|
})
|
||||||
.fail(function(xhr) {
|
.fail(function(xhr) {
|
||||||
c.flash('fail', y18n.t('app_install_custom_no_manifest'));
|
c.flash('fail', y18n.t('app_install_custom_no_manifest'));
|
||||||
store.clear('slide');
|
c.redirect("#/apps/catalog/");
|
||||||
c.redirect('#/apps/install');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
c.flash('warning', y18n.t('app_install_cancel'));
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/apps/install');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove installed app
|
|
||||||
app.get('#/apps/:app/uninstall', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('applications'),
|
|
||||||
y18n.t('confirm_uninstall', [c.params['app']]),
|
|
||||||
function() {
|
|
||||||
c.api('/apps/'+ c.params['app'], function() { // http://api.yunohost.org/#!/app/app_remove_delete_4
|
|
||||||
c.redirect('#/apps');
|
|
||||||
}, 'DELETE');
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/apps/'+ c.params['app']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Make app default
|
|
||||||
app.get('#/apps/:app/default', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('applications'),
|
|
||||||
y18n.t('confirm_app_default'),
|
|
||||||
function() {
|
|
||||||
c.api('/apps/'+ c.params['app'] +'/default', function() { //
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/apps/'+ c.params['app']);
|
|
||||||
}, 'PUT');
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/apps/'+ c.params['app']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get app change label page
|
// Get app change label page
|
||||||
app.get('#/apps/:app/changelabel', function (c) {
|
app.get('#/apps/:app/changelabel', function (c) {
|
||||||
c.api('/apps/'+c.params['app']+'?raw', function(app_data) {
|
c.api('GET', '/apps/'+c.params['app']+'?full', {}, function(app_data) {
|
||||||
data = {
|
data = {
|
||||||
id: c.params['app'],
|
id: c.params['app'],
|
||||||
label: app_data.settings.label,
|
label: app_data.settings.label,
|
||||||
|
@ -655,16 +691,15 @@
|
||||||
// Change app label
|
// Change app label
|
||||||
app.post('#/apps/:app/changelabel', function (c) {
|
app.post('#/apps/:app/changelabel', function (c) {
|
||||||
params = {'new_label': c.params['label']};
|
params = {'new_label': c.params['label']};
|
||||||
c.api('/apps/' + c.params['app'] + '/label', function(data) { // Call changelabel API
|
c.api('PUT', '/apps/' + c.params['app'] + '/label', params, function(data) {
|
||||||
store.clear('slide');
|
c.redirect_to('#/apps/'+ c.params['app']);
|
||||||
c.redirect('#/apps/'+ c.params['app']);
|
});
|
||||||
}, 'PUT', params);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get app change URL page
|
// Get app change URL page
|
||||||
app.get('#/apps/:app/changeurl', function (c) {
|
app.get('#/apps/:app/changeurl', function (c) {
|
||||||
c.api('/apps/'+c.params['app']+'?raw', function(app_data) {
|
c.api('GET', '/apps/'+c.params['app']+'?full', {}, function(app_data) {
|
||||||
c.api('/domains', function(domain_data) { // http://api.yunohost.org/#!/domain/domain_list_get_2
|
c.api('GET', '/domains', {}, function(domain_data) {
|
||||||
|
|
||||||
// Display a list of available domains
|
// Display a list of available domains
|
||||||
var domains = [];
|
var domains = [];
|
||||||
|
@ -696,14 +731,9 @@
|
||||||
y18n.t('confirm_app_change_url', [c.params['app']]),
|
y18n.t('confirm_app_change_url', [c.params['app']]),
|
||||||
function() {
|
function() {
|
||||||
params = {'domain': c.params['domain'], 'path': c.params['path']};
|
params = {'domain': c.params['domain'], 'path': c.params['path']};
|
||||||
c.api('/apps/' + c.params['app'] + '/changeurl', function(data) { // Call changeurl API
|
c.api('PUT', '/apps/' + c.params['app'] + '/changeurl', params, function(data) {
|
||||||
store.clear('slide');
|
c.redirect_to('#/apps/'+ c.params['app']);
|
||||||
c.redirect('#/apps/'+ c.params['app']);
|
});
|
||||||
}, 'PUT', params);
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/apps/'+ c.params['app'] + '/changeurl');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,118 +32,9 @@
|
||||||
c.view('backup/backup', {'storages':storages});
|
c.view('backup/backup', {'storages':storages});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Storage list
|
|
||||||
app.get('#/storages/create', function (c) {
|
|
||||||
c.view('backup/storage_create', {});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a storage
|
|
||||||
app.post('#/storages', function (c) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/storages');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a backup
|
|
||||||
app.get('#/backup/:storage/create', function (c) {
|
|
||||||
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'] = {};
|
|
||||||
c.api('/apps?with_backup', function(apps_list) {
|
|
||||||
data['apps'] = apps_list.apps;
|
|
||||||
c.view('backup/backup_create', data, c.selectAllOrNone);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
app.post('#/backup/:storage', function (c) {
|
|
||||||
var params = c.ungroupHooks(c.params['system_parts'],c.params['apps']);
|
|
||||||
c.api('/backup', function() {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']);
|
|
||||||
}, 'POST', params);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Restore a backup
|
|
||||||
app.post('#/backup/:storage/:archive/restore', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('backup'),
|
|
||||||
y18n.t('confirm_restore', [c.params['archive']]),
|
|
||||||
$.proxy(function(c){
|
|
||||||
var params = c.ungroupHooks(c.params['system_parts'],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),
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Delete a backup
|
|
||||||
app.get('#/backup/:storage/:archive/delete', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('backup'),
|
|
||||||
y18n.t('confirm_delete', [c.params['archive']]),
|
|
||||||
function(){
|
|
||||||
c.api('/backup/archives/'+c.params['archive'], function(data) {
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']);
|
|
||||||
}, 'DELETE');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Download a backup
|
|
||||||
app.get('#/backup/:storage/:archive/download', function (c) {
|
|
||||||
c.api('/backup/'+c.params['archive']+'/download', function(data) {
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
|
||||||
}, 'GET');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Copy a backup
|
|
||||||
app.get('#/backup/:storage/:archive/copy', function (c) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Upload a backup
|
|
||||||
app.get('#/backup/:storage/:archive/upload', function (c) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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.other_storages = [];
|
|
||||||
data.name = c.params['archive'];
|
|
||||||
data.system_parts = c.groupHooks(Object.keys(data['system']),data['system']);
|
|
||||||
data.items = (data['system']!={} || data['apps']!=[]);
|
|
||||||
data.locale = y18n.locale
|
|
||||||
c.view('backup/backup_info', data, c.selectAllOrNone);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Archive list
|
// Archive list
|
||||||
app.get('#/backup/:storage', function (c) {
|
app.get('#/backup/:storage', function (c) {
|
||||||
c.api('/backup/archives?with_info', function(data) {
|
c.api('GET', '/backup/archives?with_info', {}, function(data) {
|
||||||
data.storage = {
|
data.storage = {
|
||||||
id: 'local',
|
id: 'local',
|
||||||
name: y18n.t('local_archives')
|
name: y18n.t('local_archives')
|
||||||
|
@ -159,4 +50,173 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// View to create a backup
|
||||||
|
app.get('#/backup/:storage/create', function (c) {
|
||||||
|
var data = [];
|
||||||
|
data['storage'] = {
|
||||||
|
id:c.params['storage'],
|
||||||
|
name:y18n.t('local_archives')
|
||||||
|
};
|
||||||
|
c.api('GET', '/hooks/backup', {}, function(hooks) {
|
||||||
|
data['hooks'] = groupHooks(hooks['hooks']);
|
||||||
|
data['apps'] = {};
|
||||||
|
c.api('GET', '/apps?with_backup', {}, function(apps_list) {
|
||||||
|
data['apps'] = apps_list.apps;
|
||||||
|
c.view('backup/backup_create', data, function() {
|
||||||
|
|
||||||
|
// Configure buttons "select all" and "select none"
|
||||||
|
|
||||||
|
// Remove active style from buttons
|
||||||
|
$(".select_all-none input").click(function(){ $(this).toggleClass("active"); });
|
||||||
|
// Select all checkbox in this panel
|
||||||
|
$(".select_all").click(function(){
|
||||||
|
$(this).parents(".panel").children(".list-group").find("input").prop("checked", true);
|
||||||
|
});
|
||||||
|
// Deselect all checkbox in this panel
|
||||||
|
$(".select_none").click(function(){
|
||||||
|
$(this).parents(".panel").children(".list-group").find("input").prop("checked", false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Actually creating the backup
|
||||||
|
app.post('#/backup/:storage', function (c) {
|
||||||
|
var params = ungroupHooks(c.params['system_parts'],c.params['apps']);
|
||||||
|
c.api('POST', '/backup', params, function() {
|
||||||
|
c.redirect_to('#/backup/'+ c.params['storage']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get archive info
|
||||||
|
app.get('#/backup/:storage/:archive', function (c) {
|
||||||
|
c.api('GET', '/backup/archives/'+c.params['archive']+'?with_details', {}, function(data) {
|
||||||
|
data.storage = {
|
||||||
|
id: c.params['storage'],
|
||||||
|
name: y18n.t('local_archives')
|
||||||
|
};
|
||||||
|
data.name = c.params['archive'];
|
||||||
|
data.system_parts = groupHooks(Object.keys(data['system']),data['system']);
|
||||||
|
data.items = (data['system']!={} || data['apps']!=[]);
|
||||||
|
data.locale = y18n.locale;
|
||||||
|
c.view('backup/backup_info', data, function() {
|
||||||
|
|
||||||
|
// Configure buttons "select all" and "select none"
|
||||||
|
|
||||||
|
// Remove active style from buttons
|
||||||
|
$(".select_all-none input").click(function(){ $(this).toggleClass("active"); });
|
||||||
|
// Select all checkbox in this panel
|
||||||
|
$(".select_all").click(function(){
|
||||||
|
$(this).parents(".panel").children(".list-group").find("input").prop("checked", true);
|
||||||
|
});
|
||||||
|
// Deselect all checkbox in this panel
|
||||||
|
$(".select_none").click(function(){
|
||||||
|
$(this).parents(".panel").children(".list-group").find("input").prop("checked", false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete button
|
||||||
|
$('button[data-action="delete"]').on('click', function() {
|
||||||
|
var storage = $(this).data('storage');
|
||||||
|
var archive = $(this).data('archive');
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('backup'),
|
||||||
|
y18n.t('confirm_delete', [archive]),
|
||||||
|
function(){
|
||||||
|
c.api('DELETE', '/backup/archives/'+archive, {}, function(data) {
|
||||||
|
c.redirect_to('#/backup/'+ storage);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Restore a backup
|
||||||
|
app.post('#/backup/:storage/:archive/restore', function (c) {
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('backup'),
|
||||||
|
y18n.t('confirm_restore', [c.params['archive']]),
|
||||||
|
$.proxy(function(c){
|
||||||
|
var params = ungroupHooks(c.params['system_parts'],c.params['apps']);
|
||||||
|
params['force'] = '';
|
||||||
|
c.api('POST', '/backup/restore/'+c.params['archive'], params, function(data) {
|
||||||
|
c.redirect_to('#/backup/'+ c.params['storage']+'/'+c.params['archive']);
|
||||||
|
});
|
||||||
|
}, this, c)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function groupHooks(hooks, raw_infos) {
|
||||||
|
var data = {};
|
||||||
|
var rules = [
|
||||||
|
{
|
||||||
|
id:'configuration',
|
||||||
|
isIn:function (hook) {
|
||||||
|
return hook.indexOf('conf_')==0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
$.each(hooks, function(i, hook) {
|
||||||
|
var group_id=hook;
|
||||||
|
var hook_size=(raw_infos && raw_infos[hook] && raw_infos[hook].size)?raw_infos[hook].size:0;
|
||||||
|
$.each(rules, function(i, rule) {
|
||||||
|
if (rule.isIn(hook)) {
|
||||||
|
group_id = 'adminjs_group_'+rule.id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(group_id in data) {
|
||||||
|
data[group_id] = {
|
||||||
|
name:y18n.t('hook_'+group_id),
|
||||||
|
value:data[group_id].value+','+hook,
|
||||||
|
description:data[group_id].description+', '+y18n.t('hook_'+hook),
|
||||||
|
size:data[group_id].size + hook_size
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data[group_id] = {
|
||||||
|
name:y18n.t('hook_'+group_id),
|
||||||
|
value:hook,
|
||||||
|
description:(group_id==hook)?y18n.t('hook_'+hook+'_desc'):y18n.t('hook_'+hook),
|
||||||
|
size:hook_size
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ungroupHooks(system_parts, apps) {
|
||||||
|
|
||||||
|
var data = {};
|
||||||
|
data['apps'] = apps || [];
|
||||||
|
data['system'] = system_parts || [];
|
||||||
|
|
||||||
|
if (data['system'].constructor !== Array) {
|
||||||
|
data['system'] = [data['system']];
|
||||||
|
}
|
||||||
|
if (data['apps'].constructor !== Array) {
|
||||||
|
data['apps'] = [data['apps']];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Some hook value contains multiple hooks separated by commas
|
||||||
|
var split_hooks = [];
|
||||||
|
$.each(data['system'], function(i, hook) {
|
||||||
|
split_hooks = split_hooks.concat(hook.split(','));
|
||||||
|
});
|
||||||
|
data['system'] = split_hooks;
|
||||||
|
|
||||||
|
if (data['system'].length == 0) {
|
||||||
|
delete data['system'];
|
||||||
|
}
|
||||||
|
if (data['apps'].length == 0) {
|
||||||
|
delete data['apps'];
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
152
src/js/yunohost/controllers/diagnosis.js
Normal file
152
src/js/yunohost/controllers/diagnosis.js
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
(function() {
|
||||||
|
// Get application context
|
||||||
|
var app = Sammy.apps['#main'];
|
||||||
|
var store = app.store;
|
||||||
|
|
||||||
|
// *********
|
||||||
|
// Diagnosis
|
||||||
|
// *********
|
||||||
|
|
||||||
|
app.get('#/diagnosis', function (c) {
|
||||||
|
c.api('POST', '/diagnosis/run?except-if-never-ran-yet', {}, function() {
|
||||||
|
updateDiagnosisView();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function updateDiagnosisView(state) {
|
||||||
|
|
||||||
|
c.api('GET', '/diagnosis/show?full', {}, function(data) {
|
||||||
|
|
||||||
|
if (typeof(data.reports) === "undefined")
|
||||||
|
{
|
||||||
|
data.reports = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare data to be displayed ...
|
||||||
|
for (var i = 0 ; i < data.reports.length ; i++)
|
||||||
|
{
|
||||||
|
// Convert timestamp to datetime
|
||||||
|
data.reports[i].time = new Date(data.reports[i].timestamp*1000);
|
||||||
|
data.reports[i].warnings = 0;
|
||||||
|
data.reports[i].errors = 0;
|
||||||
|
data.reports[i].ignored = 0;
|
||||||
|
for (var j = 0 ; j < data.reports[i].items.length ; j++)
|
||||||
|
{
|
||||||
|
var type_ = data.reports[i].items[j].status;
|
||||||
|
type_ = type_.toLowerCase();
|
||||||
|
var ignored = data.reports[i].items[j].ignored;
|
||||||
|
var icon = "";
|
||||||
|
var issue = false;
|
||||||
|
|
||||||
|
if (type_ == "success") {
|
||||||
|
icon = "check-circle";
|
||||||
|
}
|
||||||
|
else if (type_ == "info") {
|
||||||
|
icon = "info-circle";
|
||||||
|
}
|
||||||
|
else if (ignored == true) {
|
||||||
|
icon = type_;
|
||||||
|
if (type_ == "error") {
|
||||||
|
icon = "times"
|
||||||
|
}
|
||||||
|
type_ = "ignored";
|
||||||
|
data.reports[i].ignored++;
|
||||||
|
}
|
||||||
|
else if (type_ == "warning") {
|
||||||
|
icon = "warning";
|
||||||
|
issue = true;
|
||||||
|
data.reports[i].warnings++;
|
||||||
|
}
|
||||||
|
else if (type_ == "error") {
|
||||||
|
type_ = "danger";
|
||||||
|
icon = "times";
|
||||||
|
issue = true;
|
||||||
|
data.reports[i].errors++;
|
||||||
|
}
|
||||||
|
data.reports[i].items[j].status = type_;
|
||||||
|
data.reports[i].items[j].icon = icon;
|
||||||
|
data.reports[i].items[j].issue = issue;
|
||||||
|
// We want filter_args to be something like "dnsrecords,domain=yolo.test,category=xmpp"
|
||||||
|
data.reports[i].items[j].filter_args = data.reports[i].id;
|
||||||
|
for (prop in data.reports[i].items[j].meta) {
|
||||||
|
data.reports[i].items[j].filter_args = data.reports[i].items[j].filter_args + ","+prop+"="+data.reports[i].items[j].meta[prop];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
data.reports[i].noIssues = data.reports[i].warnings + data.reports[i].errors ? false : true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Render and display the view
|
||||||
|
c.view('diagnosis/diagnosis_show', data, function() {
|
||||||
|
|
||||||
|
restoreDiagnosisViewState(state);
|
||||||
|
|
||||||
|
// Button for first diagnosis
|
||||||
|
$("button[data-action='run-full-diagnosis']").click(function() {
|
||||||
|
c.api('POST', '/diagnosis/run', {}, function(data) {
|
||||||
|
updateDiagnosisView();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure share with yunopaste button
|
||||||
|
$("button[data-action='share']").click(function() {
|
||||||
|
c.api('GET', '/diagnosis/show?share', {}, function(data) {
|
||||||
|
c.hideLoader();
|
||||||
|
window.open(data.url, '_blank');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure 'rerun diagnosis' button behavior
|
||||||
|
$("button[data-action='rerun-diagnosis']").click(function() {
|
||||||
|
var category = $(this).data("category");
|
||||||
|
c.api('POST', '/diagnosis/run?force', {"categories": [category]}, function(data) {
|
||||||
|
updateDiagnosisView(saveDiagnosisViewState());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure 'ignore' / 'unignore' buttons behavior
|
||||||
|
$("button[data-action='ignore']").click(function() {
|
||||||
|
var filter_args = $(this).data("filter-args");
|
||||||
|
c.api('POST', '/diagnosis/ignore', {'add_filter': filter_args.split(',') }, function(data) {
|
||||||
|
updateDiagnosisView(saveDiagnosisViewState());
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
$("button[data-action='unignore']").click(function() {
|
||||||
|
var filter_args = $(this).data("filter-args");
|
||||||
|
c.api('POST', '/diagnosis/ignore', {'remove_filter': filter_args.split(',') }, function(data) {
|
||||||
|
updateDiagnosisView(saveDiagnosisViewState());
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save current level of scroll + which panels are collapsed / not collapsed
|
||||||
|
function saveDiagnosisViewState() {
|
||||||
|
var collapse = {};
|
||||||
|
$(".panel-diagnosis").each(function(i, el) {
|
||||||
|
collapse[$(el).data("category")] = $($(".panel-body", el)[0]).hasClass("in");
|
||||||
|
});
|
||||||
|
return { "scroll": document.documentElement.scrollTop, "collapse": collapse };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore scroll + panel collapse state
|
||||||
|
function restoreDiagnosisViewState(state) {
|
||||||
|
if (typeof state === "undefined") { return; }
|
||||||
|
|
||||||
|
Object.keys(state.collapse).forEach(function(category) {
|
||||||
|
if (state.collapse[category]) {
|
||||||
|
$(".panel-diagnosis[data-category='"+category+"'] .panel-body").addClass("in");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$(".panel-diagnosis[data-category='"+category+"'] .panel-body").removeClass("in");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.scroll(0,state.scroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
})();
|
|
@ -10,8 +10,8 @@
|
||||||
|
|
||||||
// List existing domains
|
// List existing domains
|
||||||
app.get('#/domains', function (c) {
|
app.get('#/domains', function (c) {
|
||||||
c.api('/domains', function(data) { // http://api.yunohost.org/#!/domain/domain_list_get_2
|
c.api('GET', '/domains', {}, function(data) {
|
||||||
c.api('/domains/main', function(data2) {
|
c.api('PUT', '/domains/main', {}, function(data2) {
|
||||||
var domains = [];
|
var domains = [];
|
||||||
$.each(data.domains, function(k, domain) {
|
$.each(data.domains, function(k, domain) {
|
||||||
domains.push({
|
domains.push({
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
domains: domains,
|
domains: domains,
|
||||||
main_domain_form: main_domain_form
|
main_domain_form: main_domain_form
|
||||||
});
|
});
|
||||||
}, 'PUT');
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -68,8 +68,7 @@
|
||||||
if (c.params['domain'] === '') {
|
if (c.params['domain'] === '') {
|
||||||
if (c.params['ddomain'] === '') {
|
if (c.params['ddomain'] === '') {
|
||||||
c.flash('fail', y18n.t('error_select_domain'));
|
c.flash('fail', y18n.t('error_select_domain'));
|
||||||
store.clear('slide');
|
c.redirect_to('#/domains/add');
|
||||||
c.redirect('#/domains/add');
|
|
||||||
}
|
}
|
||||||
params.domain = c.params['ddomain'] + c.params['ddomain-ext'];
|
params.domain = c.params['ddomain'] + c.params['ddomain-ext'];
|
||||||
endurl = 'dyndns';
|
endurl = 'dyndns';
|
||||||
|
@ -77,42 +76,53 @@
|
||||||
params.domain = c.params['domain'];
|
params.domain = c.params['domain'];
|
||||||
}
|
}
|
||||||
|
|
||||||
c.api('/domains?'+endurl, function(data) { // http://api.yunohost.org/#!/domain/domain_add_post_1
|
c.api('POST', '/domains?'+endurl, params, function(data) {
|
||||||
c.redirect('#/domains');
|
c.redirect_to('#/domains');
|
||||||
}, 'POST', params);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get existing domain info
|
// Get existing domain info
|
||||||
app.get('#/domains/:domain', function (c) {
|
app.get('#/domains/:domain', function (c) {
|
||||||
c.api('/domains/main', function(dataMain) {
|
c.api('PUT', '/domains/main', {}, function(dataMain) {
|
||||||
c.api('/apps?installed', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
|
|
||||||
|
|
||||||
// FIXME - This dirty trick (along with the previous API call
|
|
||||||
// for apps installed) should be removed once letsencrypt_ynh
|
|
||||||
// is not used by many people anymore. Probably around 07/2017
|
|
||||||
// or end of 2017...
|
|
||||||
var enable_cert_management_ = true;
|
|
||||||
$.each(data['apps'], function(k, v) {
|
|
||||||
if (v.id == "letsencrypt") {
|
|
||||||
enable_cert_management_ = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
var domain = {
|
var domain = {
|
||||||
name: c.params['domain'],
|
name: c.params['domain'],
|
||||||
main: (c.params['domain'] == dataMain.current_main_domain) ? true : false,
|
main: (c.params['domain'] == dataMain.current_main_domain) ? true : false,
|
||||||
url: "https://"+c.params['domain'],
|
url: "https://"+c.params['domain']
|
||||||
enable_cert_management: enable_cert_management_
|
|
||||||
};
|
};
|
||||||
c.view('domain/domain_info', domain);
|
c.view('domain/domain_info', domain, function() {
|
||||||
|
|
||||||
|
// Configure "set default" button
|
||||||
|
$('button[data-action="set_default"]').on("click", function() {
|
||||||
|
var domain = $(this).data("domain");
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('domains'),
|
||||||
|
y18n.t('confirm_change_maindomain'),
|
||||||
|
function() {
|
||||||
|
c.api('PUT', '/domains/main', {new_main_domain: domain}, function() { c.refresh() });
|
||||||
|
}
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure delete button
|
||||||
|
$('button[data-action="delete"]').on("click", function() {
|
||||||
|
var domain = $(this).data("domain");
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('domains'),
|
||||||
|
y18n.t('confirm_delete', [domain]),
|
||||||
|
function(){
|
||||||
|
c.api('DELETE', '/domains/'+ domain, {}, function() {
|
||||||
|
c.redirect_to('#/domains');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, 'PUT');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Domain DNS
|
// Domain DNS
|
||||||
app.get('#/domains/:domain/dns', function (c) {
|
app.get('#/domains/:domain/dns', function (c) {
|
||||||
c.api('/domains/' + c.params['domain'] + '/dns', function(data) {
|
c.api('GET', '/domains/' + c.params['domain'] + '/dns', {}, function(data) {
|
||||||
var domain = {
|
var domain = {
|
||||||
name: c.params['domain'],
|
name: c.params['domain'],
|
||||||
dns: data
|
dns: data
|
||||||
|
@ -123,7 +133,7 @@
|
||||||
|
|
||||||
// Domain certificate
|
// Domain certificate
|
||||||
app.get('#/domains/:domain/cert-management', function (c) {
|
app.get('#/domains/:domain/cert-management', function (c) {
|
||||||
c.api('/domains/cert-status/' + c.params['domain'] + '?full', function(data) {
|
c.api('GET', '/domains/cert-status/' + c.params['domain'] + '?full', {}, function(data) {
|
||||||
|
|
||||||
var s = data["certificates"][c.params['domain']];
|
var s = data["certificates"][c.params['domain']];
|
||||||
var status_ = {
|
var status_ = {
|
||||||
|
@ -199,132 +209,45 @@
|
||||||
status: status_,
|
status: status_,
|
||||||
actions_enabled : actions_enabled
|
actions_enabled : actions_enabled
|
||||||
};
|
};
|
||||||
c.view('domain/domain_cert', data_);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Install let's encrypt certificate on domain
|
c.view('domain/domain_cert', data_, function() {
|
||||||
app.get('#/domains/:domain/cert-install-LE', function (c) {
|
// Configure install / renew buttons behavior
|
||||||
|
$("button[data-action]").on("click", function () {
|
||||||
|
var action = $(this).data("action"),
|
||||||
|
domain = $(this).data("domain"),
|
||||||
|
confirm_key = "",
|
||||||
|
api_url = "";
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'install-LE':
|
||||||
|
confirm_key = 'confirm_cert_install_LE';
|
||||||
|
api_url = '/domains/cert-install/' + domain;
|
||||||
|
break;
|
||||||
|
case 'regen-selfsigned':
|
||||||
|
confirm_key = 'confirm_cert_regen_selfsigned';
|
||||||
|
api_url = '/domains/cert-install/' + domain + "?self_signed";
|
||||||
|
break;
|
||||||
|
case 'renew-letsencrypt':
|
||||||
|
confirm_key = 'confirm_cert_manual_renew_LE';
|
||||||
|
api_url = '/domains/cert-renew/' + domain + "?force";
|
||||||
|
break;
|
||||||
|
case 'replace-with-selfsigned':
|
||||||
|
confirm_key = 'confirm_cert_revert_to_selfsigned';
|
||||||
|
api_url = '/domains/cert-install/' + domain + "?self_signed&force";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
c.flash('fail', y18n.t('unknown_action', [action]));
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.confirm(
|
c.confirm(
|
||||||
y18n.t('certificate'),
|
y18n.t('certificate'),
|
||||||
y18n.t('confirm_cert_install_LE', [c.params['domain']]),
|
y18n.t(confirm_key, [domain]),
|
||||||
function(){
|
function(){ c.api('POST', api_url, {}, function() { c.refresh() }); }
|
||||||
c.api('/domains/cert-install/' + c.params['domain'], function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}, 'POST');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Regenerate a self-signed certificate
|
|
||||||
app.get('#/domains/:domain/cert-regen-selfsigned', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('certificate'),
|
|
||||||
y18n.t('confirm_cert_regen_selfsigned', [c.params['domain']]),
|
|
||||||
function(){
|
|
||||||
c.api('/domains/cert-install/' + c.params['domain'] + "?self_signed", function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}, 'POST');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Manually renew a Let's Encrypt certificate
|
|
||||||
app.get('#/domains/:domain/cert-renew-letsencrypt', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('certificate'),
|
|
||||||
y18n.t('confirm_cert_manual_renew_LE', [c.params['domain']]),
|
|
||||||
function(){
|
|
||||||
c.api('/domains/cert-renew/' + c.params['domain'] + "?force", function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}, 'POST');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Replace valid cert with self-signed
|
|
||||||
app.get('#/domains/:domain/cert-replace-with-selfsigned', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('certificate'),
|
|
||||||
y18n.t('confirm_cert_revert_to_selfsigned', [c.params['domain']]),
|
|
||||||
function(){
|
|
||||||
c.api('/domains/cert-install/' + c.params['domain'] + "?self_signed&force", function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}, 'POST');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains/'+c.params['domain']+'/cert-management');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Remove existing domain
|
|
||||||
app.get('#/domains/:domain/delete', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('domains'),
|
|
||||||
y18n.t('confirm_delete', [c.params['domain']]),
|
|
||||||
function(){
|
|
||||||
c.api('/domains/'+ c.params['domain'], function(data) { // http://api.yunohost.org/#!/domain/domain_remove_delete_3
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains');
|
|
||||||
}, 'DELETE');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set default domain
|
|
||||||
app.post('#/domains', function (c) {
|
|
||||||
if (c.params['domain'] === '') {
|
|
||||||
c.flash('fail', y18n.t('error_select_domain'));
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains');
|
|
||||||
} else {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('domains'),
|
|
||||||
y18n.t('confirm_change_maindomain'),
|
|
||||||
function(){
|
|
||||||
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
|
|
||||||
var refreshDomain = window.setTimeout(function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains');
|
|
||||||
}, 15000);
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/domains');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
// Firewall status
|
// Firewall status
|
||||||
app.get('#/tools/firewall', function (c) {
|
app.get('#/tools/firewall', function (c) {
|
||||||
c.api('/firewall?raw', function(data) {
|
c.api('GET', '/firewall?raw', {}, function(data) {
|
||||||
var firewall = {
|
var firewall = {
|
||||||
ports: {},
|
ports: {},
|
||||||
upnp: false
|
upnp: false
|
||||||
|
@ -30,28 +30,49 @@
|
||||||
// Get UPnP status
|
// Get UPnP status
|
||||||
firewall.upnp = data.uPnP.enabled;
|
firewall.upnp = data.uPnP.enabled;
|
||||||
|
|
||||||
c.view('tools/tools_firewall', firewall);
|
c.view('tools/tools_firewall', firewall, function() {
|
||||||
});
|
|
||||||
|
// Buttons in the 'ports' panel to open/close specific ports
|
||||||
|
$("button[data-port]").on("click", function() {
|
||||||
|
|
||||||
|
var port = $(this).data("port");
|
||||||
|
var action = $(this).data("action");
|
||||||
|
var protocol = $(this).data("protocol");
|
||||||
|
var connection = $(this).data("connection");
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('firewall'),
|
||||||
|
// confirm_firewall_open and confirm_firewall_close
|
||||||
|
y18n.t('confirm_firewall_' + action, [ port, y18n.t(protocol), y18n.t(connection)]),
|
||||||
|
function(){ c.togglePort(port, protocol, connection, action); }
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable/Disable UPnP
|
// Buttons to enable / disable UPnP
|
||||||
app.get('#/tools/firewall/upnp/:action', function (c) {
|
$("button[data-upnp]").on("click", function() {
|
||||||
|
var action = $(this).data("upnp");
|
||||||
c.confirm(
|
c.confirm(
|
||||||
y18n.t('firewall'),
|
y18n.t('firewall'),
|
||||||
// confirm_upnp_enable and confirm_upnp_disable
|
// confirm_upnp_enable and confirm_upnp_disable
|
||||||
y18n.t('confirm_upnp_' + c.params['action'].toLowerCase()),
|
y18n.t('confirm_upnp_' + action),
|
||||||
|
function(){ c.api('GET', '/firewall/upnp', {action: action}, function() { c.refresh() }); }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update port status from form
|
||||||
|
app.post('#/tools/firewall/port', function (c) {
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('firewall'),
|
||||||
|
y18n.t('confirm_firewall_' + c.params['action'].toLowerCase(), [ c.params['port'], y18n.t(c.params['protocol']), y18n.t(c.params['connection']) ]),
|
||||||
function(){
|
function(){
|
||||||
var params = {
|
c.togglePort(
|
||||||
action : c.params['action']
|
c.params['port'],
|
||||||
};
|
c.params['protocol'],
|
||||||
c.api('/firewall/upnp', function(data) {
|
c.params['connection'],
|
||||||
store.clear('slide');
|
c.params['action']
|
||||||
c.redirect('#/tools/firewall');
|
);
|
||||||
}, 'GET', params);
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -65,8 +86,7 @@
|
||||||
|
|
||||||
if (port != parseInt(port) || port < 0 || port > 65535) {
|
if (port != parseInt(port) || port < 0 || port > 65535) {
|
||||||
c.flash('fail', y18n.t('unknown_argument', [port]));
|
c.flash('fail', y18n.t('unknown_argument', [port]));
|
||||||
store.clear('slide');
|
c.refresh();
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (connection) {
|
switch (connection) {
|
||||||
|
@ -98,11 +118,9 @@
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
c.flash('fail', y18n.t('unknown_action', [action]));
|
c.flash('fail', y18n.t('unknown_action', [action]));
|
||||||
store.clear('slide');
|
c.refresh();
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method !== null && protocol !== null && port !== null) {
|
|
||||||
// port:
|
// port:
|
||||||
// protocol:
|
// protocol:
|
||||||
// - UDP
|
// - UDP
|
||||||
|
@ -115,58 +133,12 @@
|
||||||
port : port,
|
port : port,
|
||||||
protocol : protocol
|
protocol : protocol
|
||||||
};
|
};
|
||||||
c.api('/firewall/port?'+endurl, function(data) {
|
|
||||||
store.clear('slide');
|
c.api(method, '/firewall/port?'+endurl, params, function() { c.refresh() });
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}, method, params);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update port status from direct link
|
|
||||||
// #/firewall/port/{{@key}}/tcp/ipv4/close
|
|
||||||
app.get('#/tools/firewall/port/:port/:protocol/:connection/:action', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('firewall'),
|
|
||||||
// confirm_firewall_open and confirm_firewall_close
|
|
||||||
y18n.t( 'confirm_firewall_' + c.params['action'].toLowerCase(), [ c.params['port'], y18n.t(c.params['protocol']), y18n.t(c.params['connection'])]),
|
|
||||||
function(){
|
|
||||||
c.togglePort(
|
|
||||||
c.params['port'],
|
|
||||||
c.params['protocol'],
|
|
||||||
c.params['connection'],
|
|
||||||
c.params['action']
|
|
||||||
);
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update port status from form
|
|
||||||
app.post('#/tools/firewall/port', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('firewall'),
|
|
||||||
y18n.t('confirm_firewall_' + c.params['action'].toLowerCase(), [ c.params['port'], y18n.t(c.params['protocol']), y18n.t(c.params['connection']) ]),
|
|
||||||
function(){
|
|
||||||
c.togglePort(
|
|
||||||
c.params['port'],
|
|
||||||
c.params['protocol'],
|
|
||||||
c.params['connection'],
|
|
||||||
c.params['action']
|
|
||||||
);
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/firewall');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
})();
|
})();
|
|
@ -24,45 +24,36 @@
|
||||||
$('#masthead').show()
|
$('#masthead').show()
|
||||||
.find('.logout-btn').hide();
|
.find('.logout-btn').hide();
|
||||||
store.set('path-1', '#/login');
|
store.set('path-1', '#/login');
|
||||||
if ($('div.loader').length === 0) {
|
|
||||||
$('#main').append('<div class="loader loader-content"></div>');
|
c.showLoader();
|
||||||
|
|
||||||
|
// We gonna retry 3 times to check if yunohost is installed
|
||||||
|
if (app.isInstalledTry === undefined) {
|
||||||
|
app.isInstalledTry = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
c.checkInstall(function(isInstalled) {
|
c.checkInstall(function(isInstalled) {
|
||||||
|
|
||||||
if (isInstalled) {
|
if (isInstalled) {
|
||||||
// Remove loader
|
|
||||||
$('div.loader').remove();
|
|
||||||
// Pass domain to hide form field
|
|
||||||
c.view('login', { 'domain': window.location.hostname });
|
c.view('login', { 'domain': window.location.hostname });
|
||||||
} else if (typeof isInstalled === 'undefined') {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof isInstalled !== 'undefined') {
|
||||||
|
c.redirect('#/postinstall');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the retry counter is still up, retry this function 5 sec
|
||||||
|
// later
|
||||||
if (app.isInstalledTry > 0) {
|
if (app.isInstalledTry > 0) {
|
||||||
app.isInstalledTry--;
|
app.isInstalledTry--;
|
||||||
app.loaded = false; // Show pacman
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
c.redirect('#/');
|
c.redirect('#/');
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Reset count
|
c.flash('fail', y18n.t('api_not_responding'));
|
||||||
app.isInstalledTry = 3;
|
|
||||||
|
|
||||||
// API is not responding after 3 try
|
|
||||||
$( document ).ajaxError(function( event, request, settings ) {
|
|
||||||
// Display error if status != 200.
|
|
||||||
// .ajaxError fire even with status code 200 because json is sometimes not valid.
|
|
||||||
if (request.status !== 200) c.flash('fail', y18n.t('api_not_responding', [request.status+' '+request.statusText] ));
|
|
||||||
|
|
||||||
// Unbind directly
|
|
||||||
$(document).off('ajaxError');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove pacman
|
|
||||||
app.loaded = true;
|
|
||||||
$('div.loader').remove();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$('div.loader').remove();
|
|
||||||
c.redirect('#/postinstall');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -80,7 +71,7 @@
|
||||||
var params = {
|
var params = {
|
||||||
password: c.params['password']
|
password: c.params['password']
|
||||||
};
|
};
|
||||||
c.api('/login', function(data) {
|
c.api('POST', '/login', params, function(data) {
|
||||||
store.set('connected', true);
|
store.set('connected', true);
|
||||||
c.trigger('login');
|
c.trigger('login');
|
||||||
$('#masthead .logout-btn').fadeIn();
|
$('#masthead .logout-btn').fadeIn();
|
||||||
|
@ -90,19 +81,19 @@
|
||||||
} else {
|
} else {
|
||||||
c.redirect('#/');
|
c.redirect('#/');
|
||||||
}
|
}
|
||||||
}, 'POST', params, false);
|
}, undefined, false);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('#/logout', function (c) {
|
app.get('#/logout', function (c) {
|
||||||
c.api('/logout', function (data) {
|
c.api('GET', '/logout', {}, function (data) {
|
||||||
store.clear('url');
|
store.clear('url');
|
||||||
store.clear('connected');
|
store.clear('connected');
|
||||||
store.set('path', '#/');
|
store.set('path', '#/');
|
||||||
c.trigger('logout');
|
c.trigger('logout');
|
||||||
c.flash('success', y18n.t('logged_out'));
|
c.flash('success', y18n.t('logged_out'));
|
||||||
c.redirect('#/login');
|
c.redirect('#/login');
|
||||||
}, 'GET', {}, false);
|
}, undefined, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
(function() {
|
|
||||||
// Get application context
|
|
||||||
var app = Sammy.apps['#main'];
|
|
||||||
var store = app.store;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Monitor
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Server monitoring
|
|
||||||
app.get('#/tools/monitor', function (c) {
|
|
||||||
var monitorData = {};
|
|
||||||
|
|
||||||
// Why this method ?
|
|
||||||
c.api('/services/glances', function(data) { // ?
|
|
||||||
monitorData.status = true;
|
|
||||||
|
|
||||||
if (data.status == 'running') {
|
|
||||||
c.api('/monitor/system', function(data) {
|
|
||||||
monitorData.system = data;
|
|
||||||
|
|
||||||
c.api('/monitor/disk', function(data) {
|
|
||||||
monitorData.disk = data;
|
|
||||||
|
|
||||||
c.api('/monitor/network', function(data) {
|
|
||||||
monitorData.network = data;
|
|
||||||
|
|
||||||
// Remove useless interface
|
|
||||||
delete monitorData.network.usage.lo;
|
|
||||||
|
|
||||||
// Get YunoHost versions too
|
|
||||||
c.api('/diagnosis', function(diagnosis) {
|
|
||||||
monitorData.versions = diagnosis.packages;
|
|
||||||
c.view('tools/tools_monitoring', monitorData);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
monitorData.status = false;
|
|
||||||
c.view('tools/tools_monitoring', monitorData);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, 'GET');
|
|
||||||
});
|
|
||||||
|
|
||||||
})();
|
|
|
@ -13,7 +13,7 @@
|
||||||
$('#masthead').hide();
|
$('#masthead').hide();
|
||||||
c.checkInstall(function(isInstalled) {
|
c.checkInstall(function(isInstalled) {
|
||||||
if (isInstalled || typeof isInstalled === 'undefined') {
|
if (isInstalled || typeof isInstalled === 'undefined') {
|
||||||
c.redirect('#/login');
|
c.redirect_to('#/login');
|
||||||
} else {
|
} else {
|
||||||
c.view('postinstall/postinstall_1');
|
c.view('postinstall/postinstall_1');
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@
|
||||||
if ($('#domain').val() === '') {
|
if ($('#domain').val() === '') {
|
||||||
if ($('#ddomain').val() === '') {
|
if ($('#ddomain').val() === '') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
store.clear('slide');
|
|
||||||
c.flash('fail', y18n.t('error_select_domain'));
|
c.flash('fail', y18n.t('error_select_domain'));
|
||||||
} else {
|
} else {
|
||||||
domain = $('#ddomain').val() + $('select[name="ddomain-ext"]').val();
|
domain = $('#ddomain').val() + $('select[name="ddomain-ext"]').val();
|
||||||
|
@ -51,7 +50,7 @@
|
||||||
}
|
}
|
||||||
store.set('maindomain', domain);
|
store.set('maindomain', domain);
|
||||||
});
|
});
|
||||||
}, false); // We disable enableSlide because that causes some issues with accordion when using the 'previous' button
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -59,49 +58,52 @@
|
||||||
app.get('#/postinstall/password', function(c) {
|
app.get('#/postinstall/password', function(c) {
|
||||||
$('#masthead').hide();
|
$('#masthead').hide();
|
||||||
if (!store.get('maindomain')) {
|
if (!store.get('maindomain')) {
|
||||||
store.clear('slide');
|
c.redirect_to('#/postinstall/domain');
|
||||||
c.redirect('#/postinstall/domain');
|
|
||||||
} else {
|
} else {
|
||||||
c.view('postinstall/postinstall_3', { 'domain': store.get('maindomain').toLowerCase() },
|
c.view('postinstall/postinstall_3', { 'domain': store.get('maindomain').toLowerCase() });
|
||||||
function() { },
|
|
||||||
false); // We disable enableSlide because that causes some issues with accordion when using the 'previous' button
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Execute post-installation
|
// Execute post-installation
|
||||||
app.post('#/postinstall', function (c) {
|
app.post('#/postinstall', function (c) {
|
||||||
if (c.params['password'] === '' || c.params['confirmation'] === '') {
|
|
||||||
|
var password = c.params['password'];
|
||||||
|
var confirmation = c.params['confirmation'];
|
||||||
|
var domain = c.params['domain'].toLowerCase();
|
||||||
|
|
||||||
|
// Check password ain't empty
|
||||||
|
if (password === '' || confirmation === '') {
|
||||||
c.flash('fail', y18n.t('password_empty'));
|
c.flash('fail', y18n.t('password_empty'));
|
||||||
}
|
return;
|
||||||
else if (c.params['password'] == c.params['confirmation']) {
|
|
||||||
if (c.params['domain'] === '') {
|
|
||||||
c.flash('fail', y18n.t('error_select_domain'));
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/postinstall/domain');
|
|
||||||
} else {
|
|
||||||
var params = {
|
|
||||||
domain: c.params['domain'].toLowerCase()
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check password matches confirmation
|
||||||
|
if (password !== confirmation) {
|
||||||
|
c.flash('fail', y18n.t('passwords_dont_match'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check domain ain't empty...
|
||||||
|
if (domain === '') {
|
||||||
|
c.flash('fail', y18n.t('error_select_domain'));
|
||||||
|
c.redirect_to('#/postinstall/domain', {slide: false});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask confirmation to the user
|
||||||
c.confirm(
|
c.confirm(
|
||||||
y18n.t('postinstall'),
|
y18n.t('postinstall'),
|
||||||
y18n.t('confirm_postinstall', [c.params['domain']]),
|
y18n.t('confirm_postinstall', [c.params['domain']]),
|
||||||
|
// Start the actual postinstall process
|
||||||
function(){
|
function(){
|
||||||
params.password = c.params['password'];
|
|
||||||
|
|
||||||
store.set('url', window.location.hostname +'/yunohost/api');
|
store.set('url', window.location.hostname +'/yunohost/api');
|
||||||
store.set('user', 'admin');
|
store.set('user', 'admin');
|
||||||
c.api('/postinstall', function(data) { // http://api.yunohost.org/#!/tools/tools_postinstall_post_0
|
c.api('POST', '/postinstall', {domain: domain, password: password}, function() {
|
||||||
c.redirect('#/login');
|
c.flash('success', y18n.t('installation_complete'));
|
||||||
}, 'POST', params);
|
c.redirect_to('#/login');
|
||||||
},
|
});
|
||||||
function(){
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
c.flash('fail', y18n.t('passwords_dont_match'));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -10,21 +10,15 @@
|
||||||
|
|
||||||
// All services status
|
// All services status
|
||||||
app.get('#/services', function (c) {
|
app.get('#/services', function (c) {
|
||||||
c.api('/services', function(data) { // ?
|
c.api('GET', '/services', {}, function(data) {
|
||||||
var data2 = {
|
var data2 = {
|
||||||
services: []
|
services: []
|
||||||
};
|
};
|
||||||
$.each(data, function(k, v) {
|
$.each(data, function(k, v) {
|
||||||
v.name = k;
|
v.name = k;
|
||||||
// Handlebars want booleans
|
if (v.last_state_change == 'unknown')
|
||||||
v.is_loaded = (v.loaded=='enabled') ? true : false;
|
|
||||||
v.is_running = (v.active=='active') ? true : false;
|
|
||||||
// Translate status and loaded state
|
|
||||||
v.status = y18n.t(v.status);
|
|
||||||
v.loaded = y18n.t(v.loaded);
|
|
||||||
if (v.active_at == 'unknown')
|
|
||||||
{
|
{
|
||||||
delete v.active_at;
|
v.last_state_change = 0;
|
||||||
}
|
}
|
||||||
data2.services.push(v);
|
data2.services.push(v);
|
||||||
});
|
});
|
||||||
|
@ -45,28 +39,88 @@
|
||||||
|
|
||||||
// Status & actions for a service
|
// Status & actions for a service
|
||||||
app.get('#/services/:service', function (c) {
|
app.get('#/services/:service', function (c) {
|
||||||
c.api('/services/'+ c.params['service'], function(data) { // ?
|
c.api('GET', '/services/'+ c.params['service'], {}, function(data) {
|
||||||
var data2 = {
|
c.api('GET', '/services/'+ c.params['service'] +'/log', {number: 50}, function(data_log) {
|
||||||
service: data
|
|
||||||
};
|
data.name = c.params['service'];
|
||||||
data2.service.name = c.params['service'];
|
if (data.last_state_change == 'unknown')
|
||||||
// Handlebars want booleans
|
|
||||||
data2.service.is_loaded = (data.loaded=='enabled') ? true : false;
|
|
||||||
data2.service.is_running = (data.active=='active') ? true : false;
|
|
||||||
// Translate status and loaded state
|
|
||||||
data2.service.active = y18n.t(data.active);
|
|
||||||
data2.service.loaded = y18n.t(data.loaded);
|
|
||||||
if (data.active_at != 'unknown')
|
|
||||||
{
|
{
|
||||||
data2.service.active_at = data.active_at;
|
data.last_state_change = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.logs = [];
|
||||||
|
$.each(data_log, function(k, v) {
|
||||||
|
data.logs.push({filename: k, filecontent: v.join('\n')});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort logs by filename, put the journalctl/systemd log on top
|
||||||
|
data.logs.sort(function(a,b) { return a.filename === "journalctl" ? -1 : b.filename === "journalctl" ? 1 : a.filename < b.filename ? -1 : a.filename > b.filename ? 1 : 0; });
|
||||||
|
|
||||||
|
c.view('service/service_info', data, function() {
|
||||||
|
|
||||||
|
// Don't allow user to stop critical services from the webadmin
|
||||||
|
$('button[data-action="stop"]').each(function() {
|
||||||
|
|
||||||
|
var critical = ['nginx', 'ssh', 'slapd', 'yunohost-api'];
|
||||||
|
var service = $(this).data('service');
|
||||||
|
|
||||||
|
if (critical.indexOf(service) >= 0)
|
||||||
|
{
|
||||||
|
$(this).hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure behavior for enable/disable and start/stop buttons
|
||||||
|
$('button[data-action="start"], button[data-action="restart"], button[data-action="stop"]').on('click', function() {
|
||||||
|
|
||||||
|
var service = $(this).data('service');
|
||||||
|
var action = $(this).data('action');
|
||||||
|
|
||||||
|
c.confirm(y18n.t("services"), y18n.t('confirm_service_' + action, [service]), function(){
|
||||||
|
|
||||||
|
if (action == "start")
|
||||||
|
{
|
||||||
|
var method = "PUT";
|
||||||
|
var url = "/services/" + service;
|
||||||
|
}
|
||||||
|
else if (action == "restart")
|
||||||
|
{
|
||||||
|
var method = "PUT";
|
||||||
|
var url = "/services/" + service + "/restart";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data2.service.active_at = 0;
|
var method = "DELETE";
|
||||||
|
var url = "/services/" + service;
|
||||||
}
|
}
|
||||||
store.clear('slide');
|
c.api(method, url, {}, function() { c.refresh(); });
|
||||||
c.view('service/service_info', data2);
|
});
|
||||||
}, 'GET');
|
});
|
||||||
|
|
||||||
|
// Configure behavior for enable/disable and start/stop buttons
|
||||||
|
$('button[data-action="share"]').on('click', function() {
|
||||||
|
|
||||||
|
c.showLoader();
|
||||||
|
|
||||||
|
// Send to paste.yunohost.org
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: 'https://paste.yunohost.org/documents',
|
||||||
|
data: $("#logs").text(),
|
||||||
|
})
|
||||||
|
.success(function(data, textStatus, jqXHR) {
|
||||||
|
window.open('https://paste.yunohost.org/' + data.key, '_blank');
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
c.flash('fail', y18n.t('paste_error'));
|
||||||
|
})
|
||||||
|
.always(function(){
|
||||||
|
c.hideLoader();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Service log
|
// Service log
|
||||||
|
@ -74,63 +128,14 @@
|
||||||
var params = {
|
var params = {
|
||||||
number: 50
|
number: 50
|
||||||
};
|
};
|
||||||
c.api('/services/'+ c.params['service'] +'/log', function(data) { // ?
|
c.api('GET', '/services/'+ c.params['service'] +'/log', params, function(data) { // ?
|
||||||
data2 = { 'logs': [], 'name': c.params['service'] };
|
data2 = { 'logs': [], 'name': c.params['service'] };
|
||||||
$.each(data, function(k, v) {
|
$.each(data, function(k, v) {
|
||||||
data2.logs.push({filename: k, filecontent: v.join('\n')});
|
data2.logs.push({filename: k, filecontent: v.join('\n')});
|
||||||
});
|
});
|
||||||
|
|
||||||
c.view('service/service_log', data2);
|
c.view('service/service_log', data2);
|
||||||
}, 'GET', params);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Enable/Disable & Start/Stop service
|
|
||||||
app.get('#/services/:service/:action', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
"Service",
|
|
||||||
// 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'];
|
|
||||||
|
|
||||||
switch (c.params['action']) {
|
|
||||||
case 'start':
|
|
||||||
method = 'PUT';
|
|
||||||
break;
|
|
||||||
case 'stop':
|
|
||||||
method = 'DELETE';
|
|
||||||
break;
|
|
||||||
case 'enable':
|
|
||||||
method = 'PUT';
|
|
||||||
endurl += '/enable';
|
|
||||||
break;
|
|
||||||
case 'disable':
|
|
||||||
method = 'DELETE';
|
|
||||||
endurl += '/enable';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
c.flash('fail', y18n.t('unknown_action', [c.params['action']]));
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/services/'+ c.params['service']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method && endurl) {
|
|
||||||
c.api('/services/'+ endurl, function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/services/'+ c.params['service']);
|
|
||||||
}, method);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/services/'+ c.params['service']);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/services/'+ c.params['service']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -26,77 +26,69 @@
|
||||||
});
|
});
|
||||||
if ($.isEmptyObject(params)) {
|
if ($.isEmptyObject(params)) {
|
||||||
c.flash('fail', y18n.t('error_modify_something'));
|
c.flash('fail', y18n.t('error_modify_something'));
|
||||||
store.clear('slide');
|
c.refresh();
|
||||||
c.redirect('#/tools/adminpw');
|
return;
|
||||||
} else if (params['new_password'] !== params['confirm_new_password']) {
|
}
|
||||||
|
if (params['new_password'] !== params['confirm_new_password']) {
|
||||||
c.flash('fail', y18n.t('passwords_dont_match'));
|
c.flash('fail', y18n.t('passwords_dont_match'));
|
||||||
store.clear('slide');
|
c.refresh();
|
||||||
c.redirect('#/tools/adminpw');
|
return;
|
||||||
} else {
|
}
|
||||||
c.api('/login', function(data) {
|
|
||||||
|
c.api('POST', '/login', { 'password': params['old_password'] }, function(data) {
|
||||||
// Remove useless variable
|
// Remove useless variable
|
||||||
delete params['old_password'];
|
delete params['old_password'];
|
||||||
delete params['confirm_new_password'];
|
delete params['confirm_new_password'];
|
||||||
|
|
||||||
// Update password and redirect to the home
|
// Update password and redirect to the home
|
||||||
c.api('/adminpw', function(data) { // http://api.yunohost.org/#!/tools/tools_adminpw_put_3
|
c.api('PUT', '/adminpw', params, function(data) {
|
||||||
c.redirect('#/logout');
|
c.redirect_to('#/logout');
|
||||||
}, 'PUT', params);
|
});
|
||||||
}, 'POST', { 'password': params['old_password'] }, false);
|
}, undefined, false);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// System update & upgrade
|
// System update & upgrade
|
||||||
app.get('#/update', function (c) {
|
app.get('#/update', function (c) {
|
||||||
c.api('/update', function(data) {
|
c.api('PUT', '/update', {}, function(data) {
|
||||||
c.view('update/update', data);
|
c.view('tools/tools_update', data, function() {
|
||||||
}, 'PUT');
|
// Configure buttons behaviors
|
||||||
});
|
$("button[data-upgrade]").on("click", function() {
|
||||||
|
|
||||||
// Upgrade apps or packages
|
var what = $(this).data("upgrade").toLowerCase();
|
||||||
app.get('#/upgrade/:type', function (c) {
|
|
||||||
c.confirm(
|
// Upgrade all apps or the system
|
||||||
y18n.t('tools'),
|
|
||||||
// confirm_update_apps and confirm_update_packages
|
if ((what == "system") || (what == "apps"))
|
||||||
y18n.t('confirm_update_' + c.params['type'].toLowerCase()),
|
{
|
||||||
function(){
|
var confirm_message = y18n.t('confirm_update_' + what);
|
||||||
c.api('/upgrade?'+c.params["type"],
|
var api_url = '/upgrade?'+what;
|
||||||
function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/logs');
|
|
||||||
},
|
|
||||||
'PUT');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/update');
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Upgrade a specific apps
|
// Upgrade a specific apps
|
||||||
app.get('#/upgrade/apps/:app', function (c) {
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var confirm_message = y18n.t('confirm_update_specific_app', [what]);
|
||||||
|
var api_url = '/upgrade/apps?app='+what;
|
||||||
|
}
|
||||||
|
|
||||||
c.confirm(
|
c.confirm(
|
||||||
y18n.t('tools'),
|
y18n.t('tools'),
|
||||||
y18n.t('confirm_update_specific_app', [c.params['app']]),
|
confirm_message,
|
||||||
function(){
|
function(){
|
||||||
c.api('/upgrade/apps?app='+c.params['app'].toLowerCase(),
|
c.api('PUT', api_url, {}, function(data) {
|
||||||
function(data) {
|
c.redirect_to('#/tools/logs');
|
||||||
store.clear('slide');
|
});
|
||||||
c.redirect('#/tools/logs');
|
|
||||||
},
|
|
||||||
'PUT');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/update');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Display journals list
|
// Display journals list
|
||||||
app.get('#/tools/logs', function (c) {
|
app.get('#/tools/logs', function (c) {
|
||||||
c.api("/logs?limit=25&with_details", function(categories) {
|
c.api('GET', "/logs?limit=25&with_details", {}, function(categories) {
|
||||||
data = [];
|
data = [];
|
||||||
category_icons = {
|
category_icons = {
|
||||||
'operation': 'wrench',
|
'operation': 'wrench',
|
||||||
|
@ -137,95 +129,54 @@
|
||||||
app.get(/\#\/tools\/logs\/(.*)(\?number=(\d+))?/, function (c) {
|
app.get(/\#\/tools\/logs\/(.*)(\?number=(\d+))?/, function (c) {
|
||||||
var params = "?path=" + c.params["splat"][0];
|
var params = "?path=" + c.params["splat"][0];
|
||||||
var number = (c.params["number"])?c.params["number"]:50;
|
var number = (c.params["number"])?c.params["number"]:50;
|
||||||
params += "&number=" + number;
|
params += "&filter_irrelevant&number=" + number;
|
||||||
|
|
||||||
c.api("/logs/display" + params, function(log) {
|
c.api('GET', "/logs/display" + params, {}, function(log) {
|
||||||
if ('metadata' in log) {
|
if ('metadata' in log) {
|
||||||
if (!'env' in log.metadata && 'args' in log.metadata) {
|
if (!'env' in log.metadata && 'args' in log.metadata) {
|
||||||
log.metadata.env = log.metadata.args
|
log.metadata.env = log.metadata.args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.view('tools/tools_log', {
|
c.view('tools/tools_log', {
|
||||||
"log": log,
|
"log": log,
|
||||||
"next_number": log.logs.length == number ? number * 10:false,
|
"next_number": log.logs.length == number ? number * 10:false,
|
||||||
"locale": y18n.locale
|
"locale": y18n.locale
|
||||||
|
}, function() {
|
||||||
|
log = $("#main #log").html();
|
||||||
|
log = log.replace(/.*: ERROR - .*/g, function (match) { return '<span class="alert-danger">'+match+'</span>'});
|
||||||
|
log = log.replace(/.*: WARNING - .*/g, function (match) { return '<span class="alert-warning">'+match+'</span>'});
|
||||||
|
log = log.replace(/.*: SUCCESS - .*/g, function (match) { return '<span class="alert-success">'+match+'</span>'});
|
||||||
|
log = log.replace(/.*: INFO - .*/g, function (match) { return '<span class="alert-info">'+match+'</span>'});
|
||||||
|
$("#main #log").html(log);
|
||||||
|
|
||||||
|
// Configure behavior for the button to share log on Yunohost (it calls display --share)
|
||||||
|
$('button[data-action="share"]').on("click", function() {
|
||||||
|
c.api('GET', '/logs/display?path='+$(this).data('log-id')+'&share', {},
|
||||||
|
function(data) {
|
||||||
|
c.hideLoader();
|
||||||
|
window.open(data.url, '_blank');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Download SSL Certificate Authority
|
|
||||||
app.get('#/tools/ca', function (c) {
|
|
||||||
c.view('tools/tools_ca');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Security feed
|
|
||||||
app.get('#/tools/security-feed', function (c) {
|
|
||||||
var data = {
|
|
||||||
items: []
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get security feed and display items
|
|
||||||
var forumUrl = 'https://forum.yunohost.org';
|
|
||||||
var securityUrl = 'https://forum.yunohost.org/c/security';
|
|
||||||
var securityFeed = 'https://yunohost.org/security.rss';
|
|
||||||
|
|
||||||
data.url = {
|
|
||||||
web: securityUrl,
|
|
||||||
rss: securityFeed
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: securityFeed,
|
|
||||||
// dataType: (jQuery.browser.msie) ? "text" : "xml",
|
|
||||||
dataType: "xml"
|
|
||||||
})
|
|
||||||
.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 item = {
|
|
||||||
guid: $('guid', v)[0].innerHTML,
|
|
||||||
title: $('title', v)[0].innerHTML,
|
|
||||||
url: link,
|
|
||||||
desc: description,
|
|
||||||
date: $('pubDate', v)[0].innerHTML.split(' +')[0],
|
|
||||||
};
|
|
||||||
data.items.push(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
c.view('tools/tools_security_feed', data);
|
|
||||||
})
|
|
||||||
.fail(function() {
|
|
||||||
c.flash('fail', y18n.t('error_retrieve_feed', [securityFeed]));
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reboot or shutdown button
|
// Reboot or shutdown button
|
||||||
app.get('#/tools/reboot', function (c) {
|
app.get('#/tools/reboot', function (c) {
|
||||||
c.view('tools/tools_reboot');
|
c.view('tools/tools_reboot', {}, function() {
|
||||||
});
|
// Configure reboot/shutdown buttons behavior
|
||||||
|
$("button[data-action]").on("click", function() {
|
||||||
|
var action = $(this).data("action");
|
||||||
|
|
||||||
// Reboot or shutdown actions
|
|
||||||
app.get('#/tools/reboot/:action', function (c) {
|
|
||||||
var action = c.params['action'].toLowerCase();
|
|
||||||
if (action == 'reboot' || action == 'shutdown') {
|
|
||||||
c.confirm(
|
c.confirm(
|
||||||
y18n.t('tools_' + action),
|
y18n.t('tools_' + action),
|
||||||
// confirm_reboot_action_reboot or confirm_reboot_action_shutdown
|
|
||||||
y18n.t('confirm_reboot_action_' + action),
|
y18n.t('confirm_reboot_action_' + action),
|
||||||
function(){
|
function(){
|
||||||
c.api('/'+action+'?force', function(data) {
|
c.api('PUT', '/'+action+'?force', {}, function(data) {
|
||||||
// This code is not executed due to 502 response (reboot or shutdown)
|
// This code is not executed due to 502 response (reboot or shutdown)
|
||||||
c.redirect('#/logout');
|
c.redirect_to('#/logout');
|
||||||
}, 'PUT', {}, false, function (xhr) {
|
}, function (xhr) {
|
||||||
c.flash('success', y18n.t('tools_' + action + '_done'))
|
c.flash('success', y18n.t('tools_' + action + '_done'))
|
||||||
// Disconnect from the webadmin
|
// Disconnect from the webadmin
|
||||||
store.clear('url');
|
store.clear('url');
|
||||||
|
@ -243,47 +194,20 @@
|
||||||
$('#main').replaceWith('<div id="main"><div class="alert alert-warning"><i class="fa-power-off"></i> ' + y18n.t('tools_shuttingdown') + '</div></div>');
|
$('#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
|
c.hideLoader();
|
||||||
$('div.loader').remove();
|
|
||||||
|
|
||||||
// Force scrollTop on page load
|
// Force scrollTop on page load
|
||||||
$('html, body').scrollTop(0);
|
$('html, body').scrollTop(0);
|
||||||
store.clear('slide');
|
}, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
|
||||||
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
|
|
||||||
var private = (c.params.splat[0] == 'private');
|
|
||||||
|
|
||||||
var endurl = (private) ? '?private' : '';
|
|
||||||
c.api('/diagnosis'+endurl, function(diagnosis) {
|
|
||||||
c.view('tools/tools_diagnosis', {
|
|
||||||
'diagnosis' : JSON.stringify(diagnosis, undefined, 4),
|
|
||||||
'raw' : diagnosis,
|
|
||||||
'private' : private
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Reboot or shutdown button
|
// Migrations
|
||||||
app.get('#/tools/migrations', function (c) {
|
app.get('#/tools/migrations', function (c) {
|
||||||
c.api('/migrations?pending', function(pending_migrations) {
|
c.api('GET', '/migrations?pending', {}, function(pending_migrations) {
|
||||||
c.api('/migrations?done', function(done_migrations) {
|
c.api('GET', '/migrations?done', {}, function(done_migrations) {
|
||||||
pending_migrations = pending_migrations.migrations;
|
pending_migrations = pending_migrations.migrations;
|
||||||
done_migrations = done_migrations.migrations;
|
done_migrations = done_migrations.migrations;
|
||||||
|
|
||||||
|
@ -302,148 +226,39 @@
|
||||||
c.view('tools/tools_migrations', {
|
c.view('tools/tools_migrations', {
|
||||||
'pending_migrations' : pending_migrations.reverse(),
|
'pending_migrations' : pending_migrations.reverse(),
|
||||||
'done_migrations' : done_migrations.reverse()
|
'done_migrations' : done_migrations.reverse()
|
||||||
});
|
}, function() {
|
||||||
});
|
|
||||||
});
|
// Configure button 'Run'
|
||||||
});
|
$('button[data-action="run"]').on("click", function() {
|
||||||
|
|
||||||
app.get('#/tools/migrations/run', function (c) {
|
|
||||||
var disclaimerAcks = $(".disclaimer-ack");
|
var disclaimerAcks = $(".disclaimer-ack");
|
||||||
var withAcceptDisclaimerFlag = false;
|
|
||||||
for (var i = 0 ; i < disclaimerAcks.length ; i++)
|
for (var i = 0 ; i < disclaimerAcks.length ; i++)
|
||||||
{
|
{
|
||||||
console.log($(disclaimerAcks[i]).find("input:checked").val());
|
|
||||||
if (! $(disclaimerAcks[i]).find("input:checked").val())
|
if (! $(disclaimerAcks[i]).find("input:checked").val())
|
||||||
{
|
{
|
||||||
// FIXME / TODO i18n
|
// FIXME / TODO i18n
|
||||||
c.flash('fail', "Some of these migrations require you to acknowledge a disclaimer before running them.");
|
c.flash('fail', "Some of these migrations require you to acknowledge a disclaimer before running them.");
|
||||||
c.redirect('#/tools/migrations');
|
c.refresh();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
withAcceptDisclaimerFlag = true;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Not sure if necessary, but this distinction is to avoid accidentally
|
c.api('POST', '/migrations/migrate?accept_disclaimer', {}, function() { c.refresh(); });
|
||||||
// triggering a migration with a disclaimer if one goes to the
|
|
||||||
// /tools/migrations/run page "directly" somehow ...
|
|
||||||
if (withAcceptDisclaimerFlag)
|
|
||||||
{
|
|
||||||
c.api('/migrations/migrate?accept_disclaimer',
|
|
||||||
function (data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/migrations');
|
|
||||||
}, 'POST')
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c.api('/migrations/migrate',
|
|
||||||
function (data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/migrations');
|
|
||||||
}, 'POST')
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('#/tools/migrations/skip/:migration_id', function (c) {
|
// Configure buttons 'Skip'
|
||||||
|
$('button[data-action="skip"]').on("click", function() {
|
||||||
|
var migration_id = $(this).data("migration");
|
||||||
c.confirm(
|
c.confirm(
|
||||||
y18n.t('migrations'),
|
y18n.t('migrations'),
|
||||||
y18n.t('confirm_migrations_skip'),
|
y18n.t('confirm_migrations_skip'),
|
||||||
function(){
|
function(){
|
||||||
c.api('/migrations/migrate?skip&targets=' + c.params['migration_id'], function(data) {
|
c.api('POST', '/migrations/migrate?skip&targets=' + migration_id, {}, function() { c.refresh() });
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/migrations');
|
|
||||||
}, 'POST');
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/migrations');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// List available apps lists
|
|
||||||
app.get('#/tools/appslists', function (c) {
|
|
||||||
c.api('/appslists', function(data) {
|
|
||||||
list = [];
|
|
||||||
$.each(data, function(listname, listinfo) {
|
|
||||||
list.push({
|
|
||||||
'name': listname,
|
|
||||||
'url': listinfo['url'],
|
|
||||||
'lastUpdate': listinfo['lastUpdate']
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
c.view('tools/tools_appslists_list', {
|
|
||||||
appslists: list
|
|
||||||
});
|
});
|
||||||
}, 'GET');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a new apps list
|
|
||||||
app.post('#/tools/appslists', function (c) {
|
|
||||||
list = {
|
|
||||||
'name' : c.params['appslist_name'],
|
|
||||||
'url' : c.params['appslist_url']
|
|
||||||
}
|
|
||||||
|
|
||||||
c.api('/appslists', function(data) {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/appslists/' + list.name);
|
|
||||||
}, 'PUT', list);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Show appslist info and operations
|
|
||||||
app.get('#/tools/appslists/:appslist', function (c) {
|
|
||||||
c.api('/appslists', function(data) {
|
|
||||||
if (typeof data[c.params['appslist']] !== 'undefined') {
|
|
||||||
list = {
|
|
||||||
'name' : c.params['appslist'],
|
|
||||||
'url': data[c.params['appslist']]['url'],
|
|
||||||
'lastUpdate': data[c.params['appslist']]['lastUpdate'],
|
|
||||||
'removable' : (c.params['appslist'] !== 'yunohost') ? true : false // Do not remove default apps list
|
|
||||||
};
|
|
||||||
c.view('tools/tools_appslists_info', {appslist: list});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c.flash('warning', y18n.t('appslists_unknown_list', [c.params['appslist']]));
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/appslists');
|
|
||||||
}
|
|
||||||
}, 'GET');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Refresh available apps list
|
|
||||||
app.get('#/tools/appslists/refresh', function (c) {
|
|
||||||
c.api('/appslists', function(data) {
|
|
||||||
// c.redirect(store.get('path'));
|
|
||||||
c.redirect('#/apps/install');
|
|
||||||
}, 'PUT');
|
|
||||||
});
|
|
||||||
|
|
||||||
// Refresh specific apps list
|
|
||||||
app.get('#/tools/appslists/:appslist/refresh', function (c) {
|
|
||||||
c.api('/appslists', function(data) {
|
|
||||||
c.redirect('#/tools/appslists');
|
|
||||||
}, 'PUT', {'name' : c.params['appslist']});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Remove apps list
|
|
||||||
app.get('#/tools/appslists/:appslist/remove', function (c) {
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('appslist'),
|
|
||||||
y18n.t('appslists_confirm_remove', [c.params['app']]),
|
|
||||||
function() {
|
|
||||||
c.api('/appslists', function() {
|
|
||||||
c.redirect('#/tools/appslists');
|
|
||||||
}, 'DELETE', {'name' : c.params['appslist']});
|
|
||||||
},
|
|
||||||
function() {
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/tools/appslists/'+ c.params['appslist']);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -38,12 +38,12 @@
|
||||||
**/
|
**/
|
||||||
function updateGroup(model, params) {
|
function updateGroup(model, params) {
|
||||||
var type = params.type;
|
var type = params.type;
|
||||||
var operation = params.operation;
|
var action = params.action;
|
||||||
var item = params.item;
|
var item = params.item;
|
||||||
var groupname = params.group;
|
var groupname = params.group;
|
||||||
var group = data.groups[groupname];
|
var group = data.groups[groupname];
|
||||||
var to = (operation == 'add')?group[type]:group[type + 'Inv'];
|
var to = (action == 'add')?group[type]:group[type + 'Inv'];
|
||||||
var from = (operation == 'add')?group[type+'Inv']:group[type];
|
var from = (action == 'add')?group[type+'Inv']:group[type];
|
||||||
// Do nothing, if array of destination already contains the item
|
// Do nothing, if array of destination already contains the item
|
||||||
if (from.indexOf(item) === -1) return;
|
if (from.indexOf(item) === -1) return;
|
||||||
|
|
||||||
|
@ -57,17 +57,17 @@
|
||||||
var params = {}; var url;
|
var params = {}; var url;
|
||||||
if (type == 'members') {
|
if (type == 'members') {
|
||||||
url = '/users/groups/' + groupname;
|
url = '/users/groups/' + groupname;
|
||||||
params[operation] = [item];
|
params[action] = [item];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
url = '/users/permissions/' + item;
|
url = '/users/permissions/' + item;
|
||||||
params[operation] = [groupname];
|
params[action] = [groupname];
|
||||||
}
|
}
|
||||||
c.api(url, function(data_update) {
|
c.api('PUT', url, params, function(data_update) {
|
||||||
to.push(item);
|
to.push(item);
|
||||||
from.splice(from.indexOf(item), 1);
|
from.splice(from.indexOf(item), 1);
|
||||||
updateView(data);
|
updateView(data);
|
||||||
}, 'PUT', params);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,23 +91,35 @@
|
||||||
var rendered = c.render('views/user/group_list.ms', model);
|
var rendered = c.render('views/user/group_list.ms', model);
|
||||||
rendered.swap(function () {
|
rendered.swap(function () {
|
||||||
// Add click event to get a nice "reactive" interface
|
// Add click event to get a nice "reactive" interface
|
||||||
jQuery(".group-update").on('click', function (e) {
|
$("button[data-action='add'], button[data-action='remove']").on('click', function (e) {
|
||||||
updateGroup(model, jQuery(this)[0].dataset);
|
updateGroup(model, $(this)[0].dataset);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
jQuery(".group-add-user").on('click', function (e) {
|
$('button[data-action="add-user-specific-permission"]').on('click', function (e) {
|
||||||
data.groups[$(this)[0].dataset.user].display = true;
|
data.groups[$(this).data("user")].display = true;
|
||||||
updateView(data);
|
updateView(data);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
$('button[data-action="delete-group"]').on('click', function (e) {
|
||||||
|
|
||||||
|
var group = $(this).data("group");
|
||||||
|
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('groups'),
|
||||||
|
$('<div>'+ y18n.t('confirm_delete', [group]) +'</div>'),
|
||||||
|
function() {
|
||||||
|
c.api('DELETE', '/users/groups/'+ group, {}, function(data) { c.refresh(); });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
app.get('#/groups', function (c) {
|
app.get('#/groups', function (c) {
|
||||||
c.api('/users/groups?full&include_primary_groups', function(data_groups) {
|
c.api('GET', '/users/groups?full&include_primary_groups', {}, function(data_groups) {
|
||||||
c.api('/users', function(data_users) {
|
c.api('GET', '/users', {}, function(data_users) {
|
||||||
c.api('/users/permissions?short', function(data_permissions) {
|
c.api('GET', '/users/permissions?short', {}, function(data_permissions) {
|
||||||
//var perms = data_permissions.permissions;
|
//var perms = data_permissions.permissions;
|
||||||
var specific_perms = {};
|
var specific_perms = {};
|
||||||
var all_perms = data_permissions.permissions;
|
var all_perms = data_permissions.permissions;
|
||||||
|
@ -166,33 +178,9 @@
|
||||||
|
|
||||||
app.post('#/groups/create', function (c) {
|
app.post('#/groups/create', function (c) {
|
||||||
c.params['groupname'] = c.params['groupname'].replace(' ', '_').toLowerCase();
|
c.params['groupname'] = c.params['groupname'].replace(' ', '_').toLowerCase();
|
||||||
c.api('/users/groups', function(data) {
|
c.api('POST', '/users/groups', c.params.toHash(), function(data) {
|
||||||
c.redirect('#/groups');
|
c.redirect_to('#/groups');
|
||||||
}, 'POST', c.params.toHash());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('#/groups/:group/delete', function (c) {
|
|
||||||
|
|
||||||
var params = {};
|
|
||||||
|
|
||||||
// make confirm content
|
|
||||||
var confirmModalContent = $('<div>'+ y18n.t('confirm_delete', [c.params['group']]) +'</div>');
|
|
||||||
|
|
||||||
// display confirm modal
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('groups'),
|
|
||||||
confirmModalContent,
|
|
||||||
function(){
|
|
||||||
c.api('/users/groups/'+ c.params['group'], function(data) {
|
|
||||||
c.redirect('#/groups');
|
|
||||||
}, 'DELETE', params);
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
//store.clear('slide');
|
|
||||||
c.redirect('#/groups');
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -202,14 +190,14 @@
|
||||||
|
|
||||||
// List existing users
|
// List existing users
|
||||||
app.get('#/users', function (c) {
|
app.get('#/users', function (c) {
|
||||||
c.api('/users', function(data) { // http://api.yunohost.org/#!/user/user_list_get_3
|
c.api('GET', '/users', {}, function(data) {
|
||||||
c.view('user/user_list', data);
|
c.view('user/user_list', data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create user form
|
// Create user form
|
||||||
app.get('#/users/create', function (c) {
|
app.get('#/users/create', function (c) {
|
||||||
c.api('/domains', function(data) { // http://api.yunohost.org/#!/domain/domain_list_get_2
|
c.api('GET', '/domains', {}, function(data) {
|
||||||
|
|
||||||
// Password min length
|
// Password min length
|
||||||
data.password_min_length = PASSWORD_MIN_LENGTH;
|
data.password_min_length = PASSWORD_MIN_LENGTH;
|
||||||
|
@ -229,8 +217,7 @@
|
||||||
app.post('#/users/create', function (c) {
|
app.post('#/users/create', function (c) {
|
||||||
if (c.params['password'] == c.params['confirmation']) {
|
if (c.params['password'] == c.params['confirmation']) {
|
||||||
if (c.params['password'].length < PASSWORD_MIN_LENGTH) {
|
if (c.params['password'].length < PASSWORD_MIN_LENGTH) {
|
||||||
c.flash('fail', y18n.t('password_too_short'));
|
c.flash('fail', y18n.t('passwords_too_short'));
|
||||||
store.clear('slide');
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Force unit or disable quota
|
// Force unit or disable quota
|
||||||
|
@ -242,28 +229,63 @@
|
||||||
// Compute email field
|
// Compute email field
|
||||||
c.params['mail'] = c.params['email'] + c.params['domain'];
|
c.params['mail'] = c.params['email'] + c.params['domain'];
|
||||||
|
|
||||||
c.api('/users', function(data) { // http://api.yunohost.org/#!/user/user_create_post_2
|
c.api('POST', '/users', c.params.toHash(), function(data) {
|
||||||
c.redirect('#/users');
|
c.redirect_to('#/users');
|
||||||
}, 'POST', c.params.toHash());
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.flash('fail', y18n.t('passwords_dont_match'));
|
c.flash('fail', y18n.t('passwords_dont_match'));
|
||||||
store.clear('slide');
|
|
||||||
//c.redirect('#/users/create');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show user information
|
// Show user information
|
||||||
app.get('#/users/:user', function (c) {
|
app.get('#/users/:user', function (c) {
|
||||||
c.api('/users/'+ c.params['user'], function(data) { // http://api.yunohost.org/#!/user/user_info_get_0
|
c.api('GET', '/users/'+ c.params['user'], {}, function(data) {
|
||||||
c.view('user/user_info', data);
|
c.view('user/user_info', data, function() {
|
||||||
|
|
||||||
|
// Configure delete button behavior
|
||||||
|
$('button[data-action="delete"]').on("click", function() {
|
||||||
|
var user = $(this).data("user");
|
||||||
|
|
||||||
|
var params = {};
|
||||||
|
|
||||||
|
// make confirm content
|
||||||
|
var purgeCheckbox = '<div><input type="checkbox" id="purge-user-data" name="purge-user-data"> <label for="purge-user-data">'+ y18n.t('purge_user_data_checkbox', [user]) +'</label></div>';
|
||||||
|
var purgeAlertMessage = '<div class="danger" style="display: none">⚠ '+ y18n.t('purge_user_data_warning') +'</div>';
|
||||||
|
var confirmModalContent = $('<div>'+ y18n.t('confirm_delete', [user]) +'<br><br>'+ purgeCheckbox +'<br>'+ purgeAlertMessage +'</div>');
|
||||||
|
|
||||||
|
// display confirm modal
|
||||||
|
c.confirm(
|
||||||
|
y18n.t('users'),
|
||||||
|
confirmModalContent,
|
||||||
|
function(){
|
||||||
|
c.api('DELETE', '/users/'+ user, params, function(data) {
|
||||||
|
c.redirect_to('#/users');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// toggle purge warning and parameter
|
||||||
|
confirmModalContent.find("input").click(function(){
|
||||||
|
|
||||||
|
if (confirmModalContent.find("input").is(':checked')) {
|
||||||
|
params.purge = "";
|
||||||
|
confirmModalContent.find(".danger").show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete params.purge;
|
||||||
|
confirmModalContent.find(".danger").hide();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Edit user form
|
// Edit user form
|
||||||
app.get('#/users/:user/edit', function (c) {
|
app.get('#/users/:user/edit', function (c) {
|
||||||
c.api('/users/'+ c.params['user'], function(data) { // http://api.yunohost.org/#!/user/user_info_get_0
|
c.api('GET', '/users/'+ c.params['user'], {}, function(data) {
|
||||||
c.api('/domains', function(dataDomains) { // http://api.yunohost.org/#!/domain/domain_list_get_2
|
c.api('GET', '/domains', {}, function(dataDomains) {
|
||||||
|
|
||||||
// Password min length
|
// Password min length
|
||||||
data.password_min_length = PASSWORD_MIN_LENGTH;
|
data.password_min_length = PASSWORD_MIN_LENGTH;
|
||||||
|
@ -314,7 +336,7 @@
|
||||||
// Update user information
|
// Update user information
|
||||||
app.put('#/users/:user', function (c) {
|
app.put('#/users/:user', function (c) {
|
||||||
// Get full user object
|
// Get full user object
|
||||||
c.api('/users/'+ c.params['user'], function(user) {
|
c.api('GET', '/users/'+ c.params['user'], {}, function(user) {
|
||||||
// Force unit or disable quota
|
// Force unit or disable quota
|
||||||
if (c.params['mailbox_quota']) {
|
if (c.params['mailbox_quota']) {
|
||||||
c.params['mailbox_quota'] += "M";
|
c.params['mailbox_quota'] += "M";
|
||||||
|
@ -353,79 +375,32 @@
|
||||||
|
|
||||||
if ($.isEmptyObject(params)) {
|
if ($.isEmptyObject(params)) {
|
||||||
c.flash('fail', y18n.t('error_modify_something'));
|
c.flash('fail', y18n.t('error_modify_something'));
|
||||||
store.clear('slide');
|
c.redirect_to('#/users/'+ c.params['user'] + '/edit', {slide: false});
|
||||||
c.redirect('#/users/'+ c.params['user'] + '/edit');
|
|
||||||
} else {
|
} else {
|
||||||
if (params['password']) {
|
if (params['password']) {
|
||||||
if (params['password'] == params['confirmation']) {
|
if (params['password'] == params['confirmation']) {
|
||||||
if (params['password'].length < PASSWORD_MIN_LENGTH) {
|
if (params['password'].length < PASSWORD_MIN_LENGTH) {
|
||||||
c.flash('fail', y18n.t('password_too_short'));
|
c.flash('fail', y18n.t('passwords_too_short'));
|
||||||
store.clear('slide');
|
c.redirect_to('#/users/'+ c.params['user'] + '/edit', {slide: false});
|
||||||
c.redirect('#/users/'+ c.params['user'] + '/edit');
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
params['change_password'] = params['password'];
|
params['change_password'] = params['password'];
|
||||||
c.api('/users/'+ c.params['user'], function(data) { // http://api.yunohost.org/#!/user/user_update_put_1
|
c.api('PUT', '/users/'+ c.params['user'], params, function(data) {
|
||||||
c.redirect('#/users/'+ c.params['user']);
|
c.redirect_to('#/users/'+ c.params['user']);
|
||||||
}, 'PUT', params);
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
c.flash('fail', y18n.t('passwords_dont_match'));
|
c.flash('fail', y18n.t('passwords_dont_match'));
|
||||||
store.clear('slide');
|
c.redirect_to('#/users/'+ c.params['user'] + '/edit', {slide: false});
|
||||||
c.redirect('#/users/'+ c.params['user'] + '/edit');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
c.api('/users/'+ c.params['user'], function(data) { // http://api.yunohost.org/#!/user/user_update_put_1
|
c.api('PUT', '/users/'+ c.params['user'], params, function(data) {
|
||||||
c.redirect('#/users/'+ c.params['user']);
|
c.redirect_to('#/users/'+ c.params['user']);
|
||||||
}, 'PUT', params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 'GET');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Remove existing user
|
|
||||||
app.get('#/users/:user/delete', function (c) {
|
|
||||||
|
|
||||||
var params = {};
|
|
||||||
|
|
||||||
// make confirm content
|
|
||||||
var purgeCheckbox = '<div><input type="checkbox" id="purge-user-data" name="purge-user-data"> <label for="purge-user-data">'+ y18n.t('purge_user_data_checkbox', [c.params['user']]) +'</label></div>';
|
|
||||||
var purgeAlertMessage = '<div class="danger" style="display: none">⚠ '+ y18n.t('purge_user_data_warning') +'</div>';
|
|
||||||
var confirmModalContent = $('<div>'+ y18n.t('confirm_delete', [c.params['user']]) +'<br><br>'+ purgeCheckbox +'<br>'+ purgeAlertMessage +'</div>');
|
|
||||||
|
|
||||||
// display confirm modal
|
|
||||||
c.confirm(
|
|
||||||
y18n.t('users'),
|
|
||||||
confirmModalContent,
|
|
||||||
function(){
|
|
||||||
c.api('/users/'+ c.params['user'], function(data) { // http://api.yunohost.org/#!/user/user_delete_delete_4
|
|
||||||
c.redirect('#/users');
|
|
||||||
}, 'DELETE', params);
|
|
||||||
},
|
|
||||||
function(){
|
|
||||||
store.clear('slide');
|
|
||||||
c.redirect('#/users/'+ c.params['user']);
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
// toggle purge warning and parameter
|
|
||||||
confirmModalContent.find("input").click(function(){
|
|
||||||
|
|
||||||
if (confirmModalContent.find("input").is(':checked')) {
|
|
||||||
params.purge = "";
|
|
||||||
confirmModalContent.find(".warning").show();
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
delete params.purge;
|
|
||||||
confirmModalContent.find(".warning").hide();
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -8,82 +8,15 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
app.bind('login', function(e, data) {
|
app.bind('login', function(e, data) {
|
||||||
c.api('/users', function(data) {
|
c.api('GET', '/users', {}, function(data) {
|
||||||
// Warn admin if no users are created.
|
// Warn admin if no users are created.
|
||||||
if (typeof data.users !== 'undefined' && data.users.length === 0) {
|
if (typeof data.users !== 'undefined' && data.users.length === 0) {
|
||||||
c.flash('warning', y18n.t('warning_first_user'));
|
c.flash('warning', y18n.t('warning_first_user'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
c.api('GET', '/versions', {}, function(data) {
|
||||||
* Disabling this for now because there's a duplicate Access Allow
|
$('#yunohost-version').html(y18n.t('footer_version', [data.yunohost.version, data.yunohost.repo]));
|
||||||
* Origin header thing preventing it from working and people keep
|
c.hideLoader();
|
||||||
* complaining about it and we havent effectively used this in 2
|
|
||||||
* years anyway despite various security issues.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
// Get security feed and display new items
|
|
||||||
var securityFeed = 'https://yunohost.org/security.rss';
|
|
||||||
var forumUrl = 'https://forum.yunohost.org';
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: securityFeed,
|
|
||||||
// dataType: (jQuery.browser.msie) ? "text" : "xml",
|
|
||||||
dataType: "xml"
|
|
||||||
})
|
|
||||||
.done(function(xml){
|
|
||||||
// Get viewed security alerts from cookie
|
|
||||||
var viewedItems = Cookies.get('ynhSecurityViewedItems') || [];
|
|
||||||
|
|
||||||
// Get 6 month earlier date
|
|
||||||
var SixMonthEarlier = new Date();
|
|
||||||
SixMonthEarlier.setMonth(SixMonthEarlier.getMonth() - 6);
|
|
||||||
|
|
||||||
// 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 description=$('description', v).text();
|
|
||||||
// description=description.replace('href="/','href="'+forumUrl+'/');
|
|
||||||
|
|
||||||
var item = {
|
|
||||||
guid: $('guid', v).text(),
|
|
||||||
title: $('title', v).text(),
|
|
||||||
url: link,
|
|
||||||
// desc: description,
|
|
||||||
date: new Date($('pubDate', v).text()),
|
|
||||||
};
|
|
||||||
|
|
||||||
// If item is not already viewed and is not older than 6 month
|
|
||||||
if (viewedItems.indexOf(item.guid) === -1 && (item.date.getTime() > SixMonthEarlier.getTime())) {
|
|
||||||
// Show security message to administrator
|
|
||||||
var warning = item.title + ' - ' +
|
|
||||||
item.date.toISOString().substring(0, 10) +
|
|
||||||
' (<a href="'+ item.url +'" class="alert-link" target="_blank">'+y18n.t('read_more')+'</a>)';
|
|
||||||
c.flash('warning', warning);
|
|
||||||
// Store viewed item
|
|
||||||
viewedItems.push(item.guid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Saved viewed items to cookie
|
|
||||||
Cookies.set('ynhSecurityViewedItems', viewedItems, {
|
|
||||||
expires: 7
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.fail(function(stuff) {
|
|
||||||
c.flash('fail', y18n.t('error_retrieve_feed', [securityFeed]));
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
c.api("/diagnosis", function(data) {
|
|
||||||
versions = data.packages;
|
|
||||||
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost.version, versions.yunohost.repo]));
|
|
||||||
if (data.security["CVE-2017-5754"].vulnerable) {
|
|
||||||
c.flash('danger', y18n.t('meltdown'));
|
|
||||||
}
|
|
||||||
$('div.loader').remove();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
function prefetchDomains(req) {
|
function prefetchDomains(req) {
|
||||||
// Preload domains list.
|
// Preload domains list.
|
||||||
req.params.domains = [];
|
req.params.domains = [];
|
||||||
req.api('/domains', function(data) {
|
req.api('GET', '/domains', {}, function(data) {
|
||||||
req.params.domains = data.domains;
|
req.params.domains = data.domains;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
function prefetchUsers(req){
|
function prefetchUsers(req){
|
||||||
// Preload users lists.
|
// Preload users lists.
|
||||||
req.params.users = [];
|
req.params.users = [];
|
||||||
req.api('/users', function(data) {
|
req.api('GET', '/users', {}, function(data) {
|
||||||
req.params.users = data.users;
|
req.params.users = data.users;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@
|
||||||
app.before(/domains\/add/, prefetchDomains);
|
app.before(/domains\/add/, prefetchDomains);
|
||||||
app.before(/apps\/install\//, prefetchDomains);
|
app.before(/apps\/install\//, prefetchDomains);
|
||||||
app.before(/apps\/install\//, prefetchUsers);
|
app.before(/apps\/install\//, prefetchUsers);
|
||||||
|
app.before(/apps\/install\/custom\//, prefetchDomains);
|
||||||
|
app.before(/apps\/install\/custom\//, prefetchUsers);
|
||||||
app.before(/apps\/\w+\/actions/, prefetchUsers);
|
app.before(/apps\/\w+\/actions/, prefetchUsers);
|
||||||
app.before(/apps\/\w+\/actions/, prefetchDomains);
|
app.before(/apps\/\w+\/actions/, prefetchDomains);
|
||||||
app.before(/apps\/\w+\/config-panel/, prefetchUsers);
|
app.before(/apps\/\w+\/config-panel/, prefetchUsers);
|
||||||
|
|
|
@ -3,20 +3,64 @@
|
||||||
var app = Sammy.apps['#main'];
|
var app = Sammy.apps['#main'];
|
||||||
var store = app.store;
|
var store = app.store;
|
||||||
|
|
||||||
|
// The logic used to temporily disable transition is from
|
||||||
|
// https://stackoverflow.com/a/16575811
|
||||||
|
function whichTransitionEvent(){
|
||||||
|
var t;
|
||||||
|
var el = document.createElement('fakeelement');
|
||||||
|
var transitions = {
|
||||||
|
'transition':'transitionend',
|
||||||
|
'OTransition':'oTransitionEnd',
|
||||||
|
'MozTransition':'transitionend',
|
||||||
|
'WebkitTransition':'webkitTransitionEnd'
|
||||||
|
}
|
||||||
|
|
||||||
|
for(t in transitions){
|
||||||
|
if( el.style[t] !== undefined ){
|
||||||
|
return transitions[t];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var transitionEvent = whichTransitionEvent();
|
||||||
|
|
||||||
|
function resetSliders()
|
||||||
|
{
|
||||||
|
// Disable transition effects
|
||||||
|
$('#slider-container').addClass('notransition');
|
||||||
|
// Delete the left/right temporary stuff only used during animation
|
||||||
|
$('#slideTo').css('display', 'none');
|
||||||
|
$('#slideTo').html("");
|
||||||
|
$('#slideBack').css('display', 'none');
|
||||||
|
$('#slideBack').html("");
|
||||||
|
// Set the margin-left back to 0
|
||||||
|
$('#slider-container').css('margin-left', '0');
|
||||||
|
// c.f. the stackoverflow thread
|
||||||
|
$('#slider-container')[0].offsetHeight;
|
||||||
|
// Remove the binding to this event handler for next times
|
||||||
|
// Re-enable transition effects
|
||||||
|
$('#slider-container').removeClass('notransition');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helpers
|
* Helpers
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
app.helpers({
|
app.helpers({
|
||||||
|
|
||||||
// Serialize an object
|
//
|
||||||
serialize : function(obj) {
|
// Pacman loader management
|
||||||
var str = [];
|
//
|
||||||
for(var p in obj)
|
|
||||||
if (obj.hasOwnProperty(p)) {
|
showLoader: function() {
|
||||||
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
|
app.loaded = false; // Not sure if that's really useful ... this is from old code with no explanation what it really does ...
|
||||||
|
if ($('div.loader').length === 0) {
|
||||||
|
$('#main').append('<div class="loader loader-content"></div>');
|
||||||
}
|
}
|
||||||
return str.join("&");
|
},
|
||||||
|
|
||||||
|
hideLoader: function() {
|
||||||
|
app.loaded = true; // Not sure if that's really useful ... this is from old code with no explanation what it really does ...
|
||||||
|
$('div.loader').remove();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Flash helper to diplay instant notifications
|
// Flash helper to diplay instant notifications
|
||||||
|
@ -85,7 +129,7 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
// API call
|
// API call
|
||||||
api: function(uri, callback, method, data, websocket, callbackOnFailure) {
|
api: function(method, uri, data, callback, callbackOnFailure, websocket) {
|
||||||
c = this;
|
c = this;
|
||||||
|
|
||||||
method = typeof method !== 'undefined' ? method : 'GET';
|
method = typeof method !== 'undefined' ? method : 'GET';
|
||||||
|
@ -93,39 +137,14 @@
|
||||||
if (window.navigator && window.navigator.language && (typeof data.locale === 'undefined')) {
|
if (window.navigator && window.navigator.language && (typeof data.locale === 'undefined')) {
|
||||||
data.locale = y18n.locale || window.navigator.language.substr(0, 2);
|
data.locale = y18n.locale || window.navigator.language.substr(0, 2);
|
||||||
}
|
}
|
||||||
app.loaded = false;
|
|
||||||
if ($('div.loader').length === 0) {
|
c.showLoader();
|
||||||
$('#main').append('<div class="loader loader-content"></div>');
|
|
||||||
}
|
|
||||||
call = function(uri, callback, method, data, callbackOnFailure) {
|
call = function(uri, callback, method, data, callbackOnFailure) {
|
||||||
|
|
||||||
var args = data;
|
// Define default callback for failures
|
||||||
// TODO: change this code
|
|
||||||
if (uri === '/postinstall') {
|
|
||||||
var post_installing = false;
|
|
||||||
setInterval(function () {
|
|
||||||
post_installing = true;
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof callbackOnFailure !== 'function') {
|
if (typeof callbackOnFailure !== 'function') {
|
||||||
callbackOnFailure = function(xhr) {
|
callbackOnFailure = function(xhr) {
|
||||||
// Postinstall is a custom case, we have to wait that
|
|
||||||
// operation is done before doing anything
|
|
||||||
if ((uri === '/postinstall') && (post_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);
|
|
||||||
}
|
|
||||||
// Regular errors
|
|
||||||
else {
|
|
||||||
if (xhr.status == 200) {
|
if (xhr.status == 200) {
|
||||||
// Fail with 200, WTF
|
// Fail with 200, WTF
|
||||||
callback({});
|
callback({});
|
||||||
|
@ -176,13 +195,11 @@
|
||||||
console.log(xhr);
|
console.log(xhr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove loader if any
|
c.hideLoader();
|
||||||
$('div.loader').remove();
|
|
||||||
|
|
||||||
// Force scrollTop on page load
|
// Force scrollTop on page load
|
||||||
$('html, body').scrollTop(0);
|
$('html, body').scrollTop(0);
|
||||||
store.clear('slide');
|
store.clear('slide');
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,78 +254,17 @@
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Render view (cross-browser)
|
|
||||||
view: function (view, data, callback, enableSlide) {
|
// Ask confirmation to the user through the modal window
|
||||||
|
confirm: function(title, content, confirmCallback, cancelCallback) {
|
||||||
c = this;
|
c = this;
|
||||||
|
|
||||||
// Default
|
|
||||||
callback = typeof callback !== 'undefined' ? callback : function() {};
|
|
||||||
enableSlide = (typeof enableSlide !== 'undefined') ? enableSlide : true; // Change to false to disable animation
|
|
||||||
|
|
||||||
app.loaded = true;
|
|
||||||
|
|
||||||
// Hide loader and modal
|
|
||||||
$('div.loader').remove();
|
|
||||||
$('#modal').modal('hide');
|
|
||||||
|
|
||||||
// Render content
|
|
||||||
var rendered = this.render('views/'+ view +'.ms', data);
|
|
||||||
|
|
||||||
// Update content helper
|
|
||||||
var leSwap = function() {
|
|
||||||
rendered.swap(function() {
|
|
||||||
// Slide direction
|
|
||||||
if (enableSlide) {
|
|
||||||
$('.slide, .btn-breadcrumb a:not(:last-child)').on('click', function() {
|
|
||||||
$(this).addClass('active');
|
|
||||||
if ($(this).hasClass('back') || $(this).parent('.btn-breadcrumb').length) {
|
|
||||||
store.set('slide', 'back');
|
|
||||||
} else {
|
|
||||||
store.set('slide', 'to');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Paste <pre> helper
|
|
||||||
c.prePaste();
|
|
||||||
|
|
||||||
// Run callback
|
|
||||||
callback();
|
|
||||||
|
|
||||||
// Force scrollTop on page load
|
|
||||||
$('html, body').scrollTop(0);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Slide back effect
|
|
||||||
if (enableSlide && store.get('slide') == 'back') {
|
|
||||||
store.clear('slide');
|
|
||||||
$('#slideBack').css('display', 'none');
|
|
||||||
$('#slider-container').css('margin-left', '-100%');
|
|
||||||
$('#slideTo').show().html($('#main').html());
|
|
||||||
leSwap();
|
|
||||||
$('#slider-container').css('margin-left', '0px');
|
|
||||||
}
|
|
||||||
// Slide to effect
|
|
||||||
else if (enableSlide && store.get('slide') == 'to') {
|
|
||||||
store.clear('slide');
|
|
||||||
$('#slideTo').css('display', 'none');
|
|
||||||
$('#slider-container').css('margin-left', '0px');
|
|
||||||
$('#slideBack').show().html($('#main').html());
|
|
||||||
leSwap();
|
|
||||||
$('#slider-container').css('margin-left', '-100%');
|
|
||||||
}
|
|
||||||
// No slideing effect
|
|
||||||
else {
|
|
||||||
leSwap();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
confirm: function(title, content, confirmCallback, cancelCallback) {
|
|
||||||
// Default callbacks
|
// Default callbacks
|
||||||
confirmCallback = typeof confirmCallback !== 'undefined' ? confirmCallback : function() {};
|
confirmCallback = typeof confirmCallback !== 'undefined' ? confirmCallback : function() {};
|
||||||
cancelCallback = typeof cancelCallback !== 'undefined' ? cancelCallback : function() {};
|
cancelCallback = typeof cancelCallback !== 'undefined' ? cancelCallback : function() {};
|
||||||
|
|
||||||
|
c.hideLoader();
|
||||||
|
|
||||||
// Get modal element
|
// Get modal element
|
||||||
var box = $('#modal');
|
var box = $('#modal');
|
||||||
|
|
||||||
|
@ -335,12 +291,10 @@
|
||||||
|
|
||||||
$('#modal footer button').unbind( "click" );
|
$('#modal footer button').unbind( "click" );
|
||||||
// Reset & Hide modal
|
// Reset & Hide modal
|
||||||
box
|
box.removeClass('no-title').modal('hide');
|
||||||
.removeClass('no-title')
|
|
||||||
.modal('hide');
|
|
||||||
|
|
||||||
// Do corresponding callback
|
// Do corresponding callback
|
||||||
if ($(this).data('action') == 'confirm') {
|
if ($(this).data('modal-action') == 'confirm') {
|
||||||
confirmCallback();
|
confirmCallback();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -352,19 +306,162 @@
|
||||||
return box.modal('show');
|
return box.modal('show');
|
||||||
},
|
},
|
||||||
|
|
||||||
selectAllOrNone: function () {
|
|
||||||
// Remove active style from buttons
|
// Render view (cross-browser)
|
||||||
$(".select_all-none input").click(function(){ $(this).toggleClass("active"); });
|
view: function (view, data, callback) {
|
||||||
// Select all checkbox in this panel
|
c = this;
|
||||||
$(".select_all").click(function(){
|
|
||||||
$(this).parents(".panel").children(".list-group").find("input").prop("checked", true);
|
// Default
|
||||||
|
callback = typeof callback !== 'undefined' ? callback : function() {};
|
||||||
|
|
||||||
|
// Hide loader and modal
|
||||||
|
c.hideLoader();
|
||||||
|
$('#modal').modal('hide');
|
||||||
|
|
||||||
|
// Render content
|
||||||
|
var rendered = this.render('views/'+ view +'.ms', data);
|
||||||
|
|
||||||
|
// Update content helper
|
||||||
|
var leSwap = function() {
|
||||||
|
rendered.swap(function() {
|
||||||
|
// Clicking on those kind of CSS elements will trigger a
|
||||||
|
// slide effect i.e. the next view rendering will have
|
||||||
|
// store.get('slide') set to 'back' or 'to'
|
||||||
|
$('.slide, .btn-breadcrumb a:not(:last-child)').on('click', function() {
|
||||||
|
$(this).addClass('active');
|
||||||
|
if ($(this).hasClass('back') || $(this).parent('.btn-breadcrumb').length) {
|
||||||
|
store.set('slide', 'back');
|
||||||
|
} else {
|
||||||
|
store.set('slide', 'to');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// Deselect all checkbox in this panel
|
|
||||||
$(".select_none").click(function(){
|
// Force scrollTop on page load
|
||||||
$(this).parents(".panel").children(".list-group").find("input").prop("checked", false);
|
$('html, body').scrollTop(0);
|
||||||
|
|
||||||
|
// Run callback
|
||||||
|
callback();
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Slide back effect
|
||||||
|
if (store.get('slide') == 'back') {
|
||||||
|
|
||||||
|
store.clear('slide');
|
||||||
|
// Disable transition while we tweak CSS
|
||||||
|
$('#slider-container').addClass('notransition');
|
||||||
|
// "Delete" the left part of the slider
|
||||||
|
$('#slideBack').css('display', 'none');
|
||||||
|
|
||||||
|
// Push the slider to the left
|
||||||
|
$('#slider-container').css('margin-left', '-100%');
|
||||||
|
// slideTo is the right part, and should contain the old view,
|
||||||
|
// so we copypasta what's in the "center" slider (#main)
|
||||||
|
$('#slideTo').show().html($('#main').html());
|
||||||
|
// leSwap will put the new view in the "center" slider (#main)
|
||||||
|
leSwap();
|
||||||
|
|
||||||
|
// So now things look like:
|
||||||
|
// | |
|
||||||
|
// | the screen |
|
||||||
|
// | |
|
||||||
|
//
|
||||||
|
// . #main . #slideTo .
|
||||||
|
// . the new view . the old view .
|
||||||
|
// ^ ^
|
||||||
|
// margin-left: -100% currently shown
|
||||||
|
//
|
||||||
|
// =====>>> sliiiiide =====>>>
|
||||||
|
|
||||||
|
// Re-add transition effect
|
||||||
|
$('#slider-container').removeClass('notransition');
|
||||||
|
|
||||||
|
// add the transition event to detect the end of the transition effect
|
||||||
|
transitionEvent
|
||||||
|
&& $("#slider-container").off(transitionEvent)
|
||||||
|
&& $("#slider-container").on(transitionEvent, resetSliders);
|
||||||
|
|
||||||
|
// And actually play the transition effect that will move the container from left to right
|
||||||
|
$('#slider-container').css('margin-left', '0px');
|
||||||
|
}
|
||||||
|
// Slide to effect
|
||||||
|
else if (store.get('slide') == 'to') {
|
||||||
|
|
||||||
|
// Disable transition while we tweak CSS
|
||||||
|
$('#slider-container').addClass('notransition');
|
||||||
|
// "Delete" the right part of the slider
|
||||||
|
$('#slideTo').css('display', 'none');
|
||||||
|
// Push the slider to the right
|
||||||
|
$('#slider-container').css('margin-left', '0px');
|
||||||
|
// slideBack should contain the old view,
|
||||||
|
// so we copypasta what's in the "center" slider (#main)
|
||||||
|
$('#slideBack').show().html($('#main').html());
|
||||||
|
leSwap();
|
||||||
|
|
||||||
|
// So now things look like:
|
||||||
|
//
|
||||||
|
// | |
|
||||||
|
// | the screen |
|
||||||
|
// | |
|
||||||
|
//
|
||||||
|
// . . #slideBack . #main .
|
||||||
|
// . . the old view . the new view .
|
||||||
|
// ^ ^ ^
|
||||||
|
// margin-left: -100% currently shown
|
||||||
|
//
|
||||||
|
// <<<===== sliiiiide <<<=======
|
||||||
|
|
||||||
|
|
||||||
|
// Re-add transition effect
|
||||||
|
$('#slider-container').removeClass('notransition');
|
||||||
|
|
||||||
|
// add the transition event to detect the end of the transition effect
|
||||||
|
var transitionEvent = whichTransitionEvent();
|
||||||
|
transitionEvent
|
||||||
|
&& $("#slider-container").off(transitionEvent)
|
||||||
|
&& $("#slider-container").on(transitionEvent, resetSliders);
|
||||||
|
|
||||||
|
// And actually play the transition effect that will move the container from right to left
|
||||||
|
$('#slider-container').css('margin-left', '-100%');
|
||||||
|
}
|
||||||
|
// No slideing effect
|
||||||
|
else {
|
||||||
|
leSwap();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
redirect_to: function(destination, options) {
|
||||||
|
c = this;
|
||||||
|
|
||||||
|
options = options !== undefined ? options : {};
|
||||||
|
|
||||||
|
// If destination if the same as current url,
|
||||||
|
// we don't want to display the slide animation
|
||||||
|
// (or if the code explicitly state to disable slide animation)
|
||||||
|
if ((c.path.split("#")[1] == destination.split("#")[1]) || (options.slide == false))
|
||||||
|
{
|
||||||
|
store.clear('slide');
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a copy-pasta of some of the redirect/refresh code of
|
||||||
|
// sammy.js because for some reason calling the original
|
||||||
|
// redirect/refresh function in some context does not work >.>
|
||||||
|
// (e.g. if you're already on the page)
|
||||||
|
c.trigger('redirect', {to: destination});
|
||||||
|
c.app.last_location = c.path;
|
||||||
|
c.app.setLocation(destination);
|
||||||
|
c.app.trigger('location-changed');
|
||||||
|
},
|
||||||
|
|
||||||
|
refresh: function() {
|
||||||
|
c = this;
|
||||||
|
c.redirect_to(c.path, {slide: false});
|
||||||
|
},
|
||||||
|
|
||||||
|
//
|
||||||
|
// Array / object helpers
|
||||||
|
//
|
||||||
|
|
||||||
arraySortById: function(arr) {
|
arraySortById: function(arr) {
|
||||||
arr.sort(function(a, b){
|
arr.sort(function(a, b){
|
||||||
if (a.id > b.id) {
|
if (a.id > b.id) {
|
||||||
|
@ -385,103 +482,15 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
groupHooks: function(hooks, raw_infos){
|
// Serialize an object
|
||||||
var data = {};
|
serialize : function(obj) {
|
||||||
var rules = [
|
var str = [];
|
||||||
{
|
for(var p in obj)
|
||||||
id:'configuration',
|
if (obj.hasOwnProperty(p)) {
|
||||||
isIn:function (hook) {
|
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
|
||||||
return hook.indexOf('conf_')==0
|
|
||||||
}
|
}
|
||||||
|
return str.join("&");
|
||||||
}
|
}
|
||||||
];
|
|
||||||
|
|
||||||
$.each(hooks, function(i, hook) {
|
|
||||||
var group_id=hook;
|
|
||||||
var hook_size=(raw_infos && raw_infos[hook] && raw_infos[hook].size)?raw_infos[hook].size:0;
|
|
||||||
$.each(rules, function(i, rule) {
|
|
||||||
if (rule.isIn(hook)) {
|
|
||||||
group_id = 'adminjs_group_'+rule.id;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if(group_id in data) {
|
|
||||||
data[group_id] = {
|
|
||||||
name:y18n.t('hook_'+group_id),
|
|
||||||
value:data[group_id].value+','+hook,
|
|
||||||
description:data[group_id].description+', '+y18n.t('hook_'+hook),
|
|
||||||
size:data[group_id].size + hook_size
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data[group_id] = {
|
|
||||||
name:y18n.t('hook_'+group_id),
|
|
||||||
value:hook,
|
|
||||||
description:(group_id==hook)?y18n.t('hook_'+hook+'_desc'):y18n.t('hook_'+hook),
|
|
||||||
size:hook_size
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
|
|
||||||
ungroupHooks: function(system_parts,apps) {
|
|
||||||
var data = {};
|
|
||||||
data['apps'] = apps || [];
|
|
||||||
data['system'] = system_parts || [];
|
|
||||||
|
|
||||||
if (data['system'].constructor !== Array) {
|
|
||||||
data['system'] = [data['system']];
|
|
||||||
}
|
|
||||||
if (data['apps'].constructor !== Array) {
|
|
||||||
data['apps'] = [data['apps']];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some hook value contains multiple hooks separated by commas
|
|
||||||
var split_hooks = [];
|
|
||||||
$.each(data['system'], function(i, hook) {
|
|
||||||
split_hooks = split_hooks.concat(hook.split(','));
|
|
||||||
});
|
|
||||||
data['system'] = split_hooks;
|
|
||||||
|
|
||||||
if (data['system'].length == 0) {
|
|
||||||
delete data['system'];
|
|
||||||
}
|
|
||||||
if (data['apps'].length == 0) {
|
|
||||||
delete data['apps'];
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Paste <pre>
|
|
||||||
prePaste: function() {
|
|
||||||
var pasteButtons = $('button[data-paste-content],a[data-paste-content]');
|
|
||||||
pasteButtons.on('click', function(){
|
|
||||||
// Get paste content element
|
|
||||||
var preElement = $($(this).data('paste-content'));
|
|
||||||
|
|
||||||
// Add pacman loader
|
|
||||||
$('#main').append('<div class="loader loader-content"></div>');
|
|
||||||
|
|
||||||
// Send to paste.yunohost.org
|
|
||||||
$.ajax({
|
|
||||||
type: "POST",
|
|
||||||
url: 'https://paste.yunohost.org/documents',
|
|
||||||
data: preElement.text(),
|
|
||||||
})
|
|
||||||
.success(function(data, textStatus, jqXHR) {
|
|
||||||
window.open('https://paste.yunohost.org/' + data.key, '_blank');
|
|
||||||
})
|
|
||||||
.fail(function() {
|
|
||||||
c.flash('fail', y18n.t('paste_error'));
|
|
||||||
})
|
|
||||||
.always(function(){
|
|
||||||
// Remove pacman
|
|
||||||
$('div.loader').remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -181,9 +181,8 @@
|
||||||
sam.store.set('url', window.location.hostname + '/yunohost/api');
|
sam.store.set('url', window.location.hostname + '/yunohost/api');
|
||||||
|
|
||||||
if (sam.store.get('connected')) {
|
if (sam.store.get('connected')) {
|
||||||
this.api('/diagnosis', function(diagnosis) {
|
this.api('GET', '/versions', {}, function(data) {
|
||||||
versions = diagnosis.packages;
|
$('#yunohost-version').html(y18n.t('footer_version', [data.yunohost.version, data.yunohost.repo]));
|
||||||
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost.version, versions.yunohost.repo]));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@
|
||||||
"select_user": "Seleccioneu un usuari",
|
"select_user": "Seleccioneu un usuari",
|
||||||
"service_description": "Descripció:",
|
"service_description": "Descripció:",
|
||||||
"service_log": "Registre %s",
|
"service_log": "Registre %s",
|
||||||
"service_start_on_boot": "Iniciar a l'engegada: ",
|
"service_start_on_boot": "Iniciar a l'engegada",
|
||||||
"service_status": "Estat: ",
|
"service_status": "Estat: ",
|
||||||
"services": "Serveis",
|
"services": "Serveis",
|
||||||
"services_list": "Llista de serveis",
|
"services_list": "Llista de serveis",
|
||||||
|
@ -266,11 +266,11 @@
|
||||||
"swap": "Memòria d'intercanvi",
|
"swap": "Memòria d'intercanvi",
|
||||||
"system": "Sistema",
|
"system": "Sistema",
|
||||||
"system_apps": "Aplicacions",
|
"system_apps": "Aplicacions",
|
||||||
"system_apps_nothing": "No hi ha aplicacions per actualitzar.",
|
"system_apps_nothing": "Totes les aplicacions estan actualitzades!",
|
||||||
"system_delayed_upgrade": "S'ha posposat l'actualització",
|
"system_delayed_upgrade": "S'ha posposat l'actualització",
|
||||||
"system_delayed_upgrade_warning": "<b>%s</b> serà actualitzat automàticament durant la pròxima hora.",
|
"system_delayed_upgrade_warning": "<b>%s</b> serà actualitzat automàticament durant la pròxima hora.",
|
||||||
"system_packages": "Paquets",
|
"system_packages": "Paquets del sistema",
|
||||||
"system_packages_nothing": "No hi ha paquets per actualitzar.",
|
"system_packages_nothing": "Tots els paquets del sistema estan actualitzats!",
|
||||||
"system_update": "Actualització del sistema",
|
"system_update": "Actualització del sistema",
|
||||||
"system_upgrade": "Actualització del sistema",
|
"system_upgrade": "Actualització del sistema",
|
||||||
"system_upgrade_btn": "Actualització",
|
"system_upgrade_btn": "Actualització",
|
||||||
|
@ -354,7 +354,7 @@
|
||||||
"validity": "Validesa",
|
"validity": "Validesa",
|
||||||
"domain_is_eligible_for_ACME": "Aquest domini sembla estar configurat correctament per instal·lar el certificat Let's Encrypt!",
|
"domain_is_eligible_for_ACME": "Aquest domini sembla estar configurat correctament per instal·lar el certificat Let's Encrypt!",
|
||||||
"run": "Executar",
|
"run": "Executar",
|
||||||
"domain_not_eligible_for_ACME": "Aquest domini sembla que no està configurat per a un certificat Let's Encrypt. Comprova la configuració DNS i la accessibilitat del servidor HTTP.",
|
"domain_not_eligible_for_ACME": "Aquest domini sembla que no està configurat per a un certificat Let's Encrypt. Comprova la configuració DNS i la accessibilitat del servidor HTTP. Les seccions «registres DNS» i «Web» de <a href='#/diagnosis'>la pàgina de diagnòstic</a> pot ajudar-vos a entendre el que està mal configurat.",
|
||||||
"install_letsencrypt_cert": "Instal·la un certificat Let's Encrypt",
|
"install_letsencrypt_cert": "Instal·la un certificat Let's Encrypt",
|
||||||
"manually_renew_letsencrypt_message": "El certificat es renovarà automàticament durant els últims 15 dies de validesa. El podeu renovar manualment si ho desitgeu. (No recomanat).",
|
"manually_renew_letsencrypt_message": "El certificat es renovarà automàticament durant els últims 15 dies de validesa. El podeu renovar manualment si ho desitgeu. (No recomanat).",
|
||||||
"manually_renew_letsencrypt": "Renovar manualment ara",
|
"manually_renew_letsencrypt": "Renovar manualment ara",
|
||||||
|
@ -471,5 +471,13 @@
|
||||||
"app_state_low_quality": "baixa qualitat",
|
"app_state_low_quality": "baixa qualitat",
|
||||||
"all": "Tot",
|
"all": "Tot",
|
||||||
"run_first_diagnosis": "Executa el diagnòstic inicial",
|
"run_first_diagnosis": "Executa el diagnòstic inicial",
|
||||||
"diagnosis_first_run": "La funció de diagnòstic intentarà identificar problemes habituals de diferents aspectes del servidor per tal d'assegurar que tot funcioni de la millor manera possible. No tingueu por si veieu uns quants errors just després de configurar el servidor: està precisament fet per ajudar a identificar els problemes i oferir una guia de com arreglar-los. El diagnòstic també s'executarà dues vegades al dia i enviarà un correu a l'administrador si apareix algun error."
|
"diagnosis_first_run": "La funció de diagnòstic intentarà identificar problemes habituals de diferents aspectes del servidor per tal d'assegurar que tot funcioni de la millor manera possible. No tingueu por si veieu uns quants errors just després de configurar el servidor: està precisament fet per ajudar a identificar els problemes i oferir una guia de com arreglar-los. El diagnòstic també s'executarà dues vegades al dia i s'enviarà un correu a l'administrador si es troben errors.",
|
||||||
|
"confirm_service_restart": "Esteu segur de voler reiniciar %s?",
|
||||||
|
"group_explain_visitors_needed_for_external_client": "Vigileu ja que s'ha de permetre els visitants en algunes aplicacions si voleu utilitzar-les amb clients externs. És el cas, per exemple, de Nextcloud si voleu utilitzar el client de sincronització en el telèfon mòbil o en l'ordinador.",
|
||||||
|
"groups": "Grups",
|
||||||
|
"restart": "Reiniciar",
|
||||||
|
"unmaintained_details": "Fa temps que no es manté aquesta aplicació i la persona que la mantenia ja no ho fa o no té temps per fer-ho. Us convidem a mirar el repositori de l'aplicació per oferir la vostra ajuda",
|
||||||
|
"issues": "%s problemes",
|
||||||
|
"operation_failed_explanation": "Aquesta operació ha fallat! Ens sap molt greu :( Podeu intentar <a href='https://yunohost.org/help'>demanar ajuda</a>. Si us plau doneu *el registre complet* de l'operació a la gent que intenta ajudar-vos. Podeu fer-ho fent clic al botó verd \"Compartir amb Yunopaste\". Quan compartiu els registres, YunoHost intentarà anonimitzar automàticament dades privades com els noms de domini i les IPs.",
|
||||||
|
"diagnosis_explanation": "La funció de diagnòstic intentarà identificar els errors més comuns en diferents aspectes del servidor per verificar que tot funciona correctament. El diagnòstic s'executa automàticament dues vegades al dia i s'envia un correu electrònic a l'administrador si es troben errors. Tingueu en compte que no tots els tests seran rellevants si no s'utilitzen algunes funcions específiques (com per exemple XMPP) o pot ser que falli si teniu un sistema amb una configuració complexa. En aquests casos, i si sabeu el que feu, podeu ignorar els problemes o avisos corresponents."
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"add": "Hinzufügen",
|
"add": "Hinzufügen",
|
||||||
"administration_password": "Verwaltungspasswort",
|
"administration_password": "Verwaltungspasswort",
|
||||||
"allowed_users": "Zugelassene Benutzer",
|
"allowed_users": "Zugelassene Benutzer",
|
||||||
"api_not_responding": "API antwortet nicht",
|
"api_not_responding": "Die YunoHost-API antwortet nicht. Vielleicht ist 'yunohost-api' ausgefallen oder wurde neu gestartet?",
|
||||||
"app_access": "Zugriffsrechte",
|
"app_access": "Zugriffsrechte",
|
||||||
"app_access_addall_btn": "Zugriff für alle zulassen",
|
"app_access_addall_btn": "Zugriff für alle zulassen",
|
||||||
"app_access_addall_desc": "Alle existierenden Benutzer werden Zugriff auf %s haben.",
|
"app_access_addall_desc": "Alle existierenden Benutzer werden Zugriff auf %s haben.",
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
"app_access_title": "%s Zugriffsrechte",
|
"app_access_title": "%s Zugriffsrechte",
|
||||||
"app_debug_no_logs": "Anwendungslogs stehen nicht zur Verfügung",
|
"app_debug_no_logs": "Anwendungslogs stehen nicht zur Verfügung",
|
||||||
"app_debug_tab": "Debugging Informationen anzeigen",
|
"app_debug_tab": "Debugging Informationen anzeigen",
|
||||||
"app_info_access_desc": "Zugriffsrechte verwalten. Erlaubte Nutzer: %s",
|
"app_info_access_desc": "Gruppen / Benutzer, die auf diese App zugreifen dürfen:",
|
||||||
"app_info_debug_desc": "Debugging Informationen für diese Applikation anzeigen.",
|
"app_info_debug_desc": "Debugging Informationen für diese Applikation anzeigen.",
|
||||||
"app_info_default_desc": "Hauptdomain auf diese App (%s) weiterleiten.",
|
"app_info_default_desc": "Hauptdomain auf diese App (%s) weiterleiten.",
|
||||||
"app_info_uninstall_desc": "Diese App löschen.",
|
"app_info_uninstall_desc": "Diese App löschen.",
|
||||||
|
@ -120,7 +120,7 @@
|
||||||
"hook_data_home": "Benutzerdaten",
|
"hook_data_home": "Benutzerdaten",
|
||||||
"hook_data_home_desc": "Die Daten des Benutzers werden gespeichert unter /home/USER",
|
"hook_data_home_desc": "Die Daten des Benutzers werden gespeichert unter /home/USER",
|
||||||
"hook_data_mail": "E-Mail",
|
"hook_data_mail": "E-Mail",
|
||||||
"hook_data_mail_desc": "E-Mail Adressen auf dem Server",
|
"hook_data_mail_desc": "Roth-E-Mails auf dem Server gespeichert",
|
||||||
"hostname": "Hostname",
|
"hostname": "Hostname",
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"inactive": "Inaktiv",
|
"inactive": "Inaktiv",
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
"local_ip": "Lokale IP",
|
"local_ip": "Lokale IP",
|
||||||
"log": "Log",
|
"log": "Log",
|
||||||
"logged_in": "Angemeldet",
|
"logged_in": "Angemeldet",
|
||||||
"logged_out": "Ausgeloggt",
|
"logged_out": "Abgemeldet",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"logout": "Abmelden",
|
"logout": "Abmelden",
|
||||||
"mailbox_quota_description": "Zum Beispiel, eine CD verfügt über 700M, eine über 4700M.",
|
"mailbox_quota_description": "Zum Beispiel, eine CD verfügt über 700M, eine über 4700M.",
|
||||||
|
@ -202,7 +202,7 @@
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
"select_user": "Benutzer auswählen",
|
"select_user": "Benutzer auswählen",
|
||||||
"service_log": "%s Log",
|
"service_log": "%s Log",
|
||||||
"service_start_on_boot": "Beim Hochfahren starten: ",
|
"service_start_on_boot": "Beim Hochfahren starten",
|
||||||
"service_status": "Status: ",
|
"service_status": "Status: ",
|
||||||
"services": "Dienste",
|
"services": "Dienste",
|
||||||
"services_list": "Dienstübersicht",
|
"services_list": "Dienstübersicht",
|
||||||
|
@ -218,11 +218,11 @@
|
||||||
"swap": "Auslagerungsspeicher",
|
"swap": "Auslagerungsspeicher",
|
||||||
"system": "System",
|
"system": "System",
|
||||||
"system_apps": "Apps",
|
"system_apps": "Apps",
|
||||||
"system_apps_nothing": "Es gibt keine Aktualisierungen für deine Apps.",
|
"system_apps_nothing": "Allen Apps sind auf dem neuesten Stand!",
|
||||||
"system_delayed_upgrade": "Zurückgestellte Aktualisierung",
|
"system_delayed_upgrade": "Zurückgestellte Aktualisierung",
|
||||||
"system_delayed_upgrade_warning": "<b>%s</b> wird automatisch innerhalb der nächsten Stunde aktualisiert.",
|
"system_delayed_upgrade_warning": "<b>%s</b> wird automatisch innerhalb der nächsten Stunde aktualisiert.",
|
||||||
"system_packages": "Pakete",
|
"system_packages": "Systempakete",
|
||||||
"system_packages_nothing": "Keine Pakete zur Aktualisierung gefunden.",
|
"system_packages_nothing": "Alle Systempakete sind auf dem neuesten Stand!",
|
||||||
"system_update": "System aktualisieren",
|
"system_update": "System aktualisieren",
|
||||||
"system_upgrade": "Systemaktualisierung",
|
"system_upgrade": "Systemaktualisierung",
|
||||||
"system_upgrade_btn": "Aktualisieren",
|
"system_upgrade_btn": "Aktualisieren",
|
||||||
|
@ -347,11 +347,11 @@
|
||||||
"tools_reboot": "Starte deine Server neu",
|
"tools_reboot": "Starte deine Server neu",
|
||||||
"tools_reboot_btn": "Neustart",
|
"tools_reboot_btn": "Neustart",
|
||||||
"tools_reboot_done": "Starte neu...",
|
"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_rebooting": "Dein Server startet neu. Um zur Verwaltungsoberfläche zurückzukehren, musst du warten bis der Server hochgefahren ist. Prüfen kannst du es, in dem du die Seite neu lädst (F5).",
|
||||||
"tools_shutdown": "Fahre deinen Server herunter",
|
"tools_shutdown": "Fahre deinen Server herunter",
|
||||||
"tools_shutdown_btn": "Herunterfahren",
|
"tools_shutdown_btn": "Herunterfahren",
|
||||||
"tools_shutdown_done": "Fahre herunter...",
|
"tools_shutdown_done": "Fahre herunter...",
|
||||||
"tools_shuttingdown": "Dein Server wird heruntergefahren. Solange dein Server ausgeschaltet ist, kannst du das Verwaltungsoberfläche nicht benutzen.",
|
"tools_shuttingdown": "Dein Server wird heruntergefahren. Solange dein Server ausgeschaltet ist, kannst du die Verwaltungsoberfläche nicht benutzen.",
|
||||||
"tools_shutdown_reboot": "Herunterfahren/Neustarten",
|
"tools_shutdown_reboot": "Herunterfahren/Neustarten",
|
||||||
"appslists": "Applikationslisten",
|
"appslists": "Applikationslisten",
|
||||||
"appslists_no_lists": "Keine Applikationslisten",
|
"appslists_no_lists": "Keine Applikationslisten",
|
||||||
|
@ -472,5 +472,13 @@
|
||||||
"others": "Anderes",
|
"others": "Anderes",
|
||||||
"catalog": "Katalog",
|
"catalog": "Katalog",
|
||||||
"app_state_low_quality": "geringe Qualität",
|
"app_state_low_quality": "geringe Qualität",
|
||||||
"all": "Alle"
|
"all": "Alle",
|
||||||
|
"confirm_service_restart": "Bist du sicher, dass du %s neustarten möchtest?",
|
||||||
|
"run_first_diagnosis": "Initiale Diagnose läuft",
|
||||||
|
"diagnosis_first_run": "Die Diagnose Funktion wird versuchen, gängige Probleme in verschiedenen Teilen deines Servers zu finden, damit alles reibungslos läuft. Bitte werde nicht panisch, wenn du ein paar Fehlermeldungen siehst nachdem du deinen Server aufgesetzt hast: es soll versuchen dir zu helfen, Probleme zu identifizieren und Tipps für Lösungen zu zeigen. Die Diagnose wird auch automatisch zweimal täglich ausgeführt, falls Fehler gefunden werden, bekommt der Administrator ein E-Mail.",
|
||||||
|
"unmaintained_details": "Diese Anwendung wurde seit einiger Zeit nicht gewartet und der frühere Wart hat die Anwendung aufgegeben oder hat keine Zeit mehr für die Wartung. Du bist herzlich eingeladen dir die Quellen und Unterlagen anzusehen und Hilfe zu leisten",
|
||||||
|
"group_explain_visitors_needed_for_external_client": "Sei vorsichtig und beachte, dass du manche Anwendungen für externe Besucher freigeben musst, falls du beabsichtigst, diese mit externen Clients aufzurufen. Zum Beispiel trifft das auf Nextcloud zu, wenn du eine Synchronisation auf dem Smartphone oder Desktop PC haben möchtest.",
|
||||||
|
"groups": "Gruppen",
|
||||||
|
"issues": "%s Probleme",
|
||||||
|
"restart": "Neustart"
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,63 +3,51 @@
|
||||||
"active": "Active",
|
"active": "Active",
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
"advanced": "Advanced",
|
"advanced": "Advanced",
|
||||||
"remove": "Remove",
|
|
||||||
"administration_password": "Administration password",
|
"administration_password": "Administration password",
|
||||||
|
"all": "All",
|
||||||
"all_apps": "All apps",
|
"all_apps": "All apps",
|
||||||
"api_not_responding": "The YunoHost API is not responding. Maybe 'yunohost-api' is down or got restarted?",
|
"api_not_responding": "The YunoHost API is not responding. Maybe 'yunohost-api' is down or got restarted?",
|
||||||
"app_change_label": "Change Label",
|
"app_change_label": "Change Label",
|
||||||
"app_change_url": "Change URL",
|
"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": "Groups / users currently allowed to access this app:",
|
"app_info_access_desc": "Groups / users currently allowed to access this app:",
|
||||||
"app_info_changelabel_desc": "Change app label in the portal.",
|
"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_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_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_change_url_disabled_tooltip": "This feature hasn't been implemented in this app yet",
|
||||||
"app_info_uninstall_desc": "Remove this application.",
|
"app_info_uninstall_desc": "Remove this application.",
|
||||||
"app_install_cancel": "Installation cancelled.",
|
"app_install_cancel": "Installation cancelled.",
|
||||||
"app_install_custom_no_manifest": "No manifest.json file",
|
"app_install_custom_no_manifest": "No manifest.json file",
|
||||||
"app_list": "App list",
|
|
||||||
"app_level": "App level",
|
|
||||||
"app_make_default": "Make default",
|
"app_make_default": "Make default",
|
||||||
"app_no_actions": "This application doesn't have any actions",
|
"app_no_actions": "This application doesn't have any actions",
|
||||||
"app_repository": "Application origin: ",
|
"app_state_inprogress": "not yet working",
|
||||||
"app_state": "Application state: ",
|
|
||||||
"app_state_inprogress": "in progress",
|
|
||||||
"app_state_inprogress_explanation": "This maintainer of this app declared that this application is not ready yet for production use. BE CAREFUL!",
|
"app_state_inprogress_explanation": "This maintainer of this app declared that this application is not ready yet for production use. BE CAREFUL!",
|
||||||
"app_state_notworking": "not working",
|
"app_state_notworking": "not working",
|
||||||
"app_state_notworking_explanation": "This maintainer of this app declared it as 'not working'. IT WILL BREAK YOUR SYSTEM!",
|
"app_state_notworking_explanation": "This maintainer of this app declared it as 'not working'. IT WILL BREAK YOUR SYSTEM!",
|
||||||
|
"app_state_low_quality": "low quality",
|
||||||
|
"app_state_low_quality_explanation": "This app may be functional, but may still contain issues, or is not fully integrated with YunoHost, or it does not respect the good practices.",
|
||||||
"app_state_high-quality": "high quality",
|
"app_state_high-quality": "high quality",
|
||||||
"app_state_high-quality_explanation": "This app is well-integrated with YunoHost. It has been (and is!) peer-reviewed by the YunoHost app team. It can be expected to be safe and maintained on the long-term.",
|
"app_state_high-quality_explanation": "This app is well-integrated with YunoHost. It has been (and is!) peer-reviewed by the YunoHost app team. It can be expected to be safe and maintained on the long-term.",
|
||||||
"app_state_working": "working",
|
"app_state_working": "working",
|
||||||
"app_state_working_explanation": "The maintainer of this app declared it as 'working'. It means that it should be functional (c.f. application level) but is not necessarily peer-reviewed, it may still contain issues or is not fully integrated with YunoHost.",
|
"app_state_working_explanation": "The maintainer of this app declared it as 'working'. It means that it should be functional (c.f. application level) but is not necessarily peer-reviewed, it may still contain issues or is not fully integrated with YunoHost.",
|
||||||
"application": "Application",
|
|
||||||
"applications": "Applications",
|
"applications": "Applications",
|
||||||
"archive_empty": "Empty archive",
|
"archive_empty": "Empty archive",
|
||||||
"available": "Available",
|
|
||||||
"available_apps": "Available apps",
|
|
||||||
"backup": "Backup",
|
"backup": "Backup",
|
||||||
"backup_action": "Backup",
|
"backup_action": "Backup",
|
||||||
"backup_archive_copy": "Copy this archive on another storage",
|
|
||||||
"backup_archive_delete": "Delete this archive",
|
"backup_archive_delete": "Delete this archive",
|
||||||
"backup_archive_download": "Download this archive",
|
|
||||||
"backup_content": "Backup content",
|
"backup_content": "Backup content",
|
||||||
"backup_create": "Create a backup",
|
"backup_create": "Create a backup",
|
||||||
"backup_encryption_warning": "Don't forget this password, you'll need it if you want restore the archive",
|
"backup_encryption_warning": "Don't forget this password, you'll need it if you want restore the archive",
|
||||||
"backup_new": "New backup",
|
"backup_new": "New backup",
|
||||||
"backup_optional_encryption": "Optional encryption",
|
"backup_optional_encryption": "Optional encryption",
|
||||||
"backup_optional_password": "Optional password",
|
"backup_optional_password": "Optional password",
|
||||||
"backup_type": "Type",
|
|
||||||
"backups_no": "No backup",
|
"backups_no": "No backup",
|
||||||
"begin": "Begin",
|
"begin": "Begin",
|
||||||
"bit_rate": "Bit rate",
|
|
||||||
"both": "Both",
|
"both": "Both",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
|
"catalog": "Catalog",
|
||||||
"check": "Check",
|
"check": "Check",
|
||||||
"check_mx": "MX record",
|
|
||||||
"check_stmp": "port 25 access",
|
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"configuration": "Configuration",
|
||||||
"confirm_app_change_url": "Are you sure you want to change the app access URL?",
|
"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_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_change_maindomain": "Are you sure you want to change the main domain?",
|
||||||
|
@ -73,10 +61,9 @@
|
||||||
"confirm_migrations_skip": "Skipping migrations is not recommended. Are you sure you want to do that?",
|
"confirm_migrations_skip": "Skipping migrations is not recommended. Are you sure you want to do that?",
|
||||||
"confirm_postinstall": "You are about to launch the post-installation process on the domain %s. It may take a few minutes, *do not interrupt the operation*.",
|
"confirm_postinstall": "You are about to launch the post-installation process on the domain %s. It may take a few minutes, *do not interrupt the operation*.",
|
||||||
"confirm_restore": "Are you sure you want to restore %s?",
|
"confirm_restore": "Are you sure you want to restore %s?",
|
||||||
|
"confirm_service_restart": "Are you sure you want to restart %s?",
|
||||||
"confirm_service_start": "Are you sure you want to start %s?",
|
"confirm_service_start": "Are you sure you want to start %s?",
|
||||||
"confirm_service_stop": "Are you sure you want to stop %s?",
|
"confirm_service_stop": "Are you sure you want to stop %s?",
|
||||||
"confirm_service_enable": "Are you sure you want to enable %s?",
|
|
||||||
"confirm_service_disable": "Are you sure you want to disable %s?",
|
|
||||||
"confirm_uninstall": "Are you sure you want to uninstall %s?",
|
"confirm_uninstall": "Are you sure you want to uninstall %s?",
|
||||||
"confirm_update_apps": "Are you sure you want to update all applications?",
|
"confirm_update_apps": "Are you sure you want to update all applications?",
|
||||||
"confirm_update_system": "Are you sure you want to update all system packages?",
|
"confirm_update_system": "Are you sure you want to update all system packages?",
|
||||||
|
@ -86,25 +73,21 @@
|
||||||
"confirm_reboot_action_reboot": "Are you sure you want to reboot your server?",
|
"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?",
|
"confirm_reboot_action_shutdown": "Are you sure you want to shutdown your server?",
|
||||||
"connection": "Connection",
|
"connection": "Connection",
|
||||||
"copy": "Copy",
|
|
||||||
"count_min": "%s min",
|
|
||||||
"cpu_load": "CPU Load",
|
|
||||||
"created_at": "Created at",
|
"created_at": "Created at",
|
||||||
"cumulative_usage": "Cumulative usage",
|
|
||||||
"current_maintainer_title": "Current maintainer of this package",
|
|
||||||
"custom_app_install": "Install custom app",
|
"custom_app_install": "Install custom app",
|
||||||
"custom_app_url_only_github": "Currently only from GitHub",
|
"custom_app_url_only_github": "Currently only from GitHub",
|
||||||
"default": "Default",
|
"default": "Default",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"description": "Description",
|
"description": "Description",
|
||||||
|
"details": "Details",
|
||||||
"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.",
|
"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": "Diagnosis",
|
||||||
"diagnosis_hide_private": "Show diagnostic information without private data",
|
"diagnosis_experimental_disclaimer": "Be aware that the diagnosis feature is still experimental and being polished, and it may not be fully reliable.",
|
||||||
"diagnosis_view_private": "Show diagnostic information including private data",
|
"diagnosis_first_run": "The diagnosis feature will attempt to identify common issues on the different aspects of your server to make sure everything runs smoothly. Please do not panic if you see a bunch of errors right after setting up your server: it is precisely meant to help you to identify issues and guide you to fix them. The diagnosis will also run automatically twice a day and an email is sent to the administrator if issues are found.",
|
||||||
"diagnosis_with_private": "Diagnosis with private data",
|
"diagnosis_explanation": "The diagnosis feature will attempt to identify common issues on the different aspects of your server to make sure everything runs smoothly. The diagnosis runs automatically twice a day and an email is sent to the administrator if issues are found. Note that some tests may not be relevant if you do not want to use some specific features (for example XMPP) or may fail if you have a complex setup. In such cases, and if you know what you are doing, it is alright to ignore the corresponding issues or warnings.",
|
||||||
|
"run_first_diagnosis": "Run initial diagnosis",
|
||||||
"disable": "Disable",
|
"disable": "Disable",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"disk": "Disk",
|
|
||||||
"dns": "DNS",
|
"dns": "DNS",
|
||||||
"domain": "Domain",
|
"domain": "Domain",
|
||||||
"domain_add": "Add domain",
|
"domain_add": "Add domain",
|
||||||
|
@ -112,36 +95,28 @@
|
||||||
"domain_add_dyndns_doc": "… and I want a dynamic DNS service.",
|
"domain_add_dyndns_doc": "… and I want a dynamic DNS service.",
|
||||||
"domain_add_panel_with_domain": "I already have a domain name…",
|
"domain_add_panel_with_domain": "I already have a domain name…",
|
||||||
"domain_add_panel_without_domain": "I don't have a domain name…",
|
"domain_add_panel_without_domain": "I don't have a domain name…",
|
||||||
"domain_default": "Default domain",
|
|
||||||
"domain_default_desc": "The default domain is the connection domain where users log in.",
|
"domain_default_desc": "The default domain is the connection domain where users log in.",
|
||||||
"domain_default_longdesc": "This is your default domain.",
|
"domain_default_longdesc": "This is your default domain.",
|
||||||
"domain_delete_longdesc": "Delete this domain",
|
"domain_delete_longdesc": "Delete this domain",
|
||||||
"domain_dns_config": "DNS configuration",
|
"domain_dns_config": "DNS configuration",
|
||||||
"domain_dns_longdesc": "View DNS configuration",
|
"domain_dns_longdesc": "View DNS configuration",
|
||||||
"domain_list": "Domain list",
|
|
||||||
"domain_name": "Domain name",
|
"domain_name": "Domain name",
|
||||||
"domain_select": "Select domain",
|
|
||||||
"domain_visit": "Visit",
|
"domain_visit": "Visit",
|
||||||
"domain_visit_url": "Visit %s",
|
"domain_visit_url": "Visit %s",
|
||||||
"domains": "Domains",
|
"domains": "Domains",
|
||||||
"download": "Download",
|
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"error_modify_something": "You should modify something",
|
"error_modify_something": "You should modify something",
|
||||||
"error_retrieve_feed": "Could not retrieve feed: %s. You might have a plugin prevent your browser from performing this request (or the website is down).",
|
"error_retrieve_feed": "Could not retrieve feed: %s. You might have a plugin prevent your browser from performing this request (or the website is down).",
|
||||||
"error_select_domain": "You should indicate a domain",
|
"error_select_domain": "You should indicate a domain",
|
||||||
"error_server": "Server error",
|
|
||||||
"error_server_unexpected": "Unexpected server error (%s)",
|
"error_server_unexpected": "Unexpected server error (%s)",
|
||||||
"error_connection_interrupted": "The server closed the connection instead of answering it. Has nginx or the yunohost-api been restarted or stoppted for some reason? (Error code/message: %s)",
|
"error_connection_interrupted": "The server closed the connection instead of answering it. Has nginx or the yunohost-api been restarted or stoppted for some reason? (Error code/message: %s)",
|
||||||
|
"everything_good": "Everything good!",
|
||||||
"experimental_warning": "Warning: this feature is experimental and not consider stable, you shouldn't be using it except if you know what you are doing.",
|
"experimental_warning": "Warning: this feature is experimental and not consider stable, you shouldn't be using it except if you know what you are doing.",
|
||||||
"filesystem": "Filesystem",
|
|
||||||
"firewall": "Firewall",
|
"firewall": "Firewall",
|
||||||
"footer_version": "Powered by <a href='https://yunohost.org'>YunoHost</a> %s (%s).",
|
"footer_version": "Powered by <a href='https://yunohost.org'>YunoHost</a> %s (%s).",
|
||||||
"form_input_example": "Example: %s",
|
"form_input_example": "Example: %s",
|
||||||
"free": "Free",
|
|
||||||
"from_to": "from %s to %s",
|
"from_to": "from %s to %s",
|
||||||
"fs_type": "FS Type",
|
|
||||||
"gateway": "Gateway: ",
|
|
||||||
"good_practices_about_admin_password": "You are now about to define a new admin password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_admin_password": "You are now about to define a new admin password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
||||||
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
||||||
"group": "Group",
|
"group": "Group",
|
||||||
|
@ -156,6 +131,7 @@
|
||||||
"group_explain_visitors": "This is a special group representing anonymous visitors",
|
"group_explain_visitors": "This is a special group representing anonymous visitors",
|
||||||
"group_explain_visitors_needed_for_external_client": "Be careful that you need to keep some applications allowed to visitors if you intend to use them with external clients. For example, this is the case for Nextcloud if you want intend to use a synchronization client on your smartphone or desktop computer.",
|
"group_explain_visitors_needed_for_external_client": "Be careful that you need to keep some applications allowed to visitors if you intend to use them with external clients. For example, this is the case for Nextcloud if you want intend to use a synchronization client on your smartphone or desktop computer.",
|
||||||
"group_specific_permissions": "User specific permissions",
|
"group_specific_permissions": "User specific permissions",
|
||||||
|
"groups": "Groups",
|
||||||
"groups_and_permissions": "Groups and permissions",
|
"groups_and_permissions": "Groups and permissions",
|
||||||
"groups_and_permissions_manage": "Manage groups and permissions",
|
"groups_and_permissions_manage": "Manage groups and permissions",
|
||||||
"permissions": "Permissions",
|
"permissions": "Permissions",
|
||||||
|
@ -175,8 +151,9 @@
|
||||||
"hook_data_home_desc": "User data located in /home/USER",
|
"hook_data_home_desc": "User data located in /home/USER",
|
||||||
"hook_data_mail": "Mail",
|
"hook_data_mail": "Mail",
|
||||||
"hook_data_mail_desc": "Raw emails stored on the server",
|
"hook_data_mail_desc": "Raw emails stored on the server",
|
||||||
"hostname": "Hostname",
|
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
"ignore": "Ignore",
|
||||||
|
"ignored": "%s ignored",
|
||||||
"inactive": "Inactive",
|
"inactive": "Inactive",
|
||||||
"infos": "Info",
|
"infos": "Info",
|
||||||
"install": "Install",
|
"install": "Install",
|
||||||
|
@ -184,21 +161,16 @@
|
||||||
"install_time": "Install time",
|
"install_time": "Install time",
|
||||||
"installation_complete": "Installation complete",
|
"installation_complete": "Installation complete",
|
||||||
"installed": "Installed",
|
"installed": "Installed",
|
||||||
"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://github.com/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>",
|
"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://github.com/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",
|
"ipv4": "IPv4",
|
||||||
"ipv6": "IPv6",
|
"ipv6": "IPv6",
|
||||||
|
"issues": "%s issues",
|
||||||
"label": "Label",
|
"label": "Label",
|
||||||
"label_for_manifestname": "Label for %s",
|
"label_for_manifestname": "Label for %s",
|
||||||
"level": "level",
|
"last_ran": "Last time ran:",
|
||||||
"license": "License",
|
"license": "License",
|
||||||
"loading": "Loading …",
|
"loading": "Loading …",
|
||||||
"local_archives": "Local archives",
|
"local_archives": "Local archives",
|
||||||
"local_ip": "Local IP",
|
|
||||||
"log": "Log",
|
|
||||||
"logged_in": "Logged in",
|
"logged_in": "Logged in",
|
||||||
"logged_out": "Logged out",
|
"logged_out": "Logged out",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
|
@ -210,49 +182,35 @@
|
||||||
"manage_apps": "Manage apps",
|
"manage_apps": "Manage apps",
|
||||||
"manage_domains": "Manage domains",
|
"manage_domains": "Manage domains",
|
||||||
"manage_users": "Manage users",
|
"manage_users": "Manage users",
|
||||||
"memory": "Memory",
|
|
||||||
"menu": "Menu",
|
|
||||||
"migrations": "Migrations",
|
"migrations": "Migrations",
|
||||||
"migrations_pending": "Pending migrations",
|
"migrations_pending": "Pending migrations",
|
||||||
"migrations_done": "Previous migrations",
|
"migrations_done": "Previous migrations",
|
||||||
"migrations_no_pending": "No pending migrations",
|
"migrations_no_pending": "No pending migrations",
|
||||||
"migrations_no_done": "No previous migrations",
|
"migrations_no_done": "No previous migrations",
|
||||||
"mode": "Mode",
|
|
||||||
"monitoring": "Monitoring",
|
|
||||||
"monitoring_check_glances": "Check <a href='#/services/glances'>glances</a> service status.",
|
|
||||||
"monitoring_disabled": "Monitoring is not enabled.",
|
|
||||||
"mount_point": "Mount point",
|
|
||||||
"multi_instance": "Multi instance",
|
"multi_instance": "Multi instance",
|
||||||
"myserver": "myserver",
|
"myserver": "myserver",
|
||||||
"myserver_org": "myserver.org",
|
"myserver_org": "myserver.org",
|
||||||
"network": "Network",
|
|
||||||
"next": "Next",
|
"next": "Next",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"no_installed_apps": "No installed apps.",
|
"no_installed_apps": "No installed apps.",
|
||||||
"no_log": "No log.",
|
|
||||||
"nobody": "Nobody",
|
"nobody": "Nobody",
|
||||||
"non_compatible_api": "Non-compatible API",
|
|
||||||
"ok": "OK",
|
"ok": "OK",
|
||||||
"only_highquality_apps": "Only high-quality apps",
|
"only_highquality_apps": "Only high-quality apps",
|
||||||
"only_working_apps": "Only working apps",
|
"only_working_apps": "Only working apps",
|
||||||
"only_decent_quality_apps": "Only decent quality apps",
|
"only_decent_quality_apps": "Only decent quality apps",
|
||||||
"open": "Open",
|
"open": "Open",
|
||||||
"operations": "Operations",
|
"operations": "Operations",
|
||||||
"orphaned": "not maintained",
|
"orphaned": "Not maintained",
|
||||||
"orphaned_details": "This app is not maintained anymore. It may still be working but won't receive any upgrade. Feel free to come and revive it!",
|
"orphaned_details": "This app has not been maintained for quite some time. It may still be working, but won't receive any upgrade until somebody volunteers to take care of it. Feel free to contribute to revive it!",
|
||||||
"os": "OS",
|
"others": "Others",
|
||||||
|
"operation_failed_explanation": "This operation failed! Really sorry about that :( You can try to <a href='https://yunohost.org/help'>ask for help</a>. Please provide *the full log* of the operation to the people helping you. You can do so by clicking on the 'Share with Yunopaste' green button. When sharing the logs, YunoHost will automatically attempt to anonymize private data like domain names and IPs.",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"password_confirmation": "Password confirmation",
|
"password_confirmation": "Password confirmation",
|
||||||
"password_description": "Password must be at least %s characters long.",
|
|
||||||
"password_empty": "The password field is empty",
|
"password_empty": "The password field is empty",
|
||||||
"password_new": "New password",
|
"password_new": "New password",
|
||||||
"passwords_dont_match": "Passwords don't match",
|
"passwords_dont_match": "Passwords don't match",
|
||||||
"passwords_too_short": "Password is too short",
|
"passwords_too_short": "Password is too short",
|
||||||
"path": "Path",
|
"path": "Path",
|
||||||
"diagnosis": "Diagnosis",
|
|
||||||
"diagnosis_with_private": "Diagnosis with private data",
|
|
||||||
"diagnosis_view_private": "Show diagnosis with private data",
|
|
||||||
"diagnosis_hide_private": "Show diagnosis without private data",
|
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"logs_operation": "Operations made on system with YunoHost",
|
"logs_operation": "Operations made on system with YunoHost",
|
||||||
"logs_history": "History of command run on system",
|
"logs_history": "History of command run on system",
|
||||||
|
@ -262,7 +220,6 @@
|
||||||
"logs_service": "Services logs",
|
"logs_service": "Services logs",
|
||||||
"logs_app": "Apps logs",
|
"logs_app": "Apps logs",
|
||||||
"logs_no_logs_registered": "No log registered for this category",
|
"logs_no_logs_registered": "No log registered for this category",
|
||||||
"logs_end_with_error": "This log finished with the error:",
|
|
||||||
"logs_error": "Error",
|
"logs_error": "Error",
|
||||||
"logs_ended_at": "End",
|
"logs_ended_at": "End",
|
||||||
"logs_started_at": "Start",
|
"logs_started_at": "Start",
|
||||||
|
@ -280,54 +237,37 @@
|
||||||
"postinstall_intro_3": "You can obtain more information by visiting the <a href='//yunohost.org/postinstall' target='_blank'>appropriate documentation page</a>",
|
"postinstall_intro_3": "You can obtain more information by visiting the <a href='//yunohost.org/postinstall' target='_blank'>appropriate documentation page</a>",
|
||||||
"postinstall_password": "This password will be used to manage everything on your server. Take the time to choose it wisely.",
|
"postinstall_password": "This password will be used to manage everything on your server. Take the time to choose it wisely.",
|
||||||
"previous": "Previous",
|
"previous": "Previous",
|
||||||
"process": "Process",
|
|
||||||
"protocol": "Protocol",
|
"protocol": "Protocol",
|
||||||
"public_ip": "Public IP: ",
|
|
||||||
"ram": "RAM",
|
|
||||||
"read": "Read",
|
|
||||||
"read_more": "Read more",
|
"read_more": "Read more",
|
||||||
"reception": "Reception",
|
"rerun_diagnosis": "Rerun diagnosis",
|
||||||
"refresh_app_list": "Refresh list",
|
|
||||||
"request_adoption": "waiting adoption",
|
"request_adoption": "waiting adoption",
|
||||||
"request_adoption_details": "The current maintainer would like to stop maintaining this app. Feel free to propose yourself as the new maintainer!",
|
"request_adoption_details": "The current maintainer would like to stop maintaining this app. Feel free to propose yourself as the new maintainer!",
|
||||||
"request_help": "need help",
|
"request_help": "need help",
|
||||||
"request_help_details": "The current maintainer would like some help with the maintainance of this app. Feel free to come contribute on it!",
|
"request_help_details": "The current maintainer would like some help with the maintainance of this app. Feel free to come contribute on it!",
|
||||||
"restore": "Restore",
|
"restore": "Restore",
|
||||||
|
"restart": "Restart",
|
||||||
"run": "Run",
|
"run": "Run",
|
||||||
"running": "Running",
|
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"search_for_apps": "Search for apps...",
|
"search_for_apps": "Search for apps...",
|
||||||
"select_all": "Select all",
|
"select_all": "Select all",
|
||||||
"select_none": "Select none",
|
"select_none": "Select none",
|
||||||
"service_description": "Description:",
|
"service_start_on_boot": "Start on boot",
|
||||||
"service_log": "%s log",
|
|
||||||
"service_start_on_boot": "Start on boot: ",
|
|
||||||
"service_status": "Status: ",
|
|
||||||
"services": "Services",
|
"services": "Services",
|
||||||
"services_list": "Service list",
|
|
||||||
"set_default": "Set default",
|
"set_default": "Set default",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
|
"since": "since",
|
||||||
"skip": "Skip",
|
"skip": "Skip",
|
||||||
"start": "Start",
|
"start": "Start",
|
||||||
"started_at": "Started at:",
|
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"stop": "Stop",
|
"stop": "Stop",
|
||||||
"storage_create": "Add remote storage",
|
|
||||||
"storages_new": "New remote storage",
|
|
||||||
"storages_no": "No storages.",
|
|
||||||
"swap": "Swap",
|
|
||||||
"system": "System",
|
"system": "System",
|
||||||
"system_apps": "Apps",
|
|
||||||
"system_apps_nothing": "All apps are up to date!",
|
"system_apps_nothing": "All apps are up to date!",
|
||||||
"system_packages": "System packages",
|
|
||||||
"system_packages_nothing": "All system packages are up to date!",
|
"system_packages_nothing": "All system packages are up to date!",
|
||||||
"system_update": "System update",
|
"system_update": "System update",
|
||||||
"system_upgrade": "System upgrade",
|
|
||||||
"system_upgrade_btn": "Upgrade",
|
"system_upgrade_btn": "Upgrade",
|
||||||
"system_upgrade_all_applications_btn": "Upgrade all applications",
|
"system_upgrade_all_applications_btn": "Upgrade all applications",
|
||||||
"system_upgrade_all_packages_btn": "Upgrade all packages",
|
"system_upgrade_all_packages_btn": "Upgrade all packages",
|
||||||
"tcp": "TCP",
|
"tcp": "TCP",
|
||||||
"time_since_update": "Time since update: ",
|
|
||||||
"tools": "Tools",
|
"tools": "Tools",
|
||||||
"tools_adminpw": "Change administration password",
|
"tools_adminpw": "Change administration password",
|
||||||
"tools_adminpw_confirm_placeholder": "Confirm the new password",
|
"tools_adminpw_confirm_placeholder": "Confirm the new password",
|
||||||
|
@ -349,23 +289,20 @@
|
||||||
"tools_shutdown_done": "Shutting down...",
|
"tools_shutdown_done": "Shutting down...",
|
||||||
"tools_shuttingdown": "Your server is powering off. As long as your server is off, you won't be able to use the web administration.",
|
"tools_shuttingdown": "Your server is powering off. As long as your server is off, you won't be able to use the web administration.",
|
||||||
"tools_shutdown_reboot": "Shutdown/Reboot",
|
"tools_shutdown_reboot": "Shutdown/Reboot",
|
||||||
"total": "Total",
|
|
||||||
"transmission": "Transmission",
|
|
||||||
"udp": "UDP",
|
"udp": "UDP",
|
||||||
"unauthorized": "Unauthorized",
|
"unauthorized": "Unauthorized",
|
||||||
|
"unignore": "Unignore",
|
||||||
"uninstall": "Uninstall",
|
"uninstall": "Uninstall",
|
||||||
"unknown_action": "Unknown action %s",
|
"unknown_action": "Unknown action %s",
|
||||||
"unknown_argument": "Unknown argument: %s",
|
"unknown_argument": "Unknown argument: %s",
|
||||||
"unmaintained": "Unmaintained",
|
"unmaintained": "Unmaintained",
|
||||||
|
"unmaintained_details": "This app has not been update for quite a while and the previous maintainer has gone away or does not have time to maintain this app. Feel free to check the app repository to provide your help",
|
||||||
"upload": "Upload",
|
"upload": "Upload",
|
||||||
"upload_archive": "Archive upload",
|
"upload_archive": "Archive upload",
|
||||||
"upnp": "UPnP",
|
"upnp": "UPnP",
|
||||||
"upnp_disabled": "UPnP is disabled.",
|
"upnp_disabled": "UPnP is disabled.",
|
||||||
"upnp_enabled": "UPnP is enabled.",
|
"upnp_enabled": "UPnP is enabled.",
|
||||||
"uptime": "Uptime",
|
|
||||||
"url": "URL",
|
"url": "URL",
|
||||||
"usage": "Usage",
|
|
||||||
"used": "Used",
|
|
||||||
"user_email": "Email",
|
"user_email": "Email",
|
||||||
"user_emailaliases": "Mail aliases",
|
"user_emailaliases": "Mail aliases",
|
||||||
"user_emailforward": "Mail forward",
|
"user_emailforward": "Mail forward",
|
||||||
|
@ -378,13 +315,11 @@
|
||||||
"user_username": "Username",
|
"user_username": "Username",
|
||||||
"user_username_edit": "Edit %s’s account",
|
"user_username_edit": "Edit %s’s account",
|
||||||
"users": "Users",
|
"users": "Users",
|
||||||
"users_list": "User list",
|
|
||||||
"users_new": "New user",
|
"users_new": "New user",
|
||||||
"users_no": "No users.",
|
"users_no": "No users.",
|
||||||
"versions": "Versions",
|
|
||||||
"version": "Version",
|
"version": "Version",
|
||||||
|
"warnings": "%s warnings",
|
||||||
"warning_first_user": "You probably need to <a href='#/users/create' class='alert-link'>create a user</a> first.",
|
"warning_first_user": "You probably need to <a href='#/users/create' class='alert-link'>create a user</a> first.",
|
||||||
"write": "Write",
|
|
||||||
"wrong_password": "Wrong password",
|
"wrong_password": "Wrong password",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"certificate_alert_not_valid": "CRITICAL: Current certificate is not valid! HTTPS won't work at all!",
|
"certificate_alert_not_valid": "CRITICAL: Current certificate is not valid! HTTPS won't work at all!",
|
||||||
|
@ -395,7 +330,6 @@
|
||||||
"certificate_alert_great": "Great! You're using a valid Let's Encrypt certificate!",
|
"certificate_alert_great": "Great! You're using a valid Let's Encrypt certificate!",
|
||||||
"certificate_alert_unknown": "Unknown status",
|
"certificate_alert_unknown": "Unknown status",
|
||||||
"certificate_manage": "Manage SSL certificate",
|
"certificate_manage": "Manage SSL certificate",
|
||||||
"certificate_old_letsencrypt_app_conflict": "The 'letsencrypt' app is currently installed and conflicts with this feature. Please uninstall it first to use the new certificate management interface.",
|
|
||||||
"ssl_certificate": "SSL certificate",
|
"ssl_certificate": "SSL certificate",
|
||||||
"confirm_cert_install_LE": "Are you sure you want to install a Let's Encrypt certificate for this domain?",
|
"confirm_cert_install_LE": "Are you sure you want to install a Let's Encrypt certificate for this domain?",
|
||||||
"confirm_cert_regen_selfsigned": "Are you sure you want to regenerate a self-signed certificate for this domain?",
|
"confirm_cert_regen_selfsigned": "Are you sure you want to regenerate a self-signed certificate for this domain?",
|
||||||
|
@ -406,25 +340,14 @@
|
||||||
"certificate_authority": "Certification authority",
|
"certificate_authority": "Certification authority",
|
||||||
"validity": "Validity",
|
"validity": "Validity",
|
||||||
"domain_is_eligible_for_ACME": "This domain seems correctly configured to install a Let's Encrypt certificate!",
|
"domain_is_eligible_for_ACME": "This domain seems correctly configured to install a Let's Encrypt certificate!",
|
||||||
"domain_not_eligible_for_ACME": "This domain doesn't seem ready for a Let's Encrypt certificate. Please check your DNS configuration and HTTP server reachability.",
|
"domain_not_eligible_for_ACME": "This domain doesn't seem ready for a Let's Encrypt certificate. Please check your DNS configuration and HTTP server reachability. The 'DNS records' and 'Web' section in <a href='#/diagnosis'>the diagnosis page</a> can help you understand what is misconfigured.",
|
||||||
"install_letsencrypt_cert": "Install a Let's Encrypt certificate",
|
"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_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",
|
"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_message": "If you want, you can regenerate the self-signed certificate.",
|
||||||
"regenerate_selfsigned_cert": "Regenerate 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)",
|
"revert_to_selfsigned_cert_message": "If you really want to, you can reinstall a self-signed certificate. (Not recommended)",
|
||||||
"revert_to_selfsigned_cert": "Revert to a self-signed certificate",
|
"revert_to_selfsigned_cert": "Revert to a self-signed certificate",
|
||||||
"appslists": "Applications lists",
|
"purge_user_data_checkbox": "Purge %s's data? (This will remove the content of its home and mail directories.)",
|
||||||
"appslists_no_lists": "No applications lists",
|
|
||||||
"appslists_custom": "Custom applications list",
|
|
||||||
"appslists_manage": "Manage applications lists",
|
|
||||||
"appslists_confirm_remove": "Are you sure you want to remove this applications list?",
|
|
||||||
"appslists_info_refresh_desc": "Refresh applications status for this list.",
|
|
||||||
"appslists_info_remove_desc": "Applications from this list will not be available anymore.",
|
|
||||||
"appslists_last_update": "Last update",
|
|
||||||
"appslists_unknown_list": "Unknown apps list: %s",
|
|
||||||
"name": "Name",
|
|
||||||
"purge_user_data_checkbox": "Purge %s's data? (This will remove the content of it's home and mail directories.)",
|
|
||||||
"purge_user_data_warning": "Purging user's data is not reversible. Be sure you know what you're doing!"
|
"purge_user_data_warning": "Purging user's data is not reversible. Be sure you know what you're doing!"
|
||||||
}
|
}
|
||||||
|
|
|
@ -227,7 +227,7 @@
|
||||||
"uninstall": "Malinstali",
|
"uninstall": "Malinstali",
|
||||||
"users_new": "Nova uzanto",
|
"users_new": "Nova uzanto",
|
||||||
"users": "Uzantoj",
|
"users": "Uzantoj",
|
||||||
"system_apps_nothing": "Ne estas programoj por ĝisdatigi.",
|
"system_apps_nothing": "Ĉiuj aplikoj estas ĝisdatigitaj!",
|
||||||
"used": "Uzata",
|
"used": "Uzata",
|
||||||
"tools_security_feed_view_items": "Vidu ĉiujn sekurecajn sciigojn",
|
"tools_security_feed_view_items": "Vidu ĉiujn sekurecajn sciigojn",
|
||||||
"certificate_alert_letsencrypt_about_to_expire": "Nuna atestilo estas preskaŭ eksvalidiĝi. Ĝi baldaŭ renoviĝu aŭtomate.",
|
"certificate_alert_letsencrypt_about_to_expire": "Nuna atestilo estas preskaŭ eksvalidiĝi. Ĝi baldaŭ renoviĝu aŭtomate.",
|
||||||
|
@ -259,7 +259,7 @@
|
||||||
"install_letsencrypt_cert": "Instalu atestilon Lasu-Ĉifri",
|
"install_letsencrypt_cert": "Instalu atestilon Lasu-Ĉifri",
|
||||||
"appslists_custom": "Propra listo listo",
|
"appslists_custom": "Propra listo listo",
|
||||||
"no_log": "Neniu ŝtipo.",
|
"no_log": "Neniu ŝtipo.",
|
||||||
"system_packages_nothing": "Ne estas pakoj por ĝisdatigi.",
|
"system_packages_nothing": "Ĉiuj sistemaj pakoj estas ĝisdatigitaj !",
|
||||||
"system_upgrade_all_applications_btn": "Ĝisdatigu ĉiujn aplikojn",
|
"system_upgrade_all_applications_btn": "Ĝisdatigu ĉiujn aplikojn",
|
||||||
"postinstall": "post Instalaĵo",
|
"postinstall": "post Instalaĵo",
|
||||||
"service_description": "Priskribo:",
|
"service_description": "Priskribo:",
|
||||||
|
@ -270,7 +270,7 @@
|
||||||
"unauthorized": "Ne rajtigita",
|
"unauthorized": "Ne rajtigita",
|
||||||
"wrong_password": "Erara pasvorto",
|
"wrong_password": "Erara pasvorto",
|
||||||
"tools_security_feed": "Sekurecaj sciigoj",
|
"tools_security_feed": "Sekurecaj sciigoj",
|
||||||
"system_packages": "Pakoj",
|
"system_packages": "Sistempakaĵoj",
|
||||||
"certificate_alert_unknown": "Nekonata stato",
|
"certificate_alert_unknown": "Nekonata stato",
|
||||||
"tools_shutdown_reboot": "Ŝalti/Rekomenci",
|
"tools_shutdown_reboot": "Ŝalti/Rekomenci",
|
||||||
"logs_started_at": "Komencu",
|
"logs_started_at": "Komencu",
|
||||||
|
@ -325,7 +325,7 @@
|
||||||
"tools_adminpw_current": "Aktuala Pasvorto",
|
"tools_adminpw_current": "Aktuala Pasvorto",
|
||||||
"appslists_manage": "Administri listojn de aplikoj",
|
"appslists_manage": "Administri listojn de aplikoj",
|
||||||
"menu": "menuo",
|
"menu": "menuo",
|
||||||
"service_start_on_boot": "Komencu je ekkuro: ",
|
"service_start_on_boot": "Komencu je ekkuro",
|
||||||
"storages_new": "Nova fora stokado",
|
"storages_new": "Nova fora stokado",
|
||||||
"storage_create": "Aldonu forajn stokadojn",
|
"storage_create": "Aldonu forajn stokadojn",
|
||||||
"regenerate_selfsigned_cert_message": "Se vi volas, vi povas regeneri la mem-subskribitan atestilon.",
|
"regenerate_selfsigned_cert_message": "Se vi volas, vi povas regeneri la mem-subskribitan atestilon.",
|
||||||
|
@ -457,5 +457,13 @@
|
||||||
"app_state_low_quality": "malkvalita",
|
"app_state_low_quality": "malkvalita",
|
||||||
"app_state_low_quality_explanation": "Ĉi tiu app eble funkcias, sed ankoraŭ enhavas problemojn, aŭ ne plene integras kun YunoHost, aŭ ĝi ne respektas la bonajn praktikojn.",
|
"app_state_low_quality_explanation": "Ĉi tiu app eble funkcias, sed ankoraŭ enhavas problemojn, aŭ ne plene integras kun YunoHost, aŭ ĝi ne respektas la bonajn praktikojn.",
|
||||||
"catalog": "Katalogo",
|
"catalog": "Katalogo",
|
||||||
"others": "Aliaj"
|
"others": "Aliaj",
|
||||||
|
"confirm_service_restart": "Ĉu vi certas, ke vi volas rekomenci %s ?",
|
||||||
|
"diagnosis_first_run": "La diagnoza funkcio provos identigi oftajn problemojn pri la diversaj aspektoj de via servilo por certigi, ke ĉio funkcias glate. Bonvolu ne panikiĝi, se vi vidas amason da eraroj tuj post agordo de via servilo: ĝi ĝuste celas helpi vin identigi problemojn kaj gvidi vin ripari ilin. La diagnozo ankaŭ funkcios aŭtomate dufoje ĉiutage kaj retpoŝtu al la administranto se iuj problemoj ekestos.",
|
||||||
|
"group_explain_visitors_needed_for_external_client": "Atentu, ke vi bezonas konservi iujn aplikaĵojn permesitajn al vizitantoj se vi intencas uzi ilin kun eksteraj klientoj. Ekzemple, ĉi tiu estas la kazo de Nextcloud se vi volas intenci uzi sinkronigan klienton en via inteligenta telefono aŭ labortabla komputilo.",
|
||||||
|
"restart": "Rekomenci",
|
||||||
|
"unmaintained_details": "Ĉi tiu app ne estis ĝisdatigita antaŭ tre tempo kaj la antaŭa prizorganto foriĝis aŭ ne havas tempon por subteni ĉi tiun app. Bonvolu kontroli la app-deponejon por doni vian helpon",
|
||||||
|
"run_first_diagnosis": "Kuru komencan diagnozon",
|
||||||
|
"groups": "Grupoj",
|
||||||
|
"issues": "%s aferoj"
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
"app_make_default": "Establecer como predeterminado",
|
"app_make_default": "Establecer como predeterminado",
|
||||||
"app_repository": "Origen de la aplicación: ",
|
"app_repository": "Origen de la aplicación: ",
|
||||||
"app_state": "Estado de la aplicación: ",
|
"app_state": "Estado de la aplicación: ",
|
||||||
"app_state_inprogress": "en marcha",
|
"app_state_inprogress": "Todavía no trabajando",
|
||||||
"app_state_notworking": "no funciona",
|
"app_state_notworking": "no funciona",
|
||||||
"app_state_validated": "Validado",
|
"app_state_validated": "Validado",
|
||||||
"app_state_working": "funciona",
|
"app_state_working": "funciona",
|
||||||
|
@ -222,7 +222,7 @@
|
||||||
"save": "Guardar",
|
"save": "Guardar",
|
||||||
"select_user": "Seleccionar usuario",
|
"select_user": "Seleccionar usuario",
|
||||||
"service_log": "%s log",
|
"service_log": "%s log",
|
||||||
"service_start_on_boot": "Inicio en el arranque: ",
|
"service_start_on_boot": "Inicie en el arranque",
|
||||||
"service_status": "Estado: ",
|
"service_status": "Estado: ",
|
||||||
"services": "Servicios",
|
"services": "Servicios",
|
||||||
"services_list": "Lista de servicios",
|
"services_list": "Lista de servicios",
|
||||||
|
@ -238,11 +238,11 @@
|
||||||
"swap": "Swap",
|
"swap": "Swap",
|
||||||
"system": "Sistema",
|
"system": "Sistema",
|
||||||
"system_apps": "Aplicaciones",
|
"system_apps": "Aplicaciones",
|
||||||
"system_apps_nothing": "No hay aplicaciones para actualizar.",
|
"system_apps_nothing": "¡Todas las aplicaciones están actualizadas!",
|
||||||
"system_delayed_upgrade": "Retraso en actualización",
|
"system_delayed_upgrade": "Retraso en actualización",
|
||||||
"system_delayed_upgrade_warning": "<b>%s</b> será actualizada automáticamente en la próxima hora.",
|
"system_delayed_upgrade_warning": "<b>%s</b> será actualizada automáticamente en la próxima hora.",
|
||||||
"system_packages": "Paquetes",
|
"system_packages": "Paquetes",
|
||||||
"system_packages_nothing": "No hay paquetes para actualizar.",
|
"system_packages_nothing": "¡Todos los paquetes del sistema están actualizados!",
|
||||||
"system_update": "Actualización del sistema",
|
"system_update": "Actualización del sistema",
|
||||||
"system_upgrade": "Actualización del sistema",
|
"system_upgrade": "Actualización del sistema",
|
||||||
"system_upgrade_btn": "Actualización",
|
"system_upgrade_btn": "Actualización",
|
||||||
|
@ -376,14 +376,14 @@
|
||||||
"from_to": "desde %s a %s",
|
"from_to": "desde %s a %s",
|
||||||
"only_highquality_apps": "Solo aplicaciones de alta calidad",
|
"only_highquality_apps": "Solo aplicaciones de alta calidad",
|
||||||
"only_decent_quality_apps": "Solo aplicaciones de calidad aceptable",
|
"only_decent_quality_apps": "Solo aplicaciones de calidad aceptable",
|
||||||
"orphaned": "sin mantenimiento",
|
"orphaned": "No mantenido",
|
||||||
"request_adoption": "pendiente de adopción",
|
"request_adoption": "pendiente de adopción",
|
||||||
"request_adoption_details": "Al mantenedor actual le gustaría dejar de mantener esta aplicación. ¡No dude en ofrecerse como el nuevo mantenedor!",
|
"request_adoption_details": "Al mantenedor actual le gustaría dejar de mantener esta aplicación. ¡No dude en ofrecerse como el nuevo mantenedor!",
|
||||||
"request_help": "necesita ayuda",
|
"request_help": "necesita ayuda",
|
||||||
"app_state_inprogress_explanation": "El mantenedor de esta aplicación declara que aún no está lista para su uso en producción. ¡TENGA CUIDADO!",
|
"app_state_inprogress_explanation": "El mantenedor de esta aplicación declara que aún no está lista para su uso en producción. ¡TENGA CUIDADO!",
|
||||||
"app_state_high-quality_explanation": "Esta aplicación está bien integrada en YunoHost. Ha sido (¡y continua siendo!) revisada por especialistas del equipo de aplicaciones de YunoHost. Se puede esperar que sea segura y mantenida a largo plazo.",
|
"app_state_high-quality_explanation": "Esta aplicación está bien integrada en YunoHost. Ha sido (¡y continua siendo!) revisada por especialistas del equipo de aplicaciones de YunoHost. Se puede esperar que sea segura y mantenida a largo plazo.",
|
||||||
"app_state_working_explanation": "El mantenedor de esta aplicación declara que «funciona». Significa que debería ser funcional (comparada a nivel de aplicación) pero no está revisada por especialistas necesariamente, puede tener aún problemas o no está totalmente integrada en YunoHost.",
|
"app_state_working_explanation": "El mantenedor de esta aplicación declara que «funciona». Significa que debería ser funcional (comparada a nivel de aplicación) pero no está revisada por especialistas necesariamente, puede tener aún problemas o no está totalmente integrada en YunoHost.",
|
||||||
"orphaned_details": "Esta aplicación ya no se mantiene. Puede que funcione pero no se actualizará. ¡No dude en venir y reanimarla!",
|
"orphaned_details": "Esta aplicación no se ha mantenido durante bastante tiempo. Todavía puede estar funcionando, pero no recibirá ninguna actualización hasta que alguien se ofrezca como voluntario para encargarse de ello. ¡Siéntase libre de contribuir para revivirlo!",
|
||||||
"request_help_details": "Al mantenedor actual le gustaría recibir alguna ayuda con el mantenimiento de esta aplicación. ¡No dude en venir a contribuir!",
|
"request_help_details": "Al mantenedor actual le gustaría recibir alguna ayuda con el mantenimiento de esta aplicación. ¡No dude en venir a contribuir!",
|
||||||
"tools_rebooting": "Su servidor se está reiniciando. Para volver a la interfaz de administración web necesita esperar a que el servidor esté listo. Puede comprobarlo recargando esta página (F5).",
|
"tools_rebooting": "Su servidor se está reiniciando. Para volver a la interfaz de administración web necesita esperar a que el servidor esté listo. Puede comprobarlo recargando esta página (F5).",
|
||||||
"tools_shutdown_btn": "Apagar",
|
"tools_shutdown_btn": "Apagar",
|
||||||
|
@ -466,5 +466,19 @@
|
||||||
"last_ran": "Ejecutado por última vez:",
|
"last_ran": "Ejecutado por última vez:",
|
||||||
"unignore": "Dejar de ignorar",
|
"unignore": "Dejar de ignorar",
|
||||||
"warnings": "%s avisos",
|
"warnings": "%s avisos",
|
||||||
"all": "Todo"
|
"all": "Todo",
|
||||||
|
"diagnosis_first_run": "El diagnostico intentara identificar los errores comunes en diferentes aspectos de su servidor para asegurar que todo funcione de la mejor manera. No te asustes si observas algunas errores justo después de la configuracion de tu servidor. Estos le ayudara a identificar los incidentes y le guiara para corregir los. El diagnostico correrá 2 veces al día y enviara un correo electrónico al administrador si encuentra incidentes.",
|
||||||
|
"since": "desde",
|
||||||
|
"others": "Otros",
|
||||||
|
"run_first_diagnosis": "Procesando el primer diagnostico",
|
||||||
|
"configuration": "Configuración",
|
||||||
|
"catalog": "Catálogo",
|
||||||
|
"app_state_low_quality_explanation": "Asta app esta probablemente funcional, pero puede fallar, no esta completamente integrada con YunoHost, o no respeta las buenas practicas.",
|
||||||
|
"app_state_low_quality": "baja qualidad",
|
||||||
|
"confirm_service_restart": "¿Estás seguro de que quieres reiniciar %s ?",
|
||||||
|
"group_explain_visitors_needed_for_external_client": "Tenga cuidado de que necesita mantener algunas aplicaciones permitidas a los visitantes si tiene la intención de usarlas con clientes externos. Por ejemplo, este es el caso de Nextcloud si desea utilizar un cliente de sincronización en su teléfono inteligente o computadora de escritorio.",
|
||||||
|
"issues": "%s problemas",
|
||||||
|
"unmaintained_details": "Esta aplicación no se ha actualizado durante bastante tiempo y el responsable anterior se ha ido o no tiene tiempo para mantenerla. No dude en consultar el repositorio de aplicaciones para brindar su ayuda",
|
||||||
|
"groups": "Grupos",
|
||||||
|
"restart": "Reiniciar"
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
"app_state_inprogress": "ne fonctionne pas encore",
|
"app_state_inprogress": "ne fonctionne pas encore",
|
||||||
"app_state_notworking": "Non fonctionnelle",
|
"app_state_notworking": "Non fonctionnelle",
|
||||||
"app_state_validated": "Validée",
|
"app_state_validated": "Validée",
|
||||||
"app_state_working": "Fonctionnelle",
|
"app_state_working": "fonctionnelle",
|
||||||
"application": "Application",
|
"application": "Application",
|
||||||
"applications": "Applications",
|
"applications": "Applications",
|
||||||
"archive_empty": "L’archive est vide",
|
"archive_empty": "L’archive est vide",
|
||||||
|
@ -65,7 +65,7 @@
|
||||||
"confirm_change_maindomain": "Voulez-vous vraiment changer le domaine principal ?",
|
"confirm_change_maindomain": "Voulez-vous vraiment changer le domaine principal ?",
|
||||||
"confirm_delete": "Voulez-vous vraiment supprimer %s ?",
|
"confirm_delete": "Voulez-vous vraiment supprimer %s ?",
|
||||||
"confirm_firewall": "Voulez-vous vraiment %s le port %s (protocole: %s, connexion: %s)",
|
"confirm_firewall": "Voulez-vous vraiment %s le port %s (protocole: %s, connexion: %s)",
|
||||||
"confirm_install_custom_app": "AVERTISSEMENT ! L’installation d’applications tierces peut compromettre l’intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l’installer si vous ne savez pas ce que vous faites. Prenez-vous ce risque ?",
|
"confirm_install_custom_app": "ATTENTION ! L’installation d’applications tierces peut compromettre l’intégrité et la sécurité de votre système. Vous ne devriez probablement PAS l’installer si vous ne savez pas ce que vous faites. Prenez-vous ce risque ?",
|
||||||
"confirm_install_domain_root": "Vous ne pourrez pas installer d'autres applications sur %s. Continuer ?",
|
"confirm_install_domain_root": "Vous ne pourrez pas installer d'autres applications sur %s. Continuer ?",
|
||||||
"confirm_postinstall": "Vous êtes sur le point de lancer le processus de post-installation sur le domaine %s. Cela peut prendre du temps, *n'interrompez pas l'opération avant la fin*.",
|
"confirm_postinstall": "Vous êtes sur le point de lancer le processus de post-installation sur le domaine %s. Cela peut prendre du temps, *n'interrompez pas l'opération avant la fin*.",
|
||||||
"confirm_restore": "Voulez-vous vraiment restaurer %s ?",
|
"confirm_restore": "Voulez-vous vraiment restaurer %s ?",
|
||||||
|
@ -139,7 +139,7 @@
|
||||||
"hook_data_home": "Données de l’utilisateur",
|
"hook_data_home": "Données de l’utilisateur",
|
||||||
"hook_data_home_desc": "Les données de l’utilisateur situées dans /home/USER",
|
"hook_data_home_desc": "Les données de l’utilisateur situées dans /home/USER",
|
||||||
"hook_data_mail": "Courriel",
|
"hook_data_mail": "Courriel",
|
||||||
"hook_data_mail_desc": "Les courriels qui sont stockés sur le serveur",
|
"hook_data_mail_desc": "Courriels stockés sur le serveur",
|
||||||
"hostname": "Nom d'hôte",
|
"hostname": "Nom d'hôte",
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
"inactive": "Inactif",
|
"inactive": "Inactif",
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
"select_all": "Tout sélectionner",
|
"select_all": "Tout sélectionner",
|
||||||
"select_none": "Tout désélectionner",
|
"select_none": "Tout désélectionner",
|
||||||
"service_log": "Journal de %s",
|
"service_log": "Journal de %s",
|
||||||
"service_start_on_boot": "Lancer au démarrage : ",
|
"service_start_on_boot": "Lancement au démarrage :",
|
||||||
"service_status": "Statut : ",
|
"service_status": "Statut : ",
|
||||||
"services": "Services",
|
"services": "Services",
|
||||||
"services_list": "Liste des services",
|
"services_list": "Liste des services",
|
||||||
|
@ -239,11 +239,11 @@
|
||||||
"swap": "Espace d’échange",
|
"swap": "Espace d’échange",
|
||||||
"system": "Système",
|
"system": "Système",
|
||||||
"system_apps": "Applications",
|
"system_apps": "Applications",
|
||||||
"system_apps_nothing": "Il n'y a aucune application à mettre à jour.",
|
"system_apps_nothing": "Toutes les applications sont à jour !",
|
||||||
"system_delayed_upgrade": "Mise à jour différée",
|
"system_delayed_upgrade": "Mise à jour différée",
|
||||||
"system_delayed_upgrade_warning": "<b>%s</b> sera mis-à-jour automatiquement durant l'heure suivante.",
|
"system_delayed_upgrade_warning": "<b>%s</b> sera mis-à-jour automatiquement durant l'heure suivante.",
|
||||||
"system_packages": "Paquets",
|
"system_packages": "Paquets système",
|
||||||
"system_packages_nothing": "Aucun paquet n'est à mettre à jour.",
|
"system_packages_nothing": "Tous les packages système sont à jour !",
|
||||||
"system_update": "Mettre à jour le système",
|
"system_update": "Mettre à jour le système",
|
||||||
"system_upgrade": "Mise à jour du système",
|
"system_upgrade": "Mise à jour du système",
|
||||||
"system_upgrade_btn": "Mettre à jour",
|
"system_upgrade_btn": "Mettre à jour",
|
||||||
|
@ -318,7 +318,7 @@
|
||||||
"certificate_authority": "Autorité de certification",
|
"certificate_authority": "Autorité de certification",
|
||||||
"validity": "Validité",
|
"validity": "Validité",
|
||||||
"domain_is_eligible_for_ACME": "Ce domaine semble correctement configuré pour installer un certificat Let’s Encrypt !",
|
"domain_is_eligible_for_ACME": "Ce domaine semble correctement configuré pour installer un certificat Let’s Encrypt !",
|
||||||
"domain_not_eligible_for_ACME": "Ce domaine ne semble pas prêt pour installer un certificat Let’s Encrypt. Veuillez vérifier votre configuration DNS et l’accessibilité HTTP de votre serveur.",
|
"domain_not_eligible_for_ACME": "Ce domaine ne semble pas prêt pour installer un certificat Let’s Encrypt. Veuillez vérifier votre configuration DNS et l’accessibilité HTTP de votre serveur. Les sections 'enregistrement DNS' et 'Web' dans <a href='#/diagnosis'>la page de diagnostic</a> peuvent vous aider à comprendre ce qui est mal configurée.",
|
||||||
"install_letsencrypt_cert": "Installer un certificat Let’s Encrypt",
|
"install_letsencrypt_cert": "Installer un certificat Let’s Encrypt",
|
||||||
"manually_renew_letsencrypt_message": "Le certificat sera renouvelé automatiquement durant les 15 derniers jours de sa validité. Vous pouvez le renouveler manuellement si vous le souhaitez (non recommandé).",
|
"manually_renew_letsencrypt_message": "Le certificat sera renouvelé automatiquement durant les 15 derniers jours de sa validité. Vous pouvez le renouveler manuellement si vous le souhaitez (non recommandé).",
|
||||||
"manually_renew_letsencrypt": "Renouveler manuellement maintenant",
|
"manually_renew_letsencrypt": "Renouveler manuellement maintenant",
|
||||||
|
@ -399,7 +399,7 @@
|
||||||
"error_connection_interrupted": "Le serveur a fermé la connexion au lieu d’y répondre. Est-ce que Nginx a été redémarré ou est-ce que l'API YunoHost s'est-elle arrêtée pour diverses raisons ? (code/message d’erreur : %s)",
|
"error_connection_interrupted": "Le serveur a fermé la connexion au lieu d’y répondre. Est-ce que Nginx a été redémarré ou est-ce que l'API YunoHost s'est-elle arrêtée pour diverses raisons ? (code/message d’erreur : %s)",
|
||||||
"experimental_warning": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l’utiliser à moins que vous ne sachiez ce que vous faites...",
|
"experimental_warning": "Attention : cette fonctionnalité est expérimentale et ne doit pas être considérée comme stable, vous ne devriez pas l’utiliser à moins que vous ne sachiez ce que vous faites...",
|
||||||
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe administrateur. Le mot de passe doit comporter au moins 8 caractères — bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
|
"good_practices_about_admin_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe administrateur. Le mot de passe doit comporter au moins 8 caractères — bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères (majuscules, minuscules, chiffres et caractères spéciaux).",
|
||||||
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.",
|
"good_practices_about_user_password": "Vous êtes maintenant sur le point de définir un nouveau mot de passe pour l'utilisateur. Le mot de passe doit comporter au moins 8 caractères - bien qu’il soit recommandé d’utiliser un mot de passe plus long (c’est-à-dire une phrase secrète) et/ou d’utiliser différents types de caractères tels que : majuscules, minuscules, chiffres et caractères spéciaux.",
|
||||||
"level": "niveau",
|
"level": "niveau",
|
||||||
"only_official_apps": "Applications officielles uniquement",
|
"only_official_apps": "Applications officielles uniquement",
|
||||||
"only_working_apps": "Applications fonctionnelles uniquement",
|
"only_working_apps": "Applications fonctionnelles uniquement",
|
||||||
|
@ -422,28 +422,28 @@
|
||||||
"logs_more": "Afficher plus de lignes",
|
"logs_more": "Afficher plus de lignes",
|
||||||
"search_for_apps": "Recherche des applications…",
|
"search_for_apps": "Recherche des applications…",
|
||||||
"unmaintained": "Non maintenue",
|
"unmaintained": "Non maintenue",
|
||||||
"purge_user_data_checkbox": "Purger les données de % s ? (Cela supprimera le contenu de ses répertoires home et mail.)",
|
"purge_user_data_checkbox": "Purger les données de l'utilisateur %s ? (Cela supprimera le contenu de ses répertoires home et mail.)",
|
||||||
"purge_user_data_warning": "La purge des données de l’utilisateur n’est pas réversible. Assurez-vous de savoir ce que vous faites !",
|
"purge_user_data_warning": "La purge des données de l’utilisateur n’est pas réversible. Assurez-vous de savoir ce que vous faites !",
|
||||||
"version": "Version",
|
"version": "Version",
|
||||||
"confirm_update_system": "Voulez-vous vraiment mettre à jour tous les paquets système ?",
|
"confirm_update_system": "Voulez-vous vraiment mettre à jour tous les paquets système ?",
|
||||||
"app_state_inprogress_explanation": "Le mainteneur de cette application a indiqué qu'elle n'est pas encore prête pour une utilisation en production. FAITES ATTENTION !",
|
"app_state_inprogress_explanation": "Le responsable de cette application a indiqué qu'elle n'est pas encore prête pour une utilisation en production. SOYEZ VIGILANT(E) !",
|
||||||
"app_state_notworking_explanation": "Le mainteneur de cette application a déclaré celle-ci comme \"non fonctionnelle\" SON INSTALLATION PEUT CASSER VOTRE SYSTÈME !",
|
"app_state_notworking_explanation": "Le responsable de cette application a déclaré celle-ci comme \"non fonctionnelle\". SON INSTALLATION POURRAIT CASSER VOTRE SYSTÈME !",
|
||||||
"app_state_high-quality": "Haute qualité",
|
"app_state_high-quality": "Haute qualité",
|
||||||
"app_state_high-quality_explanation": "Cette application est bien intégrée dans YunoHost. Elle a été (et est !) revue par l'équipe applicative de YunoHost. On peut s'attendre à ce qu'elle soit sûre et maintenue sur le long terme.",
|
"app_state_high-quality_explanation": "Cette application est bien intégrée à YunoHost. Elle a été (et est !) revue par l'équipe applicative de YunoHost. On peut s'attendre à ce qu'elle soit sûre et maintenue sur le long terme.",
|
||||||
"app_state_working_explanation": "Le responsable de cette application l'a déclarée comme fonctionnelle. Cela signifie qu'elle doit être utilisable (c.f. niveau de l'application) mais n'est pas nécessairement revue, elle peut encore contenir des bogues ou bien n'est pas entièrement intégrée dans YunoHost.",
|
"app_state_working_explanation": "Le responsable de cette application l'a déclarée comme 'fonctionnelle'. Cela signifie qu'elle doit fonctionner (voir son niveau d'intégration) mais n'est pas nécessairement revue, elle peut encore contenir des bugs ou bien n'est pas entièrement intégrée à YunoHost.",
|
||||||
"hook_conf_ynh_currenthost": "Domaine principal actuel",
|
"hook_conf_ynh_currenthost": "Domaine principal actuel",
|
||||||
"license": "Licence",
|
"license": "Licence",
|
||||||
"maintained": "Maintenue",
|
"maintained": "Maintenue",
|
||||||
"maintained_details": "Cette application a été maintenue par son responsable au cours des tout derniers mois.",
|
"maintained_details": "Cette application a été maintenue par son responsable au cours des derniers mois.",
|
||||||
"only_highquality_apps": "Uniquement des applications de haute qualité",
|
"only_highquality_apps": "Uniquement des applications de haute-qualité",
|
||||||
"only_decent_quality_apps": "Seulement des applications d'une qualité décente",
|
"only_decent_quality_apps": "Seulement des applications d'une qualité décente",
|
||||||
"orphaned": "Non maintenue",
|
"orphaned": "Non maintenue",
|
||||||
"orphaned_details": "Cette application n'a pas été maintenue depuis un certain temps. Il peut encore fonctionner, mais ne recevra aucune mise à niveau jusqu'à ce que quelqu'un se porte volontaire pour s'en occuper. N'hésitez pas à contribuer à la faire revivre !",
|
"orphaned_details": "Cette application n'a pas été maintenue depuis un certain temps. Il peut encore fonctionner, mais ne recevra aucune mise à niveau jusqu'à ce que quelqu'un se porte volontaire pour s'en occuper. N'hésitez pas à contribuer à la faire revivre !",
|
||||||
"request_adoption": "en attente de repreneur",
|
"request_adoption": "en attente de responsable",
|
||||||
"request_adoption_details": "Le responsable actuel aimerait arrêter de maintenir cette application. N'hésitez pas à vous proposer comme nouveau responsable !",
|
"request_adoption_details": "Le responsable actuel ne souhaite plus s'occuper de cette application. N'hésitez pas à vous proposer comme nouveau responsable !",
|
||||||
"request_help": "besoin d'assistance",
|
"request_help": "besoin d'assistance",
|
||||||
"request_help_details": "Le responsable actuel aimerait de l'aide pour la maintenance de cette application. N'hésitez pas à y contribuer !",
|
"request_help_details": "Le responsable actuel aimerait de l'aide pour la maintenance de cette application. N'hésitez pas à y contribuer !",
|
||||||
"advanced": "Avancée",
|
"advanced": "Avancé",
|
||||||
"from_to": "de %s à %s",
|
"from_to": "de %s à %s",
|
||||||
"group_name": "Nom du groupe",
|
"group_name": "Nom du groupe",
|
||||||
"nobody": "Personne",
|
"nobody": "Personne",
|
||||||
|
@ -473,10 +473,18 @@
|
||||||
"configuration": "Configuration",
|
"configuration": "Configuration",
|
||||||
"since": "depuis",
|
"since": "depuis",
|
||||||
"all": "Tout",
|
"all": "Tout",
|
||||||
"app_state_low_quality": "basse qualité",
|
"app_state_low_quality": "faible qualité",
|
||||||
"app_state_low_quality_explanation": "Cette application peut être fonctionnelle, mais peut toujours contenir des problèmes, ou n'est pas entièrement intégrée à YunoHost, ou elle ne respecte pas les bonnes pratiques.",
|
"app_state_low_quality_explanation": "Cette application peut être fonctionnelle, mais peut toujours contenir des problèmes, ou n'est pas entièrement intégrée à YunoHost, ou elle ne respecte pas les bonnes pratiques.",
|
||||||
"catalog": "Catalogue",
|
"catalog": "Catalogue",
|
||||||
"others": "Autres",
|
"others": "Autres",
|
||||||
"diagnosis_first_run": "La fonctionnalité de diagnostic va tenter de trouver certains problèmes communs sur différents aspects de votre serveur pour être sûr que tout fonctionne normalement. Merci de ne pas paniquer si vous voyez une multitude d'erreurs après avoir configuré votre serveur : la fonctionnalité est précisément prévue pour les identifier et vous aider à les résoudre. Le diagnostic sera également effectué deux fois par jour et enverra un mail à l'administrateur si des erreurs sont détectées.",
|
"diagnosis_first_run": "La fonctionnalité de diagnostic va tenter de trouver certains problèmes communs sur différents aspects de votre serveur pour être sûr que tout fonctionne normalement. Merci de ne pas paniquer si vous voyez une multitude d'erreurs après avoir configuré votre serveur : la fonctionnalité est précisément prévue pour les identifier et vous aider à les résoudre. Le diagnostic sera également effectué deux fois par jour et enverra un mail à l'administrateur si des erreurs sont détectées.",
|
||||||
"run_first_diagnosis": "Démarrer le diagnostic initial"
|
"run_first_diagnosis": "Démarrer le diagnostic initial",
|
||||||
|
"confirm_service_restart": "Êtes-vous certain de vouloir redémarrer %s ?",
|
||||||
|
"groups": "Groupes",
|
||||||
|
"restart": "Redémarrer",
|
||||||
|
"unmaintained_details": "Cette application n'a pas été mise à jour depuis un bon moment et le responsable précédent est parti ou n'a pas le temps de maintenir cette application. N'hésitez pas à consulter le référentiel des applications pour apporter votre aide",
|
||||||
|
"group_explain_visitors_needed_for_external_client": "Veillez à ce que certaines applications soient autorisées pour les visiteurs si vous avez l'intention de les utiliser avec des clients externes. Par exemple, c'est le cas pour Nextcloud si vous souhaitez avoir l'intention d'utiliser un client de synchronisation sur votre smartphone ou ordinateur de bureau.",
|
||||||
|
"issues": "%s problèmes",
|
||||||
|
"operation_failed_explanation": "L'opération a échoué ! Veuillez-nous excuser pour ça :( Vous pouvez essayer de <a href='https://yunohost.org/help'>demander de l'aide</a>. Merci de fournir *le log complet* de l'opération pour les personnes qui vont vous aider. Vous pouvez cliquer sur le bouton vert 'Partager avec Yunopaste'. Quand vous partagez les logs, YunoHost essaie automatiquement d'anonymiser les informations privées comme le nom de domaine et l'adresses IP.",
|
||||||
|
"diagnosis_explanation": "La fonctionnalité de diagnostic va tenter de trouver certains problèmes communs sur différents aspects de votre serveur pour être sûr que tout fonctionne normalement. Le diagnostic sera également effectué deux fois par jour et enverra un mail à l'administrateur si des erreurs sont détectées. À noter que certains tests ne seront pas montrés si vous n'utilisez pas certaines fonctions spécifiques (XMPP, par exemple) ou s'ils échouent à cause d'une configuration trop complexe. Dans ce cas, et si vous savez ce que vous avez modifié, vous pouvez ignorer les problèmes et les avertissements correspondantes."
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"add": "Aggiungi",
|
"add": "Aggiungi",
|
||||||
"administration_password": "Password amministrazione",
|
"administration_password": "Password amministrazione",
|
||||||
"allowed_users": "Utenti consentiti",
|
"allowed_users": "Utenti consentiti",
|
||||||
"api_not_responding": "Le API non rispondono",
|
"api_not_responding": "Le API YunoHost non rispondono. Forse 'yunohost-api' è giù o è stato riavviato?",
|
||||||
"app_access": "Accesso",
|
"app_access": "Accesso",
|
||||||
"app_access_addall_btn": "Attiva l'accesso per tutti",
|
"app_access_addall_btn": "Attiva l'accesso per tutti",
|
||||||
"app_access_addall_desc": "Tutti gli utenti esistenti avranno accesso a %s.",
|
"app_access_addall_desc": "Tutti gli utenti esistenti avranno accesso a %s.",
|
||||||
|
@ -425,5 +425,26 @@
|
||||||
"purge_user_data_checkbox": "Eliminare i dati di %s? (Questo rimuoverà il contenuto delle sue cartelle home e mail.)",
|
"purge_user_data_checkbox": "Eliminare i dati di %s? (Questo rimuoverà il contenuto delle sue cartelle home e mail.)",
|
||||||
"purge_user_data_warning": "L'eliminazione dei dati utente non è annullabile. Assicurati di sapere cosa stai facendo!",
|
"purge_user_data_warning": "L'eliminazione dei dati utente non è annullabile. Assicurati di sapere cosa stai facendo!",
|
||||||
"hook_conf_ynh_currenthost": "Dominio principale attuale",
|
"hook_conf_ynh_currenthost": "Dominio principale attuale",
|
||||||
"confirm_update_system": "Sei sicuro di voler aggiornare tutti i pacchetti di sistema?"
|
"confirm_update_system": "Sei sicuro di voler aggiornare tutti i pacchetti di sistema?",
|
||||||
|
"app_state_inprogress_explanation": "Questo maintainer di questa applicazione ha dichiarato che l'applicazione non è ancora pronta per l'uso in produzione. ATTENZIONE!",
|
||||||
|
"app_state_notworking_explanation": "Questo maintainer di questa applicazione ha dichiarato che \"non funziona\". SI ROMPERÀ IL VOSTRO SISTEMA!",
|
||||||
|
"app_state_high-quality": "alta qualità",
|
||||||
|
"group_add_permission": "Aggiungere un permesso",
|
||||||
|
"group_explain_all_users": "Questo è un gruppo speciale contenente tutti gli account di tutti gli utenti sul server",
|
||||||
|
"group": "Gruppo",
|
||||||
|
"group_name": "Nome del gruppo",
|
||||||
|
"group_all_users": "Tutti gli utenti",
|
||||||
|
"group_visitors": "Visitori",
|
||||||
|
"group_format_name_help": "È possibile utilizzare caratteri alfanumerici e spazio",
|
||||||
|
"group_add_member": "Aggiungere un utente",
|
||||||
|
"app_state_high-quality_explanation": "Questa applicazione è ben integrata con YunoHost. E 'stato (ed è!) peer-reviewed dal team di YunoHost app. Ci si può aspettare che sia sicuro e mantenuto a lungo termine.",
|
||||||
|
"details": "Dettagli",
|
||||||
|
"diagnosis_experimental_disclaimer": "Siate consapevoli che la funzione di diagnosi è ancora sperimentale e in fase di perfezionamento, e potrebbe non essere completamente affidabile.",
|
||||||
|
"errors": "%s errori",
|
||||||
|
"everything_good": "Tutto bene!",
|
||||||
|
"from_to": "da %s a %s",
|
||||||
|
"configuration": "Configuratione",
|
||||||
|
"advanced": "Avanzate",
|
||||||
|
"app_state_working_explanation": "Il manutentore di questa applicazione lo ha dichiarato \"funzionante\". Significa che dovrebbe essere funzionale (c.f. livello di applicazione) ma non è necessariamente sottoposta a peer-reviewing, può ancora contenere problemi o non è pienamente integrata con YunoHost.",
|
||||||
|
"group_new": "Nuovo gruppo"
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"configuration": "कन्फिगरेसन",
|
"configuration": "कन्फिगरेसन",
|
||||||
"close": "बन्द",
|
"close": "बन्द",
|
||||||
"check": "जाँच गर्नुहोस्",
|
"check": "जाँच गर्नुहोस्",
|
||||||
"cancel": "रद्द",
|
"cancel": "रद्द गर्नुहोस्",
|
||||||
"both": "दुबै",
|
"both": "दुबै",
|
||||||
"begin": "सुरु गर्नुहोस्",
|
"begin": "सुरु गर्नुहोस्",
|
||||||
"backups_no": "कुनै ब्याकअप छैन",
|
"backups_no": "कुनै ब्याकअप छैन",
|
||||||
|
@ -54,5 +54,8 @@
|
||||||
"remove": "हटाउनुहोस्",
|
"remove": "हटाउनुहोस्",
|
||||||
"add": "थप्नुहोस्",
|
"add": "थप्नुहोस्",
|
||||||
"active": "सक्रिय",
|
"active": "सक्रिय",
|
||||||
"action": "कार्य"
|
"action": "कार्य",
|
||||||
|
"password": "पासवर्ड",
|
||||||
|
"ok": "ठिक छ",
|
||||||
|
"logged_out": "लग आउट"
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,7 +241,7 @@
|
||||||
"save": "Salvagardar",
|
"save": "Salvagardar",
|
||||||
"select_user": "Causissètz un utilizaire",
|
"select_user": "Causissètz un utilizaire",
|
||||||
"service_log": "Jornal de %s",
|
"service_log": "Jornal de %s",
|
||||||
"service_start_on_boot": "Lançar en aviar : ",
|
"service_start_on_boot": "Lançar en aviar",
|
||||||
"service_status": "Estatut : ",
|
"service_status": "Estatut : ",
|
||||||
"services": "Servicis",
|
"services": "Servicis",
|
||||||
"services_list": "Lista dels servicis",
|
"services_list": "Lista dels servicis",
|
||||||
|
@ -257,7 +257,7 @@
|
||||||
"swap": "Espaci d’escambi",
|
"swap": "Espaci d’escambi",
|
||||||
"system": "Sistèma",
|
"system": "Sistèma",
|
||||||
"system_apps": "Aplicacions",
|
"system_apps": "Aplicacions",
|
||||||
"system_apps_nothing": "I a pas cap d’aplicacion de metre a jorn.",
|
"system_apps_nothing": "Totas las aplicacions son a jorn !",
|
||||||
"system_delayed_upgrade": "Mesa a jorn reportada",
|
"system_delayed_upgrade": "Mesa a jorn reportada",
|
||||||
"system_delayed_upgrade_warning": "<b>%s</b> serà mes a jorn dins l’ora venenta.",
|
"system_delayed_upgrade_warning": "<b>%s</b> serà mes a jorn dins l’ora venenta.",
|
||||||
"system_packages": "Paquets sistèma",
|
"system_packages": "Paquets sistèma",
|
||||||
|
@ -374,7 +374,7 @@
|
||||||
"certificate_alert_about_to_expire": "Atencion : lo certificat actual es a man d’expirar ! Serà pas renovat automaticament !",
|
"certificate_alert_about_to_expire": "Atencion : lo certificat actual es a man d’expirar ! Serà pas renovat automaticament !",
|
||||||
"certificate_alert_great": "Perfièch ! Sètz a utilizar un certificat Let’s Encrypt valid !",
|
"certificate_alert_great": "Perfièch ! Sètz a utilizar un certificat Let’s Encrypt valid !",
|
||||||
"certificate_old_letsencrypt_app_conflict": "L’aplicacion « letsencrypt » es actualament installada e es en conflicte amb aquesta foncionalitat. Mercés de la desinstallar per utilizar la novèla interfàcia de gestion dels certificats.",
|
"certificate_old_letsencrypt_app_conflict": "L’aplicacion « letsencrypt » es actualament installada e es en conflicte amb aquesta foncionalitat. Mercés de la desinstallar per utilizar la novèla interfàcia de gestion dels certificats.",
|
||||||
"domain_not_eligible_for_ACME": "Aqueste domeni sembla pas prèst per un certificat Let’s Encrypt. Mercés de verificar la configuracion DNS e l’accessibilitat del servidor HTTP.",
|
"domain_not_eligible_for_ACME": "Aqueste domeni sembla pas prèst per un certificat Let’s Encrypt. Mercés de verificar la configuracion DNS e l’accessibilitat del servidor HTTP. Las seccions « enregistrament DNS » e « Web » de <a href='#/diagnosis'>la pagina de diagnostic</a> pòt vos ajudar a comprendre çò qu’es pas configurat coma cal.",
|
||||||
"manually_renew_letsencrypt_message": "Lo certificat serà renovat automaticament pendent los 15 darrièrs jorns de validitat. Podètz lo renovar manualament se volètz. (Pas recomandat).",
|
"manually_renew_letsencrypt_message": "Lo certificat serà renovat automaticament pendent los 15 darrièrs jorns de validitat. Podètz lo renovar manualament se volètz. (Pas recomandat).",
|
||||||
"meltdown": "Sètz vulnerable a la falha de seguretat critica <a target=\"_blank\" href=\"https://meltdownattack.com/\">meltdown</a>. Per dire de resòlvre aqueste problèma, vos cal <a href=\"#/update\">actualizar vòstre sistèma</a> puèi <a href=\"#/tools/reboot\"> lo tornar aviar</a> per cargar lo nòu nuclèu linux.",
|
"meltdown": "Sètz vulnerable a la falha de seguretat critica <a target=\"_blank\" href=\"https://meltdownattack.com/\">meltdown</a>. Per dire de resòlvre aqueste problèma, vos cal <a href=\"#/update\">actualizar vòstre sistèma</a> puèi <a href=\"#/tools/reboot\"> lo tornar aviar</a> per cargar lo nòu nuclèu linux.",
|
||||||
"revert_to_selfsigned_cert_message": "S’o volètz vertadièrament, podètz tornar installar lo certificat auto-signat. (Pas recomandat)",
|
"revert_to_selfsigned_cert_message": "S’o volètz vertadièrament, podètz tornar installar lo certificat auto-signat. (Pas recomandat)",
|
||||||
|
@ -470,5 +470,10 @@
|
||||||
"all": "Totas",
|
"all": "Totas",
|
||||||
"app_state_low_quality": "qualitat bassa",
|
"app_state_low_quality": "qualitat bassa",
|
||||||
"catalog": "Catalòg",
|
"catalog": "Catalòg",
|
||||||
"others": "Autras"
|
"others": "Autras",
|
||||||
|
"run_first_diagnosis": "Executar lo diagnostic inicial",
|
||||||
|
"confirm_service_restart": "Volètz vertadièrament reaviar %s ?",
|
||||||
|
"restart": "Reaviar",
|
||||||
|
"groups": "Grops",
|
||||||
|
"issues": "%s problèmas"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"password": "hasło",
|
"password": "Hasło",
|
||||||
"action": "Akcja",
|
"action": "Akcja",
|
||||||
"active": "Aktywny",
|
"active": "Aktywny",
|
||||||
"add": "Dodaj",
|
"add": "Dodaj",
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
"free": "Livre",
|
"free": "Livre",
|
||||||
"fs_type": "Tipo de Sistema de Ficheiros",
|
"fs_type": "Tipo de Sistema de Ficheiros",
|
||||||
"gateway": "Gateway: ",
|
"gateway": "Gateway: ",
|
||||||
"hook_conf_ldap": "LDAP",
|
"hook_conf_ldap": "Base de dados LDAP",
|
||||||
"hook_conf_nginx": "Nginx",
|
"hook_conf_nginx": "Nginx",
|
||||||
"hook_conf_ssh": "SSH",
|
"hook_conf_ssh": "SSH",
|
||||||
"hook_conf_ssowat": "SSOwat",
|
"hook_conf_ssowat": "SSOwat",
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
"yes": "Sim",
|
"yes": "Sim",
|
||||||
"cancel": "Cancelar",
|
"cancel": "Cancelar",
|
||||||
"remove": "Remover",
|
"remove": "Remover",
|
||||||
"api_not_responding": "API não está respondendo",
|
"api_not_responding": "A API YunoHost não está respondendo. Talvez 'yunohost-api' esteja desligada ou foi reiniciada?",
|
||||||
"app_change_label": "Mudar etiqueta",
|
"app_change_label": "Mudar etiqueta",
|
||||||
"app_change_url": "Mudar URL",
|
"app_change_url": "Mudar URL",
|
||||||
"app_debug_no_logs": "Logs da aplicação não estão disponíveis",
|
"app_debug_no_logs": "Logs da aplicação não estão disponíveis",
|
||||||
|
@ -243,7 +243,7 @@
|
||||||
"app_no_actions": "Esta aplicação não tem nenhuma ação",
|
"app_no_actions": "Esta aplicação não tem nenhuma ação",
|
||||||
"app_repository": "Origem da aplicação: ",
|
"app_repository": "Origem da aplicação: ",
|
||||||
"app_state": "Estado da aplicação: ",
|
"app_state": "Estado da aplicação: ",
|
||||||
"app_state_inprogress": "Em curso",
|
"app_state_inprogress": "ainda não está funcionando",
|
||||||
"app_state_inprogress_explanation": "O responsável desta aplicação afirmou que não está pronta ainda para ser usada em produção. TENHA CUIDADO!",
|
"app_state_inprogress_explanation": "O responsável desta aplicação afirmou que não está pronta ainda para ser usada em produção. TENHA CUIDADO!",
|
||||||
"app_state_notworking": "Não funcionando",
|
"app_state_notworking": "Não funcionando",
|
||||||
"app_state_notworking_explanation": "O responsável desta aplicação afirmou que não está funcionando. INSTALANDO-A PODE QUEBRAR SEU SISTEMA!",
|
"app_state_notworking_explanation": "O responsável desta aplicação afirmou que não está funcionando. INSTALANDO-A PODE QUEBRAR SEU SISTEMA!",
|
||||||
|
@ -318,5 +318,6 @@
|
||||||
"diagnosis_experimental_disclaimer": "Esteja ciente de que a ferramenta de diagnóstico ainda é experimental e está em fase de aperfeiçoamento, e pode não ser totalmente confiável.",
|
"diagnosis_experimental_disclaimer": "Esteja ciente de que a ferramenta de diagnóstico ainda é experimental e está em fase de aperfeiçoamento, e pode não ser totalmente confiável.",
|
||||||
"details": "Detalhes",
|
"details": "Detalhes",
|
||||||
"catalog": "Catálogo",
|
"catalog": "Catálogo",
|
||||||
"configuration": "Configuração"
|
"configuration": "Configuração",
|
||||||
|
"confirm_service_restart": "Tem certeza que deseja reiniciar %s?"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"add": "Ekle",
|
"add": "Ekle",
|
||||||
"administration_password": "Yönetici parolası",
|
"administration_password": "Yönetici parolası",
|
||||||
"api_not_responding": "YunoHost API'si cevap vermiyor. Belki 'yunohost-api' çalışmıyor veya yeniden başlatıldı?",
|
"api_not_responding": "YunoHost API'si yanıt vermiyor. Belki 'yunohost-api' çalışmıyor veya yeniden başlatıldı?",
|
||||||
"both": "İkisi birden",
|
"both": "İkisi birden",
|
||||||
"cancel": "İptal etmek",
|
"cancel": "İptal etmek",
|
||||||
"close": "Kapat",
|
"close": "Kapat",
|
||||||
|
@ -15,13 +15,13 @@
|
||||||
"delete": "Sil",
|
"delete": "Sil",
|
||||||
"description": "Açıklama",
|
"description": "Açıklama",
|
||||||
"disable": "Devredışı bırak",
|
"disable": "Devredışı bırak",
|
||||||
"domain": "Domain",
|
"domain": "Alan adı",
|
||||||
"domain_name": "Domain ismi",
|
"domain_name": "Domain ismi",
|
||||||
"domains": "Domainler",
|
"domains": "Domainler",
|
||||||
"enable": "Devreye al",
|
"enable": "Devreye al",
|
||||||
"error_modify_something": "Bir şeyleri değiştirmelisiniz",
|
"error_modify_something": "Bir şeyleri değiştirmelisiniz",
|
||||||
"error_occured": "Bir hata oluştu, tekrar deneyiniz",
|
"error_occured": "Bir hata oluştu, tekrar deneyiniz",
|
||||||
"error_retrieve_feed": "Akış alınamadı : %s",
|
"error_retrieve_feed": "Feed alınamadı:% s. Tarayıcınızın bu isteği yerine getirmesini engelleyen bir eklentiniz olabilir (veya web sitesi kapalı).",
|
||||||
"error_select_domain": "Domain belirtmelisiniz",
|
"error_select_domain": "Domain belirtmelisiniz",
|
||||||
"error_server": "Sunucu hatası",
|
"error_server": "Sunucu hatası",
|
||||||
"home": "Başlangıç",
|
"home": "Başlangıç",
|
||||||
|
@ -80,5 +80,24 @@
|
||||||
"remove": "Kaldır",
|
"remove": "Kaldır",
|
||||||
"advanced": "Gelişmiş",
|
"advanced": "Gelişmiş",
|
||||||
"active": "Etkin",
|
"active": "Etkin",
|
||||||
"action": "Eylem"
|
"action": "Eylem",
|
||||||
|
"app_state_notworking_explanation": "Bu uygulamanın bu geliştiricisi 'çalışmıyor' olarak ilan etti. SİSTEMİNİZİ KIRACAK!",
|
||||||
|
"app_install_custom_no_manifest": "Manifest.json dosyası yok",
|
||||||
|
"app_state_inprogress_explanation": "Bu uygulamanın bu sürdürücü, bu uygulamanın henüz üretim kullanımına hazır olmadığını açıkladı. DİKKATLİ OL!",
|
||||||
|
"app_state_high-quality_explanation": "Bu uygulama YunoHost ile iyi entegre edilmiştir. YunoHost uygulama ekibi tarafından hakemli bir incelemedir. Güvenli olması ve uzun vadede korunması beklenebilir.",
|
||||||
|
"last_ran": "Son sefer:",
|
||||||
|
"app_state_high-quality": "yüksek kalite",
|
||||||
|
"app_info_uninstall_desc": "Bu uygulamayı kaldırın.",
|
||||||
|
"app_state_low_quality": "Düşük kalite",
|
||||||
|
"app_state_low_quality_explanation": "Bu uygulama işlevsel olabilir, ancak yine de sorunlar içerebilir veya YunoHost ile tamamen entegre değildir veya iyi uygulamalara uymaz.",
|
||||||
|
"purge_user_data_checkbox": "%s verileri temizlensin mi? (Bu işlem ana ve posta dizinlerinin içeriğini silecektir.)",
|
||||||
|
"app_info_change_url_disabled_tooltip": "Bu özellik bu uygulamada henüz uygulanmadı",
|
||||||
|
"app_state_notworking": "çalışmıyor",
|
||||||
|
"app_info_default_desc": "Alan adı kökünü bu uygulamaya yönlendirin (% s).",
|
||||||
|
"app_state_inprogress": "Henüz çalışmıyor",
|
||||||
|
"app_info_changeurl_desc": "Bu uygulamanın erişim URL'sini değiştirin (alan adı ve / veya yol).",
|
||||||
|
"app_install_cancel": "Yükleme iptal edildi.",
|
||||||
|
"app_info_changelabel_desc": "Portaldaki uygulama etiketini değiştirin.",
|
||||||
|
"app_make_default": "Varsayılan yap",
|
||||||
|
"app_no_actions": "Bu uygulamanın herhangi bir eylemi yok"
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,5 +11,6 @@
|
||||||
"logged_out": "登出",
|
"logged_out": "登出",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"ok": "好",
|
"ok": "好",
|
||||||
"password": "密码"
|
"password": "密码",
|
||||||
|
"logged_in": "登录"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
<div class="btn-breadcrumb">
|
<div class="btn-breadcrumb">
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
<a href="#/apps">{{t 'applications'}}</a>
|
<a href="#/apps">{{t 'applications'}}</a>
|
||||||
<a href="#/apps/install">{{t 'install'}}</a>
|
<a href="#/apps/catalog">{{t 'catalog'}}</a>
|
||||||
|
<a href="#/apps/catalog/{{category.id}}">{{category.title}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="input-group" id="app-filter-input">
|
<div class="input-group" id="app-filter-input">
|
||||||
<span class="input-group-addon"><i class="fas fa-search"></i></span>
|
<div class="input-group-btn"><a class="btn btn-primary" href="#/apps/catalog"><i class="fa-arrow-left"></i></a></div>
|
||||||
|
<span class="input-group-addon"><i class="fa-fw fa-{{category.icon}}"></i> {{category.title}}</span>
|
||||||
|
<span class="input-group-addon" style="background: white;border: none;"> </span>
|
||||||
|
<span class="input-group-addon"><i class="fa-search"></i></span>
|
||||||
<input type="text" id="filter-app-cards" class="form-control" role="textbox" placeholder="{{t 'search_for_apps'}}" aria-describedby="basic-addon0"/>
|
<input type="text" id="filter-app-cards" class="form-control" role="textbox" placeholder="{{t 'search_for_apps'}}" aria-describedby="basic-addon0"/>
|
||||||
<div class="input-group-btn">
|
<div class="input-group-btn">
|
||||||
<button type="button" role="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span id="app-cards-list-filter-text">{{t 'only_decent_quality_apps'}}</span> <span class="caret"></span>
|
<span id="app-cards-list-filter-text">{{t 'only_decent_quality_apps'}}</span> <span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul id="dropdownFilter" class="dropdown-menu" data-filter="decentQuality" role="menu">
|
<ul id="dropdownFilter" class="dropdown-menu" data-filter="decentQuality" role="menu">
|
||||||
|
@ -24,32 +28,51 @@
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="list-group grid">
|
<div class="subtag-selector">
|
||||||
{{#apps}}
|
{{#if category.subtags}}
|
||||||
<div class="app-card panel panel-default {{status}} {{state}} {{isWorking}} {{isHighQuality}} {{decentQuality}} {{level}}-level">
|
<button class="btn btn-default active" data-subtag="all">{{t 'all'}}</button>
|
||||||
<div class="panel-body">
|
{{/if}}
|
||||||
<h2 class="app-title">{{name}}</h2>
|
{{#category.subtags}}
|
||||||
<div class="category">
|
<button class="btn btn-default" data-subtag="{{id}}">{{title}}</button>
|
||||||
<span class="label label-{{stateColor}} label-as-badge app-state" title="{{t (concat 'app_state_' state '_explanation') }}">{{t (concat 'app_state_' state) }}</span>
|
{{/category.subtags}}
|
||||||
<a target="_BLANK" href="https://yunohost.org/#/packaging_apps_levels"><span class="label label-{{levelColor}} label-as-badge app-level" title="{{t 'app_level'}}">{{t 'level'}} {{levelFormatted}}</span></a>
|
{{#if category.subtags}}
|
||||||
<span class="label label-{{maintainedColor}} label-as-badge maintained-status" title="{{t (concat maintained '_details') }}"> {{t maintained}}</span>
|
<button class="btn btn-default" data-subtag="others">{{t 'others'}}</button>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="app-card-desc">{{description}}</div>
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div id="apps" class="list-group grid">
|
||||||
|
{{#apps}}
|
||||||
|
<div class="app-card panel panel-default {{state}} {{isWorking}} {{isHighQuality}} {{decentQuality}} {{level}}-level" data-subtags="{{#subtags}}{{.}}{{#unless @last}},{{/unless}}{{/subtags}}">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2 class="app-title">
|
||||||
|
{{manifest.name}}
|
||||||
|
{{#if (eq state 'working') }}
|
||||||
|
{{#if (eq decentQuality 'badQuality')}}
|
||||||
|
<span class="label label-warning label-as-badge app-state" title="{{t 'app_state_low_quality_explanation' }}">{{t 'app_state_low_quality' }}</span>
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
<span class="label label-{{stateColor}} label-as-badge app-state" title="{{t (concat 'app_state_' state '_explanation') }}">{{t (concat 'app_state_' state) }}</span>
|
||||||
|
{{/if}}
|
||||||
|
</h2>
|
||||||
|
<div class="app-card-desc">{{manifest.description}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-card-date-maintainer">
|
<div class="app-card-date-maintainer">
|
||||||
<i class="fa-refresh"></i> {{formatDate updateDate day="numeric" month="long" year="numeric"}} -
|
{{#if (eq maintainedColor 'danger') }}
|
||||||
<span title="{{t 'current_maintainer_title'}}" class="maintained"></span><i class="fa-user"></i> {{manifest.maintainer}}</span>
|
<span class="text text-warning maintained-status" title="{{t (concat maintained '_details') }}"><i class="fa-fw fa-warning"></i> {{t maintained}}</span>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<a href="{{git.url}}" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
<a href="{{git.url}}" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
||||||
<i class="fa-globe"></i> Code
|
<i class="fa-fw fa-code"></i> Code
|
||||||
</a>
|
</a>
|
||||||
<a href="{{git.url}}/blob/master/README.md" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
<a href="{{git.url}}/blob/master/README.md" target="_BLANK" type="button" role="button" class="btn btn-default col-xs-4">
|
||||||
<i class="fa-book"></i> Readme
|
<i class="fa-fw fa-book"></i> Readme
|
||||||
</a>
|
</a>
|
||||||
{{#installable}}
|
{{#installable}}
|
||||||
<a href="#/apps/install/{{id}}" type="button" role="button" class="btn btn-{{installColor}} col-xs-4 active">
|
<a href="#/apps/install/{{manifest.id}}" type="button" role="button" class="btn btn-{{installColor}} col-xs-4 active">
|
||||||
<i class="fa-plus"></i> {{t 'install'}}{{^isSafe}} <i class="fa-warning"></i>{{/isSafe}}
|
<i class="fa-fw fa-plus"></i> {{t 'install'}}{{^isSafe}} <i class="fa-fw fa-warning"></i>{{/isSafe}}
|
||||||
</a>
|
</a>
|
||||||
{{/installable}}
|
{{/installable}}
|
||||||
{{^installable}}
|
{{^installable}}
|
||||||
|
@ -60,28 +83,29 @@
|
||||||
{{/apps}}
|
{{/apps}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div id="install-custom-app" class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-download"></span> {{t 'custom_app_install'}}</h2>
|
<h2 class="panel-title"><span class="fa-fw fa-download"></span> {{t 'custom_app_install'}}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p class="alert alert-warning">
|
<p class="alert alert-warning">
|
||||||
<span class="fa-warning"></span>
|
<span class="fa-fw fa-warning"></span>
|
||||||
{{t 'confirm_install_custom_app'}}
|
{{t 'confirm_install_custom_app'}}
|
||||||
</p>
|
</p>
|
||||||
<form action="#/apps/install/custom" method="POST" class="form-horizontal">
|
|
||||||
|
<form class="form-horizontal">
|
||||||
<div class="form-group has-feedback">
|
<div class="form-group has-feedback">
|
||||||
<label for="url" class="col-sm-12">{{t 'url'}}</label>
|
<label for="url" class="col-sm-12">{{t 'url'}}</label>
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<input type="url" id="url" name="url" class="form-control" value="" placeholder="https://github.com/USER/REPOSITORY" required pattern="^https://github.com/[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_.]+[/]?$">
|
<input type="url" id="url" name="url" class="form-control" value="" placeholder="https://github.com/USER/REPOSITORY" required pattern="^https://github.com/[a-zA-Z0-9-_.]+/[a-zA-Z0-9-_.]+[/]?$">
|
||||||
<p class="text-warning">
|
<p class="text-warning">
|
||||||
<span class="fa-github"></span> {{t 'custom_app_url_only_github'}}
|
<span class="fa-fw fa-github"></span> {{t 'custom_app_url_only_github'}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<input type="submit" role="button" class="btn btn-success slide" value="{{t 'install'}}">
|
<a role="button" class="btn btn-success slide">{{t 'install'}}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
23
src/views/app/app_catalog_home.ms
Normal file
23
src/views/app/app_catalog_home.ms
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/apps">{{t 'applications'}}</a>
|
||||||
|
<a href="#/apps/catalog">{{t 'catalog'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div id="category-selector" class="list-group grid">
|
||||||
|
<a class="app-category-card panel panel-default" href="#/apps/catalog/all">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2 class="app-category-title" style="padding-top: 1em;"><span class="fa-fw fa-search"></span> {{t 'all_apps'}}</h2>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{#categories}}
|
||||||
|
<a class="app-category-card panel panel-default" href="#/apps/catalog/{{id}}">
|
||||||
|
<div class="panel-body">
|
||||||
|
<h2 class="app-category-title"><span class="fa-fw fa-{{icon}}"></span> {{title}}</h2>
|
||||||
|
<h3 class="app-category-card-desc">{{description}}</h3>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
{{/categories}}
|
||||||
|
</div>
|
|
@ -1,39 +0,0 @@
|
||||||
<div class="btn-breadcrumb">
|
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
|
||||||
<a href="#/apps">{{t 'applications'}}</a>
|
|
||||||
<a href="#/apps/{{name}}">{{label}}</a>
|
|
||||||
<a href="#/apps/{{name}}/debug">{{t 'debug'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
{{#if services}}
|
|
||||||
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
|
||||||
{{#services}}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading" role="tab" id="heading-{{ @index }}">
|
|
||||||
<h2 class="panel-title">
|
|
||||||
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-{{ @index }}" aria-expanded="true" aria-controls="collapse-{{ @index }}">
|
|
||||||
<span class="fa-fw fa-info-circle"></span> {{t 'service_log' name }}
|
|
||||||
</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div id="collapse-{{ @index }}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-{{ @index }}">
|
|
||||||
<div class="panel-body">
|
|
||||||
{{#logs}}
|
|
||||||
<h3>{{file_name}}</h3>
|
|
||||||
<pre id="service-log-{{ @index }}" class="service-log">{{file_content}}</pre>
|
|
||||||
<button data-paste-content="#service-log-{{ @index }}"><i class="fa-cloud-upload"></i> {{t 'upload'}}</button>
|
|
||||||
{{/logs}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/services}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<span class="fa-exclamation-triangle"></span>
|
|
||||||
{{t 'app_debug_no_logs'}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
|
@ -22,7 +22,7 @@
|
||||||
<dt>{{t 'version'}}</dt>
|
<dt>{{t 'version'}}</dt>
|
||||||
<dd>{{version}}</dd>
|
<dd>{{version}}</dd>
|
||||||
<dt>{{t 'multi_instance'}}</dt>
|
<dt>{{t 'multi_instance'}}</dt>
|
||||||
<dd>{{manifest.multi_instance}}</dd>
|
<dd>{{supports_multi_instance}}</dd>
|
||||||
<dt>{{t 'install_time'}}</dt>
|
<dt>{{t 'install_time'}}</dt>
|
||||||
<dd>{{formatTime install_time day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
<dd>{{formatTime install_time day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
||||||
{{#if settings.domain}}
|
{{#if settings.domain}}
|
||||||
|
@ -57,14 +57,14 @@
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'app_info_default_desc' settings.domain}}</p>
|
<p>{{t 'app_info_default_desc' settings.domain}}</p>
|
||||||
<a role="button" href="#/apps/{{settings.id}}/default" class="btn btn-success slide">
|
<button class="btn btn-success" data-action="set-as-default" data-app="{{settings.id}}">
|
||||||
<span class="fa-star"></span> {{t 'app_make_default'}}
|
<span class="fa-star"></span> {{t 'app_make_default'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'app_info_changeurl_desc' settings.domain}}</p>
|
<p>{{t 'app_info_changeurl_desc' settings.domain}}</p>
|
||||||
{{#if change_url}}
|
{{#if supports_change_url}}
|
||||||
<a href="#/apps/{{settings.id}}/changeurl" role="button" class="btn btn-info slide">
|
<a href="#/apps/{{settings.id}}/changeurl" role="button" class="btn btn-info slide">
|
||||||
<span class="fa-exchange"></span> {{t 'app_change_url'}}
|
<span class="fa-exchange"></span> {{t 'app_change_url'}}
|
||||||
</a>
|
</a>
|
||||||
|
@ -79,16 +79,9 @@
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'app_info_uninstall_desc'}}</p>
|
<p>{{t 'app_info_uninstall_desc'}}</p>
|
||||||
<a href="#/apps/{{settings.id}}/uninstall" role="button" class="btn btn-danger slide back">
|
<button class="btn btn-danger slide back" data-action="uninstall" data-app="{{settings.id}}">
|
||||||
<span class="fa-trash-o"></span> {{t 'uninstall'}}
|
<span class="fa-trash-o"></span> {{t 'uninstall'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div class="container">
|
|
||||||
<p>{{t 'app_info_debug_desc'}}</p>
|
|
||||||
<a href="#/apps/{{settings.id}}/debug" role="button" class ="btn btn-warning slide">
|
|
||||||
<span class="fa-bug"></span> {{t 'app_debug_tab'}}
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<div class="btn-breadcrumb">
|
<div class="btn-breadcrumb">
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
<a href="#/apps">{{t 'applications'}}</a>
|
<a href="#/apps">{{t 'applications'}}</a>
|
||||||
<a href="#/apps/install">{{t 'install'}}</a>
|
<a href="#/apps/catalog">{{t 'catalog'}}</a>
|
||||||
<a href="#/apps/install/{{id}}">{{manifest.name}}</a>
|
<a href="#/apps/install/{{id}}">{{t 'install_name' manifest.name}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>{{t 'id'}}</dt>
|
<dt>{{t 'id'}}</dt>
|
||||||
<dd>{{id}}</dd>
|
<dd>{{manifest.id}}</dd>
|
||||||
<dt>{{t 'description'}}</dt>
|
<dt>{{t 'description'}}</dt>
|
||||||
<dd>{{description}}</dd>
|
<dd>{{description}}</dd>
|
||||||
{{#displayLicense}}
|
{{#displayLicense}}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions-group">
|
<div class="actions-group">
|
||||||
<a role="button" href="#/apps/install" class="btn btn-success slide">
|
<a role="button" href="#/apps/catalog" class="btn btn-success slide">
|
||||||
<span class="fa-plus"></span> {{t 'install'}}
|
<span class="fa-plus"></span> {{t 'install'}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<a href="#/apps/{{id}}" class="list-group-item slide" title="{{t 'infos'}}">
|
<a href="#/apps/{{id}}" class="list-group-item slide" title="{{t 'infos'}}">
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
<span class="fa-chevron-right pull-right"></span>
|
||||||
<h2 class="list-group-item-heading">
|
<h2 class="list-group-item-heading">
|
||||||
{{label}} <small>{{name}}</small>
|
{{settings.label}} <small>{{name}}</small>
|
||||||
</h2>
|
</h2>
|
||||||
<p class="list-group-item-text">{{description}}</p>
|
<p class="list-group-item-text">{{description}}</p>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -3,12 +3,6 @@
|
||||||
<a href="#/backup">{{t 'backup'}}</a>
|
<a href="#/backup">{{t 'backup'}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions-group">
|
|
||||||
<!--<a role="button" href="#/storages/create" class="btn btn-success slide">
|
|
||||||
<span class="fa-plus"></span> {{t 'storages_new'}}
|
|
||||||
</a>-->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
|
@ -18,10 +12,6 @@
|
||||||
<h2 class="list-group-item-heading">{{name}} <small>{{id}}</small></h2>
|
<h2 class="list-group-item-heading">{{name}} <small>{{id}}</small></h2>
|
||||||
<p class="list-group-item-text">{{uri}}</p>
|
<p class="list-group-item-text">{{uri}}</p>
|
||||||
</a>
|
</a>
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<span class="fa-exclamation-triangle"></span>
|
|
||||||
{{t 'storages_no'}}
|
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
|
|
|
@ -83,41 +83,11 @@
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<!--<div class="container">
|
|
||||||
<p>{{t 'backup_archive_download'}}</p>
|
|
||||||
<a role="button" class="btn btn-info slide" href="#/backup/{{storage.id}}/{{name}}/download">
|
|
||||||
<span class="fa-download"></span> {{t 'download'}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<hr>-->
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'backup_archive_delete'}}</p>
|
<p>{{t 'backup_archive_delete'}}</p>
|
||||||
<a href="#/backup/{{storage.id}}/{{name}}/delete" role="button" class="btn btn-danger slide">
|
<button class="btn btn-danger slide" data-action="delete" data-storage="{{storage.id}}" data-archive="{{name}}">
|
||||||
<span class="fa-trash-o"></span> {{t 'delete'}}
|
<span class="fa-trash-o"></span> {{t 'delete'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
|
||||||
{{#if other_storages}}
|
|
||||||
<hr>
|
|
||||||
<div class="container">
|
|
||||||
<p>{{t 'backup_archive_copy'}}</p>
|
|
||||||
<form action="#/backup/{{storage.id}}/{{name}}/copy" method="POST" class="form-horizontal">
|
|
||||||
<div class="form-group has-feedback">
|
|
||||||
<label for="label" class="col-sm-12">{{t 'url'}}</label>
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<select id="storage" name="storage" class="form-control" required>
|
|
||||||
{{#each storages}}
|
|
||||||
<option value="{{id}}">{{name}} ({{uri}})</option>
|
|
||||||
{{/each}}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<div class="text-center">
|
|
||||||
<input type="submit" role="button" class="btn btn-success slide" value="{{t 'copy'}}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
|
|
||||||
<div class="btn-breadcrumb">
|
|
||||||
<a href="#/"><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
|
||||||
<a href="#/backup">{{t 'backup'}}</a>
|
|
||||||
<a href="#/backup/{{storage.id}}/create">{{t 'storage_create'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<form action="#/storages" method="POST" class="form-horizontal">
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="type" class="col-sm-3 control-label">{{t 'backup_type'}}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select class="form-control" name="type">
|
|
||||||
<option>sftp</option>
|
|
||||||
<option>ftp</option>
|
|
||||||
<option>rsync</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="domain" class="col-sm-3 control-label">{{t 'domain'}}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text" id="domain" name="domain" class="form-control" placeholder="monserver.fr" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="username" class="col-sm-3 control-label">{{t 'user_username'}}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text" id="username" name="username" class="form-control" placeholder="johndoe" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="password" class="col-sm-3 control-label">{{t 'password'}}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="password" id="password" name="password" class="form-control" placeholder="•••••" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="path" class="col-sm-3 control-label">{{t 'path'}}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<input type="text" id="path" name="path" class="form-control" placeholder="~/" required>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-center">
|
|
||||||
<input type="submit" role="button" class="btn btn-success slide back" value="{{t 'save'}}">
|
|
||||||
</div>
|
|
||||||
</form>
|
|
67
src/views/diagnosis/diagnosis_show.ms
Normal file
67
src/views/diagnosis/diagnosis_show.ms
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<div class="btn-breadcrumb">
|
||||||
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
|
<a href="#/diagnosis">{{t 'diagnosis'}}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions-group">
|
||||||
|
<button class="btn btn-success" data-action="share">
|
||||||
|
<span class="fa-cloud-upload"></span> {{t 'logs_share_with_yunopaste'}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="separator"></div>
|
||||||
|
|
||||||
|
<div class="alert alert-info text-center">
|
||||||
|
{{#if reports}}
|
||||||
|
<p>{{t 'diagnosis_explanation'}}</p>
|
||||||
|
{{else}}
|
||||||
|
<p>{{t 'diagnosis_first_run'}}</p>
|
||||||
|
<br>
|
||||||
|
<button class="btn btn-info" data-action="run-full-diagnosis"><span class="fa-fw fa-stethoscope"></span> {{t 'run_first_diagnosis'}}</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-warning text-center">{{t 'diagnosis_experimental_disclaimer'}}</div>
|
||||||
|
|
||||||
|
{{#reports}}
|
||||||
|
<div class="panel panel-default panel-diagnosis" data-category="{{id}}">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h2 class="panel-title" style="display: inline-block; margin-right: 10px;">
|
||||||
|
<a data-toggle="collapse" href="#diagnosis-body-{{id}}">{{ description }}</a>
|
||||||
|
</h2>
|
||||||
|
{{#if noIssues}}{{#if items}}<span class="label label-success">{{t 'everything_good'}}</span>{{/if}}{{/if}}
|
||||||
|
{{#if errors}}<span class="label label-danger">{{t 'issues' errors }}</span>{{/if}}
|
||||||
|
{{#if warnings}}<span class="label label-warning">{{t 'warnings' warnings }}</span>{{/if}}
|
||||||
|
{{#if ignored}}<span class="label label-default">{{t 'ignored' ignored }}</span>{{/if}}
|
||||||
|
<button class="btn btn-sm {{#if items}}btn-info{{else}}btn-success{{/if}} pull-right" data-action="rerun-diagnosis" data-category="{{ id }}"><span class="fa-fw fa-refresh"></span> {{t 'rerun_diagnosis'}}</button>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body collapse {{#if errors}}in{{/if}}" id="diagnosis-body-{{id}}">
|
||||||
|
<ul class="list-group" style="margin-bottom: 0px">
|
||||||
|
<p>{{t 'last_ran' }} {{formatRelative time day="numeric" month="long" year="numeric" hour="numeric" minute="numeric" }}</p>
|
||||||
|
{{#items}}
|
||||||
|
<li class="list-group-item alert alert-{{status}} alert-{{status}}-yo clearfix diagnosis-item">
|
||||||
|
{{#if icon}}
|
||||||
|
<span class="fa-fw fa-{{icon}}"></span>
|
||||||
|
{{/if}}
|
||||||
|
{{{summary}}}
|
||||||
|
{{#if ignored}}
|
||||||
|
<button class="btn btn-sm btn-default pull-right" data-action="unignore" data-filter-args="{{ filter_args }}"><span class="fa-fw fa-bell"></span> {{t 'unignore'}}</button>
|
||||||
|
{{else}}
|
||||||
|
{{#if issue}}
|
||||||
|
<button class="btn btn-sm btn-warning pull-right" data-action="ignore" data-filter-args="{{ filter_args }}"><span class="fa-fw fa-bell-slash"></span> {{t 'ignore'}}</button>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if details}}
|
||||||
|
<a role="button" class="btn btn-sm btn-default pull-right" data-toggle="collapse" href="#details-{{../id}}-{{@index}}" aria-expanded="false" aria-controls="details-{{../id}}-{{@index}}"><span class="fa-fw fa-level-down"></span>{{t 'details'}}</a>
|
||||||
|
<div class="collapse diagnosis-details" id="details-{{../id}}-{{@index}}">
|
||||||
|
<ul>
|
||||||
|
{{#details}}<li>{{{.}}}</li>{{/details}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
</li>
|
||||||
|
{{/items}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/reports}}
|
|
@ -46,36 +46,36 @@
|
||||||
<p><span class="fa-fw fa-meh-o"></span>
|
<p><span class="fa-fw fa-meh-o"></span>
|
||||||
{{t 'domain_not_eligible_for_ACME'}}</p>
|
{{t 'domain_not_eligible_for_ACME'}}</p>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<a role="button" href="#/domains/{{name}}/cert-install-LE" class="btn btn-success {{#unless status.ACME_eligible}}disabled{{/unless}}">
|
<button class="btn btn-success {{#unless status.ACME_eligible}}disabled{{/unless}}" data-domain="{{name}}" data-action="install-LE" >
|
||||||
<span class="fa-star"></span> {{t 'install_letsencrypt_cert'}}
|
<span class="fa-star"></span> {{t 'install_letsencrypt_cert'}}
|
||||||
</a>
|
</button>
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if actions_enabled.manual_renew_letsencrpt}}
|
{{#if actions_enabled.manual_renew_letsencrpt}}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'manually_renew_letsencrypt_message'}}</p>
|
<p>{{t 'manually_renew_letsencrypt_message'}}</p>
|
||||||
<a role="button" href="#/domains/{{name}}/cert-renew-letsencrypt" class="btn btn-warning">
|
<button class="btn btn-warning" data-domain="{{name}}" data-action="renew-letsencrypt">
|
||||||
<span class="fa-refresh"></span> {{t 'manually_renew_letsencrypt'}}
|
<span class="fa-refresh"></span> {{t 'manually_renew_letsencrypt'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if actions_enabled.regen_selfsigned}}
|
{{#if actions_enabled.regen_selfsigned}}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'regenerate_selfsigned_cert_message'}}</p>
|
<p>{{t 'regenerate_selfsigned_cert_message'}}</p>
|
||||||
<a href="#/domains/{{name}}/cert-regen-selfsigned" role="button" class="btn btn-warning">
|
<button class="btn btn-warning" data-domain="{{name}}" data-action="regen-selfsigned">
|
||||||
<span class="fa-refresh"></span> {{t 'regenerate_selfsigned_cert'}}
|
<span class="fa-refresh"></span> {{t 'regenerate_selfsigned_cert'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if actions_enabled.replace_with_selfsigned}}
|
{{#if actions_enabled.replace_with_selfsigned}}
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'revert_to_selfsigned_cert_message'}}</p>
|
<p>{{t 'revert_to_selfsigned_cert_message'}}</p>
|
||||||
<a href="#/domains/{{name}}/cert-replace-with-selfsigned" role="button" class="btn btn-danger">
|
<button class="btn btn-danger" data-domain="{{name}}" data-action="replace-with-selfsigned">
|
||||||
<span class="fa-exclamation-triangle"></span> {{t 'revert_to_selfsigned_cert'}}
|
<span class="fa-exclamation-triangle"></span> {{t 'revert_to_selfsigned_cert'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,67 +12,46 @@
|
||||||
<span class="fa-fw fa-globe"></span> {{name}}
|
<span class="fa-fw fa-globe"></span> {{name}}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
|
||||||
{{#if main}}
|
|
||||||
<p class="alert alert-success">
|
|
||||||
<span class="fa-star" title="{{t 'default'}}"></span> {{t 'domain_default_longdesc'}}
|
|
||||||
</p>
|
|
||||||
{{/if}}
|
|
||||||
<p><a href="{{url}}" target="_blank">{{url}}</a></p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</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">
|
<div class="panel-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'domain_visit_url' url}}</p>
|
<p>{{t 'domain_visit_url' url}}</p>
|
||||||
<a role="button" href="{{url}}" class="btn btn-success" target="_blank">
|
<a role="button" href="{{url}}" class="btn btn-success" target="_blank">
|
||||||
{{t 'domain_visit'}} <span class="fa-fw fa-external-link"></span>
|
<span class="fa-fw fa-external-link"></span> {{t 'domain_visit'}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{{#unless main}}
|
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'domain_default_desc'}}</p>
|
<p>{{t 'domain_default_desc'}}</p>
|
||||||
<form method="POST" action="#/domains">
|
{{#if main}}
|
||||||
<input type="hidden" name="domain" value="{{name}}" required class="form-control">
|
<p class="alert alert-info">
|
||||||
<button type="submit" class="btn btn-primary slide back" value="{{t 'set_default'}}">
|
<span class="fa-star" title="{{t 'default'}}"></span> {{t 'domain_default_longdesc'}}
|
||||||
{{t 'set_default'}} <span class="fa-fw fa-star"></span>
|
</p>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn btn-primary" data-action="set_default" data-domain="{{name}}">
|
||||||
|
<span class="fa-fw fa-star"></span> {{t 'set_default'}}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/unless}}
|
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'domain_dns_longdesc'}}</p>
|
<p>{{t 'domain_dns_longdesc'}}</p>
|
||||||
<a role="button" href="#/domains/{{name}}/dns" class="btn btn-default slide">
|
<a role="button" href="#/domains/{{name}}/dns" class="btn btn-default slide">
|
||||||
{{t 'domain_dns_config'}} <span class="fa-fw fa-globe"></span>
|
<span class="fa-fw fa-globe"></span> {{t 'domain_dns_config'}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'certificate_manage'}}</p>
|
<p>{{t 'certificate_manage'}}</p>
|
||||||
{{#unless enable_cert_management}}
|
<a href="#/domains/{{name}}/cert-management" role="button" class="btn btn-default slide">
|
||||||
<p><span class="fa-fw fa-exclamation-circle"></span>
|
<span class="fa-fw fa-lock"></span> {{t 'ssl_certificate'}}
|
||||||
{{t 'certificate_old_letsencrypt_app_conflict'}}
|
|
||||||
</p>
|
|
||||||
{{/unless}}
|
|
||||||
<a href="#/domains/{{name}}/cert-management" role="button" class="btn btn-default slide {{#unless enable_cert_management}}disabled{{/unless}}">
|
|
||||||
{{t 'ssl_certificate'}} <span class="fa-fw fa-lock"></span>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>{{t 'domain_delete_longdesc' name}}</p>
|
<p>{{t 'domain_delete_longdesc' name}}</p>
|
||||||
<a href="#/domains/{{name}}/delete" role="button" class="btn btn-danger slide back">
|
<button class="btn btn-danger" data-action="delete" data-domain="{{name}}">
|
||||||
{{t 'delete'}} <span class="fa-fw fa-trash-o"></span>
|
<span class="fa-fw fa-trash-o"></span> {{t 'delete'}}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,10 +21,5 @@
|
||||||
</h2>
|
</h2>
|
||||||
<p class="list-group-item-text">https://{{url}}</p>
|
<p class="list-group-item-text">https://{{url}}</p>
|
||||||
</a>
|
</a>
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<span class="fa-exclamation-triangle"></span>
|
|
||||||
{{t 'domains_no'}}
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,6 +23,10 @@
|
||||||
<span class="pull-right fa-chevron-right"></span>
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
<h2 class="list-group-item-heading"><span class="fa-fw fa-wrench"></span> {{t 'tools'}}</h2>
|
<h2 class="list-group-item-heading"><span class="fa-fw fa-wrench"></span> {{t 'tools'}}</h2>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="#/diagnosis" class="list-group-item slide clearfix">
|
||||||
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
|
<h2 class="list-group-item-heading"><span class="fa-fw fa-stethoscope"></span> {{t 'diagnosis'}}</h2>
|
||||||
|
</a>
|
||||||
<a href="#/backup" class="list-group-item slide clearfix">
|
<a href="#/backup" 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"><span class="fa-fw fa-archive"></span> {{t 'backup'}}</h2>
|
<h2 class="list-group-item-heading"><span class="fa-fw fa-archive"></span> {{t 'backup'}}</h2>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="btn-breadcrumb">
|
<div class="btn-breadcrumb">
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
||||||
<a href="#/services">{{t 'services'}}</a>
|
<a href="#/services">{{t 'services'}}</a>
|
||||||
<a href="#/services/{{service.name}}">{{service.name}}</a>
|
<a href="#/services/{{service.name}}">{{name}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
@ -9,76 +9,70 @@
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-info-circle"></span> {{t 'infos'}}</h2>
|
<h2 class="panel-title" style="display: inline-block; margin-right: 10px;"><span class="fa-fw fa-info-circle"></span> {{name}}</h2>
|
||||||
|
{{#if (eq status "running")}}
|
||||||
|
<button class="btn btn-sm btn-danger pull-right" data-service="{{name}}" data-action="stop">
|
||||||
|
<span class="fa-fw fa-warning"></span> {{t 'stop'}}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-sm btn-warning pull-right" data-service="{{name}}" data-action="restart">
|
||||||
|
<span class="fa-fw fa-refresh"></span> {{t 'restart'}}
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn btn-sm btn-success pull-right" data-service="{{name}}" data-action="start">
|
||||||
|
<span class="fa-fw fa-play"></span> {{t 'start'}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{{#service}}
|
|
||||||
<dl class="dl-horizontal">
|
<dl class="dl-horizontal">
|
||||||
<dt>{{t 'name'}}</dt>
|
|
||||||
<dd>{{name}}</dd>
|
|
||||||
<dt>{{t 'description'}}</dt>
|
<dt>{{t 'description'}}</dt>
|
||||||
<dd>{{description}}</dd>
|
<dd>{{description}}</dd>
|
||||||
</dl>
|
|
||||||
{{/service}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<dt>{{t 'status'}}</dt>
|
||||||
|
<dd>
|
||||||
|
{{#if (eq status "running")}}
|
||||||
|
<span class="text-success">
|
||||||
|
<span class="fa-fw fa-check-circle"></span>
|
||||||
|
{{else}}
|
||||||
|
<span class="text-danger">
|
||||||
|
<span class="fa-fw fa-times"></span>
|
||||||
|
{{/if}}
|
||||||
|
{{t status}} </span> {{t 'since'}} {{formatRelative last_state_change day="numeric" month="long" year="numeric" hour="numeric" minute="numeric" }}
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>{{t 'service_start_on_boot'}}</dt>
|
||||||
|
{{#if (eq start_on_boot "enabled")}}
|
||||||
|
<dd class="text-success">
|
||||||
|
{{else}}
|
||||||
|
<dd class="text-danger">
|
||||||
|
{{/if}}
|
||||||
|
{{t start_on_boot}}
|
||||||
|
</dd>
|
||||||
|
|
||||||
|
<dt>{{t 'configuration'}}</dt>
|
||||||
|
{{#if (eq configuration "valid")}}
|
||||||
|
<dd class="text-success">
|
||||||
|
{{else if (eq configuration "broken")}}
|
||||||
|
<dd class="text-danger">
|
||||||
|
{{else}}
|
||||||
|
<dd>
|
||||||
|
{{/if}}
|
||||||
|
{{t configuration}}
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-wrench"></span> {{t 'status'}}</h2>
|
<h2 class="panel-title" style="display: inline-block; margin-right: 10px;"><span class="fa-fw fa-book"></span> {{t 'logs'}}</h2>
|
||||||
|
<button class="btn btn-sm btn-success pull-right" data-action="share"><span class="fa-cloud-upload"></span> {{t 'logs_share_with_yunopaste'}}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div id="logs" class="panel-body">
|
||||||
<dl class="dl-horizontal">
|
{{#logs}}
|
||||||
{{#service}}
|
<h2>{{filename}}</h2>
|
||||||
<div class="pull-left">
|
<pre class="service-log">{{filecontent}}</pre>
|
||||||
{{t 'service_start_on_boot'}}
|
{{/logs}}
|
||||||
<span class="text-{{#is_loaded}}success{{/is_loaded}}{{^is_loaded}}danger{{/is_loaded}}">
|
|
||||||
{{loaded}}
|
|
||||||
</span>
|
|
||||||
<br>
|
|
||||||
{{t 'service_status'}}
|
|
||||||
<span class="text-{{#is_running}}success{{/is_running}}{{^is_running}}danger{{/is_running}}">
|
|
||||||
{{active}}
|
|
||||||
</span>
|
|
||||||
<br>
|
|
||||||
{{t 'started_at'}}
|
|
||||||
{{#active_at}}
|
|
||||||
{{formatTime . day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}
|
|
||||||
{{/active_at}}
|
|
||||||
{{^active_at}}
|
|
||||||
{{t 'unknown'}}
|
|
||||||
{{/active_at}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pull-right">
|
|
||||||
{{#is_loaded}}
|
|
||||||
<a href="#/services/{{name}}/disable" role="button" class="btn btn-danger">
|
|
||||||
<span class="fa-square-o"></span> {{t 'disable'}}
|
|
||||||
</a>
|
|
||||||
{{/is_loaded}}
|
|
||||||
{{^is_loaded}}
|
|
||||||
<a href="#/services/{{name}}/enable" role="button" class="btn btn-success">
|
|
||||||
<span class="fa-check-square-o"></span> {{t 'enable'}}
|
|
||||||
</a>
|
|
||||||
{{/is_loaded}}
|
|
||||||
|
|
||||||
{{#is_running}}
|
|
||||||
<a href="#/services/{{name}}/stop" role="button" class="btn btn-danger">
|
|
||||||
<span class="fa-stop"></span> {{t 'stop'}}
|
|
||||||
</a>
|
|
||||||
{{/is_running}}
|
|
||||||
{{^is_running}}
|
|
||||||
<a href="#/services/{{name}}/start" role="button" class="btn btn-success">
|
|
||||||
<span class="fa-play"></span> {{t 'start'}}
|
|
||||||
</a>
|
|
||||||
{{/is_running}}
|
|
||||||
<a href="#/services/{{name}}/log" role="button" class="btn btn-default slide">
|
|
||||||
<span class="fa-book"></span> {{t 'log'}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{/service}}
|
|
||||||
</dl>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,18 +11,16 @@
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
<span class="fa-chevron-right pull-right"></span>
|
||||||
<h2 class="list-group-item-heading">{{name}} <small>{{description}}</small></h2>
|
<h2 class="list-group-item-heading">{{name}} <small>{{description}}</small></h2>
|
||||||
<div class="list-group-item-text">
|
<div class="list-group-item-text">
|
||||||
{{t 'service_status'}}
|
{{#if (eq status "running")}}
|
||||||
<span class="text-{{#is_running}}success{{/is_running}}{{^is_running}}danger{{/is_running}}">
|
<span class="text-success">
|
||||||
{{active}}
|
<span class="fa-fw fa-check-circle"></span>
|
||||||
|
{{else}}
|
||||||
|
<span class="text-danger">
|
||||||
|
<span class="fa-fw fa-times"></span>
|
||||||
|
{{/if}}
|
||||||
|
{{t status}}
|
||||||
</span>
|
</span>
|
||||||
<br>
|
{{t 'since'}} {{formatRelative last_state_change day="numeric" month="long" year="numeric" hour="numeric" minute="numeric" }}
|
||||||
{{t 'started_at'}}
|
|
||||||
{{#active_at}}
|
|
||||||
{{formatTime . day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}
|
|
||||||
{{/active_at}}
|
|
||||||
{{^active_at}}
|
|
||||||
{{t 'unknown'}}
|
|
||||||
{{/active_at}}
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
{{/services}}
|
{{/services}}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
<div class="btn-breadcrumb">
|
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
|
||||||
<a href="#/services">{{t 'services'}}</a>
|
|
||||||
<a href="#/services/{{name}}">{{name}}</a>
|
|
||||||
<a href="#/services/{{name}}/log">{{t 'log'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
{{#logs}}
|
|
||||||
<h2>{{filename}}</h2>
|
|
||||||
<pre id="log" class="service-log">{{filecontent}}</pre>
|
|
||||||
<button data-paste-content="#log"><i class="fa-cloud-upload"></i> {{t 'upload'}}</button>
|
|
||||||
{{/logs}}
|
|
||||||
</div>
|
|
|
@ -1,49 +0,0 @@
|
||||||
<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/appslists">{{t 'appslists'}}</a>
|
|
||||||
<a href="#/tools/appslists/{{name}}">{{appslist.name}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-info-circle"></span> {{t 'infos'}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>{{t 'name'}}</dt>
|
|
||||||
<dd>{{appslist.name}}</dd>
|
|
||||||
<dt>{{t 'url'}}</dt>
|
|
||||||
<dd>{{appslist.url}}</dd>
|
|
||||||
<dt>{{t 'appslists_last_update'}}</dt>
|
|
||||||
<dd>{{formatTime appslist.lastUpdate day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</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">
|
|
||||||
<div class="container">
|
|
||||||
<p>{{t 'appslists_info_refresh_desc'}}</p>
|
|
||||||
<a href="#/tools/appslists/{{appslist.name}}/refresh" role="button" class="btn btn-info slide">
|
|
||||||
<span class="fa-refresh"></span> {{t 'refresh_app_list'}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{#appslist.removable}}
|
|
||||||
<hr>
|
|
||||||
<div class="container">
|
|
||||||
<p>{{t 'appslists_info_remove_desc'}}</p>
|
|
||||||
<a role="button" href="#/tools/appslists/{{appslist.name}}/remove" class="btn btn-danger slide back">
|
|
||||||
<span class="fa-trash-o"></span> {{t 'remove'}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{{/appslist.removable}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,57 +0,0 @@
|
||||||
<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/appslists">{{t 'appslists'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-list"></span> {{t 'appslists'}}</h2>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="list-group">
|
|
||||||
{{#appslists}}
|
|
||||||
<a href="#/tools/appslists/{{name}}" class="list-group-item">
|
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
|
||||||
<h2 class="list-group-item-heading">
|
|
||||||
{{name}}
|
|
||||||
</h2>
|
|
||||||
</a>
|
|
||||||
{{/appslists}}
|
|
||||||
{{^appslists}}
|
|
||||||
<p class="list-group-item text-warning">
|
|
||||||
<span class="fa-exclamation-triangle"></span>
|
|
||||||
{{t 'appslists_no_lists'}}
|
|
||||||
</p>
|
|
||||||
{{/appslists}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-plus"></span> {{t 'appslists_custom'}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<form action="#/tools/appslists" method="POST" class="form-horizontal">
|
|
||||||
<div class="form-group has-feedback">
|
|
||||||
<label for="appslist_name" class="col-md-2 col-sm-12 control-label">{{t 'name'}}</label>
|
|
||||||
<div class="col-md-10 col-sm-12">
|
|
||||||
<input type="text" id="appslist_name" name="appslist_name" class="form-control" value="" required />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group has-feedback">
|
|
||||||
<label for="appslist_url" class="col-md-2 col-sm-12 control-label">{{t 'url'}}</label>
|
|
||||||
<div class="col-md-10 col-sm-12">
|
|
||||||
<input type="url" id="appslist_url" name="appslist_url" class="form-control" value="" placeholder="https://some.domain.tld/somelist.json" required />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="col-md-10 col-md-push-2 col-sm-12">
|
|
||||||
<input type="submit" class="btn btn-success slide" value="{{t 'add'}}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<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/ca">{{t 'tools_download_ca'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-body">
|
|
||||||
<p>{{t 'tools_download_ca_desc'}}</p>
|
|
||||||
<a role="button" href="ca.crt" class="btn btn-success">CA.crt</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,25 +0,0 @@
|
||||||
<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/diagnosis">{{t 'diagnosis'}}</a>
|
|
||||||
{{#private}}
|
|
||||||
<a href="#/tools/diagnosis/private">{{t 'diagnosis_with_private'}}</a>
|
|
||||||
{{/private}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-stethoscope"></span> {{t 'diagnosis'}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<pre id="diagnosis">{{ diagnosis }}</pre>
|
|
||||||
{{#if private}}
|
|
||||||
<a class="btn btn-primary" role="button" href="#/tools/diagnosis"><i class="fa-eye-slash"></i> {{t 'diagnosis_hide_private'}}</a>
|
|
||||||
{{else}}
|
|
||||||
<a class="btn btn-primary" role="button" href="#/tools/diagnosis/private"><i class="fa-eye"></i> {{t 'diagnosis_view_private'}}</a>
|
|
||||||
{{/if}}
|
|
||||||
<button data-paste-content="#diagnosis"><i class="fa-cloud-upload"></i> {{t 'upload'}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -29,20 +29,20 @@
|
||||||
<td>
|
<td>
|
||||||
{{#if this.ipv4}}
|
{{#if this.ipv4}}
|
||||||
<span class="fa-check"></span>
|
<span class="fa-check"></span>
|
||||||
<a class="btn btn-xs btn-danger" href="#/tools/firewall/port/{{@key}}/tcp/ipv4/close">{{t 'close'}}</a>
|
<button class="btn btn-xs btn-danger" data-action="close" data-port="{{@key}}" data-protocol="tcp" data-connection="ipv4">{{t 'close'}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span></span>
|
<span></span>
|
||||||
<span class="fa-times"></span>
|
<span class="fa-times"></span>
|
||||||
<a class="btn btn-xs btn-success" href="#/tools/firewall/port/{{@key}}/tcp/ipv4/open">{{t 'open'}}</a>
|
<button class="btn btn-xs btn-success" data-action="open" data-port="{{@key}}" data-protocol="tcp" data-connection="ipv4">{{t 'open'}}</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{#if this.ipv6}}
|
{{#if this.ipv6}}
|
||||||
<span class="fa-check"></span>
|
<span class="fa-check"></span>
|
||||||
<a class="btn btn-xs btn-danger" href="#/tools/firewall/port/{{@key}}/tcp/ipv6/close">{{t 'close'}}</a>
|
<button class="btn btn-xs btn-danger" data-action="close" data-port="{{@key}}" data-protocol="tcp" data-connection="ipv6">{{t 'close'}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="fa-times"></span>
|
<span class="fa-times"></span>
|
||||||
<a class="btn btn-xs btn-success" href="#/tools/firewall/port/{{@key}}/tcp/ipv6/open">{{t 'open'}}</a>
|
<button class="btn btn-xs btn-success" data-action="open" data-port="{{@key}}" data-protocol="tcp" data-connection="ipv6">{{t 'open'}}</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -75,20 +75,20 @@
|
||||||
<td>
|
<td>
|
||||||
{{#if this.ipv4}}
|
{{#if this.ipv4}}
|
||||||
<span class="fa-check"></span>
|
<span class="fa-check"></span>
|
||||||
<a class="btn btn-xs btn-danger" href="#/tools/firewall/port/{{@key}}/udp/ipv4/close">{{t 'close'}}</a>
|
<button class="btn btn-xs btn-danger" data-action="close" data-port="{{@key}}" data-protocol="udp" data-connection="ipv4">{{t 'close'}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span></span>
|
<span></span>
|
||||||
<span class="fa-times"></span>
|
<span class="fa-times"></span>
|
||||||
<a class="btn btn-xs btn-success" href="#/tools/firewall/port/{{@key}}/udp/ipv4/open">{{t 'open'}}</a>
|
<button class="btn btn-xs btn-success" data-action="open" data-port="{{@key}}" data-protocol="udp" data-connection="ipv4">{{t 'open'}}</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{#if this.ipv6}}
|
{{#if this.ipv6}}
|
||||||
<span class="fa-check"></span>
|
<span class="fa-check"></span>
|
||||||
<a class="btn btn-xs btn-danger" href="#/tools/firewall/port/{{@key}}/udp/ipv6/close">{{t 'close'}}</a>
|
<button class="btn btn-xs btn-danger" data-action="close" data-port="{{@key}}" data-protocol="udp" data-connection="ipv6">{{t 'close'}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="fa-times"></span>
|
<span class="fa-times"></span>
|
||||||
<a class="btn btn-xs btn-success" href="#/tools/firewall/port/{{@key}}/udp/ipv6/open">{{t 'open'}}</a>
|
<button class="btn btn-xs btn-success" data-action="open" data-port="{{@key}}" data-protocol="udp" data-connection="ipv6">{{t 'open'}}</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -168,10 +168,10 @@
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{{#if upnp}}
|
{{#if upnp}}
|
||||||
<p class="text-success">{{t 'upnp_enabled'}}</p>
|
<p class="text-success">{{t 'upnp_enabled'}}</p>
|
||||||
<a role="button" href="#/tools/firewall/upnp/disable" class="btn btn-danger">{{t 'disable'}}</a>
|
<button class="btn btn-danger" data-upnp="disable">{{t 'disable'}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<p class="text-danger">{{t 'upnp_disabled'}}</p>
|
<p class="text-danger">{{t 'upnp_disabled'}}</p>
|
||||||
<a role="button" href="#/tools/firewall/upnp/enable" class="btn btn-success">{{t 'enable'}}</a>
|
<button class="btn btn-success" data-upnp="enable">{{t 'enable'}}</button>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
<a href="#/tools/diagnosis" class="list-group-item slide clearfix">
|
|
||||||
<span class="pull-right fa-chevron-right"></span>
|
|
||||||
<h2 class="list-group-item-heading">{{t 'diagnosis'}}</h2>
|
|
||||||
</a>
|
|
||||||
<a href="#/tools/logs" class="list-group-item slide clearfix">
|
<a href="#/tools/logs" 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 'logs'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'logs'}}</h2>
|
||||||
|
@ -18,41 +14,17 @@
|
||||||
<span class="pull-right fa-chevron-right"></span>
|
<span class="pull-right fa-chevron-right"></span>
|
||||||
<h2 class="list-group-item-heading">{{t 'migrations'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'migrations'}}</h2>
|
||||||
</a>
|
</a>
|
||||||
<a href="#/tools/reboot" class="list-group-item slide clearfix">
|
<a href="#/tools/firewall" 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 'tools_shutdown_reboot'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'firewall'}}</h2>
|
||||||
</a>
|
</a>
|
||||||
<a href="#/tools/adminpw" class="list-group-item slide">
|
<a href="#/tools/adminpw" class="list-group-item slide">
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
<span class="fa-chevron-right pull-right"></span>
|
||||||
<h2 class="list-group-item-heading">{{t 'tools_adminpw'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'tools_adminpw'}}</h2>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
<a href="#/tools/reboot" class="list-group-item slide clearfix">
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
<h2 style="font-weight:600; padding-left:0.5em;">{{t 'advanced'}}</h2>
|
|
||||||
|
|
||||||
<div class="list-group">
|
|
||||||
<a href="#/tools/monitor" 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 'monitoring'}}</h2>
|
<h2 class="list-group-item-heading">{{t 'tools_shutdown_reboot'}}</h2>
|
||||||
</a>
|
|
||||||
<a href="#/tools/firewall" class="list-group-item slide clearfix">
|
|
||||||
<span class="pull-right fa-chevron-right"></span>
|
|
||||||
<h2 class="list-group-item-heading">{{t 'firewall'}}</h2>
|
|
||||||
</a>
|
|
||||||
<a href="#/tools/security-feed" class="list-group-item slide">
|
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
|
||||||
<h2 class="list-group-item-heading">{{t 'tools_security_feed'}}</h2>
|
|
||||||
</a>
|
|
||||||
<a href="#/tools/appslists" class="list-group-item slide clearfix">
|
|
||||||
<span class="pull-right fa-chevron-right"></span>
|
|
||||||
<h2 class="list-group-item-heading">{{t 'appslists'}}</h2>
|
|
||||||
</a>
|
|
||||||
<a href="#/tools/ca" class="list-group-item slide">
|
|
||||||
<span class="fa-chevron-right pull-right"></span>
|
|
||||||
<h2 class="list-group-item-heading">{{t 'tools_download_ca'}}</h2>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -9,30 +9,31 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="actions-group">
|
|
||||||
<a href="javascript:void(null);" onclick="c.api('/logs/display?path={{#if log.name}}{{ log.name }}{{else}}{{ log.log_path }}{{/if}}&share', function(data) { $('div.loader').remove(); window.open(data.url, '_blank'); });" class="btn btn-success">
|
|
||||||
<span class="fa-cloud-upload"></span> {{t 'logs_share_with_yunopaste'}}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
<div class="separator"></div>
|
||||||
|
|
||||||
{{#intl locales=locale}}
|
{{#intl locales=locale}}
|
||||||
{{#if log.metadata}}
|
{{#if log.metadata}}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<!-- PLEASE DON'T INDENT THIS CODE, IT IS PASTED ON YUNOPASTE -->
|
<h2 class="panel-title" id="description" style="display: inline-block; margin-right: 10px;"><span class="fa-fw fa-info-circle"></span> {{ log.description }}</h2>
|
||||||
<h2 class="panel-title" id="description"><span class="fa-fw fa-info-circle"></span> {{ log.description }}</h2>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<dl class="dl-horizontal" id="metadata">
|
<dl class="dl-horizontal" id="metadata">
|
||||||
<dt>{{t 'logs_path'}}</dt> <dd>{{ log.log_path }}</dd>
|
<dt>{{t 'logs_path'}}</dt> <dd>{{ log.log_path }}</dd>
|
||||||
{{#if log.metadata.started_at}}<dt>{{t 'logs_started_at'}}</dt> <dd>{{formatTime log.metadata.started_at day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
{{#if log.metadata.started_at}}<dt>{{t 'logs_started_at'}}</dt> <dd>{{formatTime log.metadata.started_at day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>
|
||||||
{{/if}}{{#if log.metadata.ended_at}}<dt>{{t 'logs_ended_at'}}</dt> <dd>{{formatTime log.metadata.ended_at day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>{{/if}}
|
{{/if}}{{#if log.metadata.ended_at}}<dt>{{t 'logs_ended_at'}}</dt> <dd>{{formatTime log.metadata.ended_at day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}</dd>{{/if}}
|
||||||
{{#if log.metadata.error}}<dt>{{t 'logs_error'}}</dt> <dd>{{t 'logs_end_with_error'}} {{log.metadata.error}}</dd>{{/if}}
|
{{#if log.metadata.error}}<dt>{{t 'logs_error'}}</dt> <dd>{{log.metadata.error}}</dd>{{/if}}
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{#if log.metadata.error}}
|
||||||
|
<div class="alert alert-danger text-center">
|
||||||
|
<p>{{t 'operation_failed_explanation'}}</p>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<!--
|
||||||
{{#if log.metadata.env}}
|
{{#if log.metadata.env}}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading" role="tab" id="heading-context">
|
<div class="panel-heading" role="tab" id="heading-context">
|
||||||
|
@ -52,17 +53,27 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
-->
|
||||||
|
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-file-text"></span> {{#if log.metadata}}{{t 'logs'}}{{else}}{{log.log_path}}{{/if}}</h2>
|
<h2 class="panel-title" style="display: inline-block; margin-right: 10px;">
|
||||||
|
<span class="fa-fw fa-file-text"></span> {{#if log.metadata}}{{t 'logs'}}{{else}}{{log.log_path}}{{/if}}</h2>
|
||||||
|
<button class="btn btn-sm btn-success pull-right" data-action="share" data-log-id="{{#if log.name}}{{ log.name }}{{else}}{{ log.log_path }}{{/if}}">
|
||||||
|
<span class="fa-cloud-upload"></span> {{t 'logs_share_with_yunopaste'}}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body overflow-auto">
|
<div class="panel-body overflow-auto">
|
||||||
{{#if next_number}}<a href="#/tools/logs/{{#if log.name}}{{ log.name }}{{else}}{{ log.log_path }}{{/if}}?number={{ next_number }}" class="btn btn-default full-width"><span class="fa-fw fa-plus"></span> {{t 'logs_more'}}</a>{{/if}}
|
{{#if next_number}}<a href="#/tools/logs/{{#if log.name}}{{ log.name }}{{else}}{{ log.log_path }}{{/if}}?number={{ next_number }}" class="btn btn-default full-width"><span class="fa-fw fa-plus"></span> {{t 'logs_more'}}</a>{{/if}}
|
||||||
<!-- no indent because pre is sensible to whitespaces -->
|
<!-- no indent because pre is sensible to whitespaces -->
|
||||||
<pre id="log" class="full-width">{{#log.logs}}{{.}}
|
<pre id="log" class="full-width">{{#log.logs}}{{.}}
|
||||||
{{/log.logs}}</pre>
|
{{/log.logs}}</pre>
|
||||||
|
<center>
|
||||||
|
<button class="btn btn-success" data-action="share" data-log-id="{{#if log.name}}{{ log.name }}{{else}}{{ log.log_path }}{{/if}}">
|
||||||
|
<span class="fa-cloud-upload"></span> {{t 'logs_share_with_yunopaste'}}
|
||||||
|
</button>
|
||||||
|
</center>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/intl}}
|
{{/intl}}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
<div id="collapse-{{key}}" class="panel-collapse{{#if @first}}{{else}} collapse{{/if}}" role="tabpanel" aria-labelledby="heading-{{key}}">
|
<div id="collapse-{{key}}" class="panel-collapse{{#if @first}}{{else}} collapse{{/if}}" role="tabpanel" aria-labelledby="heading-{{key}}">
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{{#value}}
|
{{#value}}
|
||||||
<a href="#/tools/logs/{{ name }}" class="list-group-item" title='{{formatTime started_at day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}'><small style="margin-right:20px;" >{{formatRelative started_at}}</small>
|
<a href="#/tools/logs/{{ name }}" class="list-group-item slide" title='{{formatTime started_at day="numeric" month="long" year="numeric" hour="numeric" minute="numeric"}}'><small style="margin-right:20px;" >{{formatRelative started_at}}</small>
|
||||||
<span class="fa-fw fa-{{success_icon}}"></span> {{ description }}</a>
|
<span class="fa-fw fa-{{success_icon}}"></span> {{ description }}</a>
|
||||||
{{/value}}
|
{{/value}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-cogs"></span> {{t 'migrations_pending'}}
|
<h2 class="panel-title"><span class="fa-fw fa-cogs"></span> {{t 'migrations_pending'}}
|
||||||
{{#if pending_migrations}}
|
{{#if pending_migrations}}
|
||||||
<div class="btn-toolbar pull-right">
|
<div class="btn-toolbar pull-right">
|
||||||
<a href="#/tools/migrations/run" class="btn btn-sm btn-success"><span class="fa-fw fa-play"></span> {{t 'run'}}</a>
|
<button class="btn btn-sm btn-success" data-action="run"><span class="fa-fw fa-play"></span> {{t 'run'}}</button>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
<h3 class="list-group-item-heading">
|
<h3 class="list-group-item-heading">
|
||||||
{{ number }}. {{ description }}
|
{{ number }}. {{ description }}
|
||||||
<div class="btn-toolbar pull-right">
|
<div class="btn-toolbar pull-right">
|
||||||
<a href="#/tools/migrations/skip/{{ id }}" class="btn btn-xs btn-warning" style="color:white;"><span class="fa-fw fa-close"></span> {{t 'skip'}}</a>
|
<button class="btn btn-xs btn-warning" style="color:white;" data-action="skip" data-migration="{{id}}"><span class="fa-fw fa-close"></span> {{t 'skip'}}</button>
|
||||||
</div>
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
{{#if disclaimer }}
|
{{#if disclaimer }}
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
<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/monitor">{{t 'monitoring'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
{{#if status}}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-info-circle"></span> {{t 'infos'}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>{{t 'hostname'}}</dt>
|
|
||||||
<dd>{{system.infos.hostname}}</dd>
|
|
||||||
<dt>{{t 'os'}}</dt>
|
|
||||||
<dd>{{ucwords system.infos.linux_distro}} {{system.infos.platform}} ({{system.infos.os_name}} {{system.infos.os_version}})</dd>
|
|
||||||
<dt>{{t 'uptime'}}</dt>
|
|
||||||
<dd>{{system.uptime}}</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title"><span class="fa-fw fa-cogs"></span> {{t 'versions'}}</h2>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
{{#each versions}}
|
|
||||||
<dt>{{@key}}</dt>
|
|
||||||
<dd>{{version}} ({{repo}})</dd>
|
|
||||||
{{/each}}
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-group" id="accordion">
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">
|
|
||||||
<span class="fa-fw fa-check-square-o"></span>
|
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#check">{{t 'check'}}</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div id="check" class="panel-collapse collapse">
|
|
||||||
<div class="panel-body">
|
|
||||||
<dl class="dl-horizontal">
|
|
||||||
<dt>{{t 'check_stmp'}}</dt>
|
|
||||||
<dd>{{network.check.smtp_check}}</dd>
|
|
||||||
<dt>{{t 'check_mx'}}</dt>
|
|
||||||
<dd>
|
|
||||||
{{#if network.check.mx_check.mx0}}
|
|
||||||
<ul>
|
|
||||||
{{#each network.check.mx_check}}
|
|
||||||
<li>{{this}}</li>
|
|
||||||
{{/each}}
|
|
||||||
</ul>
|
|
||||||
{{else}}
|
|
||||||
{{network.check.mx_check}}
|
|
||||||
{{/if}}
|
|
||||||
</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">
|
|
||||||
<span class="fa-fw fa-cog"></span>
|
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#system">{{t 'system'}}</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div id="system" class="panel-collapse collapse">
|
|
||||||
<div class="panel-body row">
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h3>{{t 'memory'}}</h3>
|
|
||||||
<h4>{{t 'ram'}}</h4>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'used'}}</td>
|
|
||||||
<td>{{humanSize system.memory.ram.used}} ({{system.memory.ram.percent}} %)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'free'}}</td>
|
|
||||||
<td>{{humanSize system.memory.ram.free}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="active">
|
|
||||||
<td>{{t 'total'}}</td>
|
|
||||||
<td>{{humanSize system.memory.ram.total}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h4>{{t 'swap'}}</h4>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'used'}}</td>
|
|
||||||
<td>{{humanSize system.memory.swap.used}} ({{system.memory.swap.percent}} %)</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'free'}}</td>
|
|
||||||
<td>{{humanSize system.memory.swap.free}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="active">
|
|
||||||
<td>{{t 'total'}}</td>
|
|
||||||
<td>{{humanSize system.memory.swap.total}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h3>{{t 'cpu_load'}}</h3>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'count_min' "1"}}</td>
|
|
||||||
<td>{{system.cpu.load.min1}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'count_min' "5"}}</td>
|
|
||||||
<td>{{system.cpu.load.min5}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'count_min' "15"}}</td>
|
|
||||||
<td>{{system.cpu.load.min15}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h3>{{t 'process'}}</h3>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'running'}}</td>
|
|
||||||
<td>{{system.process.running}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'sleeping'}}</td>
|
|
||||||
<td>{{system.process.sleeping}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="active">
|
|
||||||
<td>{{t 'total'}}</td>
|
|
||||||
<td>{{system.process.total}}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">
|
|
||||||
<span class="fa-fw fa-cloud"></span>
|
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#network">{{t 'network'}}</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div id="network" class="panel-collapse collapse">
|
|
||||||
<div class="panel-body">
|
|
||||||
<b>{{t 'public_ip'}}</b>{{network.infos.public_ip}}
|
|
||||||
<br>
|
|
||||||
<b>{{t 'gateway'}}</b>{{network.infos.gateway}}
|
|
||||||
|
|
||||||
<h3>{{t 'local_ip'}}</h3>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>{{t 'interface'}}</th>
|
|
||||||
<th>{{t 'ipv4'}}</th>
|
|
||||||
<th>{{t 'ipv6'}}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{#each network.infos.local_ip}}
|
|
||||||
<tr>
|
|
||||||
<td>{{@key}}</td>
|
|
||||||
<td>{{ ipv4 }}</td>
|
|
||||||
<td>{{ ipv6 }}</td>
|
|
||||||
</tr>
|
|
||||||
{{/each}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3>{{t 'usage'}}</h3>
|
|
||||||
{{#each network.usage}}
|
|
||||||
<div class="clearfix">
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<h4>
|
|
||||||
{{@key}}
|
|
||||||
<small>{{t 'time_since_update'}}{{humanTime time_since_update}}</small>
|
|
||||||
</h4>
|
|
||||||
</th>
|
|
||||||
<th>{{t 'bit_rate'}}</th>
|
|
||||||
<th>{{t 'cumulative_usage'}}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'transmission'}}</td>
|
|
||||||
<td>{{bitRate tx time_since_update}}</td>
|
|
||||||
<td>{{humanSize cumulative_tx}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'reception'}}</td>
|
|
||||||
<td>{{bitRate rx time_since_update}}</td>
|
|
||||||
<td>{{humanSize cumulative_rx}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h2 class="panel-title">
|
|
||||||
<span class="fa-fw fa-hdd-o"></span>
|
|
||||||
<a data-toggle="collapse" data-parent="#accordion" href="#disk">{{t 'disk'}}</a>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<div id="disk" class="panel-collapse collapse">
|
|
||||||
<div class="panel-body">
|
|
||||||
{{#each disk}}
|
|
||||||
<div class="clearfix">
|
|
||||||
<h3>{{@key}}</h3>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>{{t 'filesystem'}}</h4>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'fs_type'}}</td><td>{{ filesystem.fs_type }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'mount_point'}}</td><td>{{ filesystem.mnt_point }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'size'}}</td><td>{{humanSize filesystem.size }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'used'}}</td><td>{{humanSize filesystem.used }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="active">
|
|
||||||
<td>{{t 'available'}}</td><td>{{humanSize filesystem.avail }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>{{t 'io'}} <small>{{t 'time_since_update'}}{{humanTime io.time_since_update }}</small></h4>
|
|
||||||
<table class="table table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'read'}}</td><td>{{humanSize io.read_bytes }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{t 'write'}}</td><td>{{humanSize io.write_bytes }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- .panel-group -->
|
|
||||||
|
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-warning">
|
|
||||||
<span class="fa-exclamation-triangle"></span>
|
|
||||||
{{t 'monitoring_disabled'}}
|
|
||||||
<br>
|
|
||||||
{{t 'monitoring_check_glances'}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{{/if}}
|
|
|
@ -15,14 +15,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<p>
|
<p>
|
||||||
<a role="button" href="#/tools/reboot/reboot" class="btn btn-danger">
|
<button class="btn btn-danger" data-action="reboot">
|
||||||
<i class="fa-refresh"></i> {{t 'tools_reboot_btn'}}
|
<i class="fa-refresh"></i> {{t 'tools_reboot_btn'}}
|
||||||
</a>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a role="button" href="#/tools/reboot/shutdown" class="btn btn-danger">
|
<button class="btn btn-danger" data-action="shutdown">
|
||||||
<i class="fa-power-off"></i> {{t 'tools_shutdown_btn'}}
|
<i class="fa-power-off"></i> {{t 'tools_shutdown_btn'}}
|
||||||
</a>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<div class="alert alert-warning"><i class="fa-refresh"></i> {{t 'tools_rebooting'}}</div>
|
|
|
@ -1,34 +0,0 @@
|
||||||
<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/ca">{{t 'tools_security_feed'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
{{#if items}}
|
|
||||||
<div class="list-group">
|
|
||||||
{{#items}}
|
|
||||||
<div class="list-group-item">
|
|
||||||
<!-- <a href="{{url}}" class="fa-chevron-right pull-right"></a> -->
|
|
||||||
<h2 class="list-group-item-heading"><a href="{{url}}">{{title}}</a></h2>
|
|
||||||
<div class="list-group-item-text">
|
|
||||||
<p class="pub-date"><em>{{date}}</em></p>
|
|
||||||
{{{desc}}}
|
|
||||||
<p class="text-right">
|
|
||||||
<a href="{{url}}" role="button" class="btn btn-default">{{t 'read_more'}}</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{{/items}}
|
|
||||||
</div>
|
|
||||||
{{else}}
|
|
||||||
<div class="alert alert-success">
|
|
||||||
<span class="fa-thumbs-o-up"></span> {{t 'tools_security_feed_no_items'}}
|
|
||||||
</div>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<a role="button" href="{{url.web}}" class="btn btn-success" target="_blank"><span class="fa-list"></span> {{t 'tools_security_feed_view_items'}}</a>
|
|
||||||
<a role="button" href="{{url.rss}}" class="btn btn-warning" target="_blank"><span class="fa-rss"></span> {{t 'tools_security_feed_subscribe_rss'}}</a>
|
|
||||||
</div>
|
|
|
@ -1 +0,0 @@
|
||||||
<div class="alert alert-warning"><i class="fa-power-off"></i> {{t 'tools_shuttingdown'}}</div>
|
|
|
@ -20,7 +20,7 @@
|
||||||
{{/system}}
|
{{/system}}
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
<a href="#/upgrade/system" role="button" class="btn btn-success">{{t 'system_upgrade_all_packages_btn'}}</a>
|
<button class="btn btn-success" data-upgrade="system">{{t 'system_upgrade_all_packages_btn'}}</button>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
@ -37,14 +37,14 @@
|
||||||
<div class="list-group">
|
<div class="list-group">
|
||||||
{{#apps}}
|
{{#apps}}
|
||||||
<div class="list-group-item clearfix">
|
<div class="list-group-item clearfix">
|
||||||
<a href="#/upgrade/apps/{{id}}" role="button" class="btn btn-success pull-right">{{t 'system_upgrade_btn'}}</a>
|
<button class="btn btn-success pull-right" data-upgrade="{{id}}">{{t 'system_upgrade_btn'}}</button>
|
||||||
<h3 class="list-group-item-heading">{{label}} <small>{{id}}</small></h3>
|
<h3 class="list-group-item-heading">{{label}} <small>{{id}}</small></h3>
|
||||||
<p class="list-group-item-text">{{t 'from_to' current_version new_version}}</p>
|
<span class="list-group-item-text">{{t 'from_to' current_version new_version}}</span>
|
||||||
</div>
|
</div>
|
||||||
{{/apps}}
|
{{/apps}}
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
<a role="button" href="#/upgrade/apps" class="btn btn-success">{{t 'system_upgrade_all_applications_btn'}}</a>
|
<button class="btn btn-success" data-upgrade="apps">{{t 'system_upgrade_all_applications_btn'}}</button>
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
|
@ -1,18 +0,0 @@
|
||||||
<div class="btn-breadcrumb">
|
|
||||||
<a href="#/" ><i class="fa-home"></i><span class="sr-only">{{t 'home'}}</span></a>
|
|
||||||
<a href="#/update">{{t 'system_update'}}</a>
|
|
||||||
<a href="#/upgrade">{{t 'system_upgrade'}}</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="separator"></div>
|
|
||||||
|
|
||||||
{{#if logs}}
|
|
||||||
<pre id="upgrade-log" class="upgrade-log log">
|
|
||||||
{{#logs}}
|
|
||||||
{{.}}
|
|
||||||
{{/logs}}
|
|
||||||
</pre>
|
|
||||||
<button data-paste-content="#upgrade-log"><i class="fa-cloud-upload"></i> {{t 'upload'}}</button>
|
|
||||||
{{else}}
|
|
||||||
{{t 'no_log'}}
|
|
||||||
{{/if}}
|
|
|
@ -3,7 +3,7 @@
|
||||||
<a href="#/users" class="visible-xs">…</a>
|
<a href="#/users" class="visible-xs">…</a>
|
||||||
<a href="#/users" class="hidden-xs">{{t 'users'}}</a>
|
<a href="#/users" class="hidden-xs">{{t 'users'}}</a>
|
||||||
<a href="#/groups" class="visible-xs">…</a>
|
<a href="#/groups" class="visible-xs">…</a>
|
||||||
<a href="#/groups" class="hidden-xs">{{t 'group_permissions'}}</a>
|
<a href="#/groups" class="hidden-xs">{{t 'groups_and_permissions'}}</a>
|
||||||
<a href="#/groups/create">{{t 'group_new'}}</a>
|
<a href="#/groups/create">{{t 'group_new'}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
<span class="label label-default label-removable">
|
<span class="label label-default label-removable">
|
||||||
<span class="fa-fw fa-{{icon}}"></span>
|
<span class="fa-fw fa-{{icon}}"></span>
|
||||||
{{text}}
|
{{text}}
|
||||||
<a role="button" data-type="{{type}}s" data-operation="remove" data-item="{{value}}" data-group="{{group}}" class="group-update">
|
<button data-type="{{type}}s" data-action="remove" data-item="{{value}}" data-group="{{group}}">
|
||||||
<span class="fa-close" style="margin-left:5px"></span>
|
<span class="fa-close" style="margin-left:5px"></span>
|
||||||
<span class="sr-only">{{t 'delete'}}</span>
|
<span class="sr-only">{{t 'delete'}}</span>
|
||||||
</a>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
{{/inline}}
|
{{/inline}}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{{#each inv}}
|
{{#each inv}}
|
||||||
<li><a href="#" data-type="{{../type}}s" data-operation="add" data-item="{{.}}" data-group="{{../group}}" class="group-update">{{call ../display .}}</a></li>
|
<li><button data-type="{{../type}}s" data-action="add" data-item="{{.}}" data-group="{{../group}}" >{{call ../display .}}</button></li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -53,10 +53,10 @@
|
||||||
<span class="fa-fw fa-group"></span> {{#if special}}{{t (concat 'group_' @key)}}{{else}}{{t 'group'}} "{{ucwords @key}}"{{/if}}
|
<span class="fa-fw fa-group"></span> {{#if special}}{{t (concat 'group_' @key)}}{{else}}{{t 'group'}} "{{ucwords @key}}"{{/if}}
|
||||||
</a>
|
</a>
|
||||||
{{#unless special}}
|
{{#unless special}}
|
||||||
<a href="#/groups/{{@key}}/delete" role="button" class="group-delete">
|
<button class="group-delete" data-action="delete-group" data-group="{{@key}}">
|
||||||
<span class="fa-close"></span>
|
<span class="fa-close"></span>
|
||||||
<span class="sr-only">{{t 'delete'}}</span>
|
<span class="sr-only">{{t 'delete'}}</span>
|
||||||
</a>
|
</button>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
@ -125,7 +125,7 @@
|
||||||
{{#each groups}}
|
{{#each groups}}
|
||||||
{{#if primary}}
|
{{#if primary}}
|
||||||
{{#unless (or permissions display)}}
|
{{#unless (or permissions display)}}
|
||||||
<li><a href="#" data-user="{{@key}}" class="group-add-user">{{@key}}</a></li>
|
<li><button data-action="add-user-specific-permission" data-user="{{@key}}">{{@key}}</button></li>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
</table>
|
</table>
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
<a role="button" href="#/users/{{username}}/edit" class="btn btn-info slide"><span class="fa-pencil-square-o"/> {{t 'user_username_edit' username}}</a>
|
<a role="button" href="#/users/{{username}}/edit" class="btn btn-info slide"><span class="fa-pencil-square-o"/> {{t 'user_username_edit' username}}</a>
|
||||||
<a role="button" href="#/users/{{username}}/delete" class="btn btn-danger slide back"><span class="fa-trash-o"/> {{t 'delete'}}</a>
|
<button class="btn btn-danger" data-action="delete" data-user="{{username}}"><span class="fa-trash-o"/> {{t 'delete'}}</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
120
tests/test_i18n_keys.py
Normal file
120
tests/test_i18n_keys.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import yaml
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Find used keys in python code #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def find_expected_string_keys():
|
||||||
|
|
||||||
|
# Try to find :
|
||||||
|
# y18n.t("foo" +) # (the real key is a concatenation of 'foo' with something else)
|
||||||
|
# y18n.t("foo") or y18n.t('foo', ...) # actual full key
|
||||||
|
js_p1 = re.compile(r'y18n\.t\(\s*[\"\'](\w+)[\"\']\s*[\,\)]')
|
||||||
|
js_p2 = re.compile(r'y18n\.t\(\s*[\"\'](\w+)[\"\']\s*\+')
|
||||||
|
|
||||||
|
js_files = glob.glob("../src/js/yunohost/controllers/*.js")
|
||||||
|
js_files.extend(glob.glob("../src/js/yunohost/*.js"))
|
||||||
|
|
||||||
|
for js_file in js_files:
|
||||||
|
content = open(js_file).read()
|
||||||
|
for m in js_p1.findall(content):
|
||||||
|
yield m
|
||||||
|
for m in js_p2.findall(content):
|
||||||
|
yield m
|
||||||
|
|
||||||
|
# In views we have stuff like {{t 'foo' arg}}
|
||||||
|
views_p1 = re.compile(r'{{t\s*[\"\'](\w+)[\"\']')
|
||||||
|
# Somes are inside {{ (t 'foo')))
|
||||||
|
views_p2 = re.compile(r'\(t\s*[\"\'](\w+)[\"\']\)')
|
||||||
|
views_p3 = re.compile(r't \(concat\s*[\"\'](\w+)[\"\']')
|
||||||
|
views_p4 = re.compile(r'data-y18n=[\"\'](\w+)[\"\']')
|
||||||
|
|
||||||
|
view_files = glob.glob("../src/*.html")
|
||||||
|
view_files.extend(glob.glob("../src/views/*.ms"))
|
||||||
|
view_files.extend(glob.glob("../src/views/*/*.ms"))
|
||||||
|
|
||||||
|
for view_file in view_files:
|
||||||
|
content = open(view_file).read()
|
||||||
|
for m in views_p1.findall(content):
|
||||||
|
yield m
|
||||||
|
for m in views_p2.findall(content):
|
||||||
|
yield m
|
||||||
|
for m in views_p3.findall(content):
|
||||||
|
yield m
|
||||||
|
for m in views_p4.findall(content):
|
||||||
|
yield m
|
||||||
|
|
||||||
|
# App maintenance state
|
||||||
|
for state in ['maintained', 'orphaned', 'request_adoption', 'request_help','unmaintained']:
|
||||||
|
yield state
|
||||||
|
yield state + "_details"
|
||||||
|
|
||||||
|
# Service states
|
||||||
|
for state in ['active', 'disabled', 'enabled', 'inactive']:
|
||||||
|
yield state
|
||||||
|
|
||||||
|
yield "confirm_cert_"
|
||||||
|
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Load en locale json keys #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
def keys_defined_for_en():
|
||||||
|
return json.loads(open("../src/locales/en.json").read()).keys()
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Compare keys used and keys defined #
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
|
||||||
|
expected_string_keys = set(find_expected_string_keys())
|
||||||
|
keys_defined = set(keys_defined_for_en())
|
||||||
|
|
||||||
|
def test_undefined_i18n_keys():
|
||||||
|
undefined_keys = expected_string_keys.difference(keys_defined)
|
||||||
|
undefined_keys = sorted(undefined_keys)
|
||||||
|
|
||||||
|
undefined_keys = [k for k in undefined_keys if not k.endswith("_")]
|
||||||
|
|
||||||
|
return undefined_keys
|
||||||
|
|
||||||
|
if undefined_keys:
|
||||||
|
raise Exception("Those i18n keys should be defined in en.json:\n"
|
||||||
|
" - " + "\n - ".join(undefined_keys))
|
||||||
|
|
||||||
|
|
||||||
|
def test_unused_i18n_keys():
|
||||||
|
|
||||||
|
unused_keys = keys_defined.difference(expected_string_keys)
|
||||||
|
unused_keys = sorted(unused_keys)
|
||||||
|
|
||||||
|
partial_match = [k for k in unused_keys if any(k.startswith(m) for m in expected_string_keys if m.endswith("_")) ]
|
||||||
|
|
||||||
|
unused_keys_2 = []
|
||||||
|
for k in unused_keys:
|
||||||
|
if not any(k.startswith(m) for m in expected_string_keys if m.endswith("_")):
|
||||||
|
unused_keys_2.append(k)
|
||||||
|
|
||||||
|
return unused_keys_2
|
||||||
|
|
||||||
|
if unused_keys:
|
||||||
|
raise Exception("Those i18n keys appears unused:\n"
|
||||||
|
" - " + "\n - ".join(unused_keys))
|
||||||
|
|
||||||
|
|
||||||
|
print("--------- undefined")
|
||||||
|
print()
|
||||||
|
print(test_undefined_i18n_keys())
|
||||||
|
print("--------- unused")
|
||||||
|
print()
|
||||||
|
print(test_unused_i18n_keys())
|
Loading…
Add table
Reference in a new issue