Merge pull request #130 from YunoHost/journals

Web interface for journal new features
This commit is contained in:
Alexandre Aubin 2018-08-23 21:42:18 +02:00 committed by GitHub
commit 71b3bb8dce
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 203 additions and 2 deletions

View file

@ -6,6 +6,7 @@
"dependencies": {
"bootstrap": "3.3.6",
"font-awesome": "4.5.0",
"handlebars-helper-intl": "1.1.2",
"handlebars": "4.0.11",
"sammy": "0.7.6",
"js-cookie": "2.1.0",

View file

@ -444,6 +444,13 @@ button[data-paste-content] {
}
}
.full-width {
width: 100%;
}
.overflow-auto {
overflow: auto;
}
/** Breadcrumb **/
@breadcrumb-bg: none;

View file

@ -41,6 +41,7 @@ gulp.task('js', function() {
'bower_components/jquery/dist/jquery.js',
'bower_components/js-cookie/src/js.cookie.js',
'bower_components/handlebars/handlebars.js',
'bower_components/handlebars-helper-intl/dist/handlebars-intl-with-locales.js',
'bower_components/sammy/lib/sammy.js',
'bower_components/sammy/lib/plugins/sammy.handlebars.js',
'bower_components/sammy/lib/plugins/sammy.json.js',

View file

@ -96,6 +96,62 @@
}
});
// Display journals list
app.get('#/tools/logs', function (c) {
c.api("/logs", function(categories) {
data = [];
icons = {
'operation': 'wrench',
'history': 'history',
'package': 'puzzle-piece',
'system': 'cogs',
'access': 'ban',
'service': 'cog',
'app': 'cubes'
}
for (var category in categories) {
if (categories.hasOwnProperty(category)) {
data.push({
key:category,
icon:(category in icons)?icons[category]:'info-circle',
value:categories[category]
});
}
}
c.view('tools/tools_logs', {
"data": data,
"locale": y18n.locale
});
});
});
// One journal
app.get(/\#\/tools\/logs\/(.*)(\?number=(\d+))?/, function (c) {
var params = "?path=" + c.params["splat"][0];
var number = (c.params["number"])?c.params["number"]:50;
params += "&number=" + number;
c.api("/logs/display" + params, function(log) {
if ('metadata' in log) {
if ('started_at' in log.metadata) {
log.metadata.started_at = Date.parse(log.metadata.started_at)
}
if ('ended_at' in log.metadata) {
log.metadata.ended_at = Date.parse(log.metadata.ended_at)
}
if (!'env' in log.metadata && 'args' in log.metadata) {
log.metadata.env = log.metadata.args
}
}
c.view('tools/tools_log', {
"log": log,
"next_number": log.logs.length == number ? number * 10:false,
"locale": y18n.locale
});
});
});
// Upgrade a specific apps
app.get('#/upgrade/apps/:app', function (c) {
c.confirm(

View file

@ -390,7 +390,7 @@
// Paste <pre>
prePaste: function() {
var pasteButtons = $('button[data-paste-content]');
var pasteButtons = $('button[data-paste-content],a[data-paste-content]');
pasteButtons.on('click', function(){
// Get paste content element
var preElement = $($(this).data('paste-content'));
@ -402,7 +402,7 @@
$.ajax({
type: "POST",
url: 'https://paste.yunohost.org/documents',
data: preElement[0].innerHTML,
data: preElement.text(),
})
.success(function(data, textStatus, jqXHR) {
window.open('https://paste.yunohost.org/' + data.key, '_blank');

View file

@ -10,6 +10,7 @@
// Plugins
sam.use('Handlebars', 'ms');
window.HandlebarsIntl.registerWith(Handlebars);
Handlebars.registerHelper('ucwords', function(str) {
return (str + '').replace(/^([a-z\u00E0-\u00FC])|\s+([a-z\u00E0-\u00FC])/g, function ($1) {
@ -41,6 +42,16 @@
var result = y18n.t(y18n_key, Array.prototype.slice.call(arguments, 1));
return new Handlebars.SafeString(result);
});
Handlebars.registerHelper('concat', function() {
var outStr = '';
for(var arg in arguments){
if(typeof arguments[arg]!='object'){
outStr += arguments[arg];
}
}
return outStr;
});
// Block helper to add a tooltip to any element
Handlebars.registerHelper('tooltip', function(tooltip, options) {

View file

@ -226,6 +226,27 @@
"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",
"logs_package": "Debian packages management history",
"logs_system": "Kernel logs and others low level events",
"logs_access": "List of access and bans",
"logs_service": "Services logs",
"logs_app": "Apps logs",
"logs_no_logs_registered": "No log registered for this category",
"logs_end_with_error": "This log finished with the error :",
"logs_error": "Error",
"logs_ended_at": "End",
"logs_started_at": "Start",
"logs_path": "Path",
"logs_context": "Context",
"logs_share_with_yunopaste": "Share with YunoPaste",
"logs_more": "Display more lines",
"path_url": "Path",
"port": "Port",
"ports": "Ports",

View file

@ -11,6 +11,10 @@
<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>
</a>
<a href="#/tools/migrations" class="list-group-item slide clearfix">
<span class="pull-right fa-chevron-right"></span>
<h2 class="list-group-item-heading">{{t 'migrations'}}</h2>

View file

@ -0,0 +1,64 @@
<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/logs">{{t 'logs'}}</a>
<a href="#/tools/logs/{{ log.log_path }}">{{ log.log_path }}</a>
</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>
{{#intl locales=locale}}
{{#if log.metadata}}
<div class="panel panel-default">
<div class="panel-heading">
<!-- PLEASE DON'T INDENT THIS CODE, IT IS PASTED ON YUNOPASTE -->
<h2 class="panel-title" id="description"><span class="fa-fw fa-info-circle"></span> {{ log.description }}</h2>
</div>
<div class="panel-body">
<dl class="dl-horizontal" id="metadata">
<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}}{{#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}}
</dl>
</div>
</div>
{{#if log.metadata.env}}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading-context">
<h2 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-context" aria-expanded="true" aria-controls="collapse-context">
<span class="fa-fw fa-bug"></span>{{t 'logs_context'}}
</a>
</h2>
</div>
<div id="collapse-context" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-context">
<div class="panel-body">
<dl class="dl-horizontal" id="env">
{{#each log.metadata.env}}<dt>{{@key}}</dt> <dd>{{.}}</dd>
{{/each}}
</dl>
</div>
</div>
</div>
{{/if}}
{{/if}}
<div class="panel panel-default">
<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>
</div>
<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}}
<!-- no indent because pre is sensible to whitespaces -->
<pre id="log" class="full-width">{{#log.logs}}{{.}}
{{/log.logs}}</pre>
</div>
</div>
{{/intl}}

View file

@ -0,0 +1,34 @@
<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/logs">{{t 'logs'}}</a>
</div>
<div class="separator"></div>
{{#intl locales=locale}}
{{#if data}}
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
{{#data}}
{{#if value}}
<div class="panel panel-default">
<div class="panel-heading" role="tab" id="heading-{{key}}">
<h2 class="panel-title">
<a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse-{{key}}" aria-expanded="true" aria-controls="collapse-{{key}}">
<span class="fa-fw fa-{{icon}}"></span>{{t (concat 'logs_' key)}}
</a>
</h2>
</div>
<div id="collapse-{{key}}" class="panel-collapse{{#if @first}}{{else}} collapse{{/if}}" role="tabpanel" aria-labelledby="heading-{{key}}">
<div class="list-group">
{{#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> {{ description }}</a>
{{/value}}
</div>
</div>
</div>
{{/if}}
{{/data}}
</div>
{{/if}}
{{/intl}}

View file

@ -0,0 +1 @@
<div class="alert alert-warning"><i class="fa-refresh"></i> {{t 'tools_rebooting'}}</div>

View file

@ -0,0 +1 @@
<div class="alert alert-warning"><i class="fa-power-off"></i> {{t 'tools_shuttingdown'}}</div>