Merge pull request #209 from YunoHost/new-diagnosis-interface

[enh] New diagnosis interface
This commit is contained in:
Alexandre Aubin 2019-11-07 00:51:08 +01:00 committed by GitHub
commit ca5b2eeecd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 219 additions and 66 deletions

View file

@ -101,10 +101,6 @@ button {
color: transparent;
}
.label {
border-radius: 1px;
}
/*
* The top heading of the doc
*
@ -941,3 +937,30 @@ input[type='radio'].nice-radio {
-o-transition: none !important;
transition: none !important;
}
/* Just to be able to override list-group-item with alert-success's background and border colors */
.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;
}

View file

@ -0,0 +1,100 @@
(function() {
// Get application context
var app = Sammy.apps['#main'];
var store = app.store;
// *********
// Diagnosis
// *********
app.get('#/diagnosis', function (c) {
c.api('GET', '/diagnosis/show?full', {}, function(data) {
// 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 (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() {
// 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) {
c.refresh();
});
});
// 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) {
c.refresh();
})
});
$("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) {
c.refresh();
})
});
});
});
});
})();

View file

@ -251,21 +251,6 @@
});
});
// 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('GET', '/diagnosis'+endurl, {}, function(diagnosis) {
c.view('tools/tools_diagnosis', {
'diagnosis' : JSON.stringify(diagnosis, undefined, 4),
'raw' : diagnosis,
'private' : private
});
});
});
// Migrations
app.get('#/tools/migrations', function (c) {
c.api('GET', '/migrations?pending', {}, function(pending_migrations) {

View file

@ -69,13 +69,10 @@
c.flash('fail', y18n.t('error_retrieve_feed', [securityFeed]));
});
c.api("GET", "/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'));
}
c.hideLoader();
c.api("GET", "/diagnosis/show?full", {}, function(data) {
basesystem = data.reports.filter(function(r) { return r.id == "basesystem"; })[0];
version_info = basesystem.items.filter(function(i) { return (i.meta && i.meta.test && i.meta.test == "ynh_versions"); })[0];
$('#yunohost-version').html(y18n.t('footer_version', [version_info.data.main_version, version_info.data.repo]));
});
});
});

View file

@ -525,6 +525,18 @@
c.hideLoader();
});
});
},
force_redirect: function(to) {
c = this;
// This is a copy-pasta of some of the redirect/refresh code of
// sammy.js because for some reason calling the origina
// redirect/refresh function in some context does not work >.>
// (e.g. if you're already on the page)
c.trigger('redirect', {to: to});
c.app.last_location = c.path;
c.app.setLocation(to);
c.app.trigger('location-changed');
}
});

View file

@ -181,9 +181,10 @@
sam.store.set('url', window.location.hostname + '/yunohost/api');
if (sam.store.get('connected')) {
this.api('GET', '/diagnosis', {}, function(diagnosis) {
versions = diagnosis.packages;
$('#yunohost-version').html(y18n.t('footer_version', [versions.yunohost.version, versions.yunohost.repo]));
this.api('GET', '/diagnosis/show?full', {}, function(data) {
basesystem = data.reports.filter(function(r) { return r.id == "basesystem"; })[0];
version_info = basesystem.items.filter(function(i) { return (i.meta && i.meta.test && i.meta.test == "ynh_versions"); })[0];
$('#yunohost-version').html(y18n.t('footer_version', [version_info.data.main_version, version_info.data.repo]));
});
}

View file

@ -88,11 +88,10 @@
"default": "Default",
"delete": "Delete",
"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.",
"diagnosis": "Diagnosis",
"diagnosis_hide_private": "Show diagnostic information without private data",
"diagnosis_view_private": "Show diagnostic information including private data",
"diagnosis_with_private": "Diagnosis with private data",
"diagnosis_experimental_disclaimer": "Be aware that the diagnosis feature is still experimental and being polished, and it may not be fully reliable.",
"disable": "Disable",
"disabled": "Disabled",
"dns": "DNS",
@ -117,12 +116,14 @@
"download": "Download",
"enable": "Enable",
"enabled": "Enabled",
"errors": "%s errors",
"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_select_domain": "You should indicate a domain",
"error_server": "Server error",
"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)",
"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.",
"firewall": "Firewall",
"footer_version": "Powered by <a href='https://yunohost.org'>YunoHost</a> %s (%s).",
@ -162,6 +163,8 @@
"hook_data_mail": "Mail",
"hook_data_mail_desc": "Raw emails stored on the server",
"id": "ID",
"ignore": "Ignore",
"ignored": "%s ignored",
"inactive": "Inactive",
"infos": "Info",
"install": "Install",
@ -176,6 +179,7 @@
"ipv6": "IPv6",
"label": "Label",
"label_for_manifestname": "Label for %s",
"last_ran": "Last time ran:",
"level": "level",
"license": "License",
"loading": "Loading …",
@ -224,10 +228,6 @@
"passwords_dont_match": "Passwords don't match",
"passwords_too_short": "Password is too short",
"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_operation": "Operations made on system with YunoHost",
"logs_history": "History of command run on system",
@ -257,6 +257,7 @@
"previous": "Previous",
"protocol": "Protocol",
"read_more": "Read more",
"rerun_diagnosis": "Rerun diagnosis",
"refresh_app_list": "Refresh list",
"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!",
@ -318,6 +319,7 @@
"tools_shutdown_reboot": "Shutdown/Reboot",
"udp": "UDP",
"unauthorized": "Unauthorized",
"unignore": "Unignore",
"uninstall": "Uninstall",
"unknown_action": "Unknown action %s",
"unknown_argument": "Unknown argument: %s",
@ -344,6 +346,7 @@
"users_new": "New user",
"users_no": "No users.",
"version": "Version",
"warnings": "%s warnings",
"warning_first_user": "You probably need to <a href='#/users/create' class='alert-link'>create a user</a> first.",
"wrong_password": "Wrong password",
"yes": "Yes",

View file

@ -0,0 +1,57 @@
<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-warning">{{t 'diagnosis_experimental_disclaimer'}}</div>
{{#reports}}
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title" style="display: inline-block; margin-right: 10px;">
<a data-toggle="collapse" href="#category-{{id}}">{{ description }}</a>
</h2>
{{#if noIssues}}<span class="label label-success">{{t 'everything_good'}}</span>{{/if}}
{{#if errors}}<span class="label label-danger">{{t 'errors' 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 btn-info 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="category-{{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">
{{#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" id="details-{{../id}}-{{@index}}">
<ul>
{{#details}}<li>{{.}}</li>{{/details}}
</ul>
</div>
{{/if}}
</li>
{{/items}}
</ul>
</div>
</div>
{{/reports}}

View file

@ -23,6 +23,10 @@
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading"><span class="fa-fw fa-wrench"></span> {{t 'tools'}}</h2>
</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">
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading"><span class="fa-fw fa-archive"></span> {{t 'backup'}}</h2>

View file

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

View file

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

View file

@ -39,7 +39,7 @@
<div class="list-group-item clearfix">
<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>
<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>
{{/apps}}
</div>