Commit 8f5081b2 authored by Leo Iannacone's avatar Leo Iannacone

Merge remote-tracking branch 'github/master' into portable

parents f8da1df2 50091ba0
......@@ -31,7 +31,7 @@ app.set("view engine", "ejs")
# index page
app.get("/", routes.index)
# distibution page
# distribution page
app.get(config.routes.distribution, routes.distribution)
# preferences page
......
......@@ -143,6 +143,10 @@ class Client
stats.get_all_packages (packages) =>
@socket.emit e.history, packages
@socket.on e.disk_usage, () =>
stats.get_disk_usage (result) =>
@socket.emit e.disk_usage, result
# on client disconnection close all watchers
@socket.on "disconnect", =>
socket_watchers = @socket.watchers
......
......@@ -90,6 +90,15 @@ config.debomatic.excluded_files = [
"json"
]
###
List of subdirectories in distributions to show in disk usage
###
config.debomatic.disk_usage_subdirs = [
"aptcache"
"pool"
"chroot"
]
###
The routes, that are the pages urls
###
......@@ -118,6 +127,7 @@ config.events.client.file = "c.file"
config.events.client.file_newcontent = "c.file_newcontent"
config.events.client.status = "c.status"
config.events.client.history = "c.history"
config.events.client.disk_usage = "c.disk_usage"
###
The status according with JSONLogger.py module
......
fs = require('fs')
glob = require('glob')
exec = require('child_process').exec
config = require('./config')
utils = require('./utils')
......@@ -13,7 +14,7 @@ get_all_packages = (cb) ->
glob "#{config.debomatic.path}/*/pool/*/*.json", {}, (err, files) ->
if err?
utils.errors_handler "history:get_all_packages", err
utils.errors_handler "stats:get_all_packages", err
return
packages = []
for f in files
......@@ -30,4 +31,46 @@ get_all_packages = (cb) ->
cb(packages)
get_disk_usage = (cb) ->
exec "du -BM -d 2 #{config.debomatic.path}", (error, stdout, stderr) ->
if error?
if stderr?
error = '\n\t' + stderr.replace(/\n/g, '\n\t')
utils.errors_handler "disk usage error:", error
return
result = {}
others = 0
for line in stdout.split('\n')
continue if line == ''
info = line.split(/\t+/g)
size = parseInt(info[0])
dirs = info[1].replace("#{config.debomatic.path}", '').split('/')
# case total size for debomatic incoming
if dirs.length <= 1
result['size'] = size
continue
distribution = dirs[1]
if not result[distribution]?
result[distribution] = {}
# case total size for distribution
if dirs.length == 2
result[distribution]['size'] = size
result[distribution]['others'] = others
others = 0
continue
# case size for distribution/subdir
subdir = dirs[2]
subdir = "chroot" if distribution == subdir
if subdir in config.debomatic.disk_usage_subdirs
result[distribution][subdir] = size
else
others += size
cb(result)
module.exports.get_all_packages = get_all_packages
module.exports.get_disk_usage = get_disk_usage
......@@ -109,8 +109,12 @@ watch_path_onsocket = (event_name, socket, data, watch_path, callback) ->
errors_handler = (from, err, socket) ->
from = "NO SOCKET: " + from unless socket
console.error from, err.message
socket.emit config.events.error, err.message if socket
if err.message?
msg = err.message
else
msg = err
console.error from, msg
socket.emit config.events.error, message if socket
return
Tail::watchEvent = (e) ->
......
......@@ -3,6 +3,7 @@
"version": "1.0.0",
"private": true,
"dependencies": {
"coffee-script": "*",
"express": "4.x",
"serve-index": "*",
"serve-static": "*",
......@@ -15,7 +16,7 @@
},
"scripts": {
"install": "bash scripts/install.sh",
"start": "coffee debomatic-webui",
"start": "./node_modules/coffee-script/bin/coffee debomatic-webui",
"test": "cd test; mocha -b -R spec --compilers coffee:coffee-script/register --require should tests.coffee"
},
"bin": {
......
......@@ -105,6 +105,36 @@ function Page_History() {
}
// add tooltip to graphs
function _create_graph_tooltip(graph, element, suffix_value) {
var $chart = $(graph);
var $toolTip = $chart
.append('<div class="tooltip fade top in" role="tooltip">' +
'<div class="tooltip-arrow"></div> ' +
'<div class="tooltip-inner"></div>' +
'</div>').find('.tooltip').hide();
$chart.on('mousemove', function (event) {
$toolTip.css({
left: event.offsetX - $toolTip.width() / 2,
top: event.offsetY - $toolTip.height() - 20
});
});
$chart.on('mouseenter', element, function () {
var $point = $(this),
value = $point.attr('ct:value'),
seriesName = $point.parent().attr('ct:series-name');
if (suffix_value)
value = value + " " + suffix_value;
$toolTip.find('.tooltip-inner').html(seriesName + ' (' + value + ')');
$toolTip.show();
});
$chart.on('mouseleave', element, function () {
$toolTip.hide();
});
}
function _create_graph_distributions() {
// build the distribution Pie graph
var distributions_data = {
......@@ -147,44 +177,87 @@ function Page_History() {
});
}
Chartist.Line('#days-chart', days_data);
_create_graph_tooltip("#days-chart", '.ct-point');
var $chart = $('#days-chart');
var effect = function (x, t, b, c, d) {
return -c * (t /= d) * (t - 2) + b;
};
var $chart = $('#days-chart');
var $toolTip = $chart
.append('<div class="tooltip fade top in" role="tooltip">' +
'<div class="tooltip-arrow"></div> ' +
'<div class="tooltip-inner"></div>' +
'</div>').find('.tooltip').hide();
$chart.on('mouseenter', '.ct-point', function () {
var $point = $(this),
value = $point.attr('ct:value'),
seriesName = $point.parent().attr('ct:series-name');
$point.stop().animate({
$(this).stop().animate({
'stroke-width': '20px'
}, 200, effect);
$toolTip.find('.tooltip-inner').html(seriesName + ' (' + value + ')');
$toolTip.show();
});
$chart.on('mouseleave', '.ct-point', function () {
var $point = $(this);
$point.stop().animate({
$(this).stop().animate({
'stroke-width': '10px'
}, 150, effect);
$toolTip.hide();
});
}
$chart.on('mousemove', function (event) {
$toolTip.css({
left: event.offsetX - $toolTip.width() / 2,
top: event.offsetY - $toolTip.height() - 20
function _create_graph_disk(socket_data) {
var distributions = [];
var subdirs = [];
var data = {};
var total_sizes = {};
var series = [];
var labels = [];
for (var distribution in socket_data) {
if (distribution == 'size') {
var total_size_in_gb = Number(socket_data.size / 1000).toFixed(1);
$("#disk-usage .total-size").text(total_size_in_gb + ' GB');
continue;
}
distributions.push(distribution);
}
distributions.sort();
for (var i = 0; i < distributions.length; i++) {
distribution = distributions[i];
for (var subdir in socket_data[distribution]) {
if (subdir == 'size') {
total_sizes[distribution] = socket_data[distribution].size;
continue;
}
if (!data.hasOwnProperty(subdir)) {
subdirs.push(subdir);
data[subdir] = [];
}
data[subdir].push(socket_data[distribution][subdir]);
}
}
for (i = 0; i < subdirs.length; i++) {
series.push({
name: subdirs[i],
data: data[subdirs[i]]
});
}
var options = {
seriesBarDistance: 12
};
Chartist.Bar('#disk-chart', {
labels: distributions,
series: series
}, options);
_create_graph_tooltip("#disk-chart", '.ct-bar', "MB");
// WORKAROUND: add total spaces to label
// wating for support multilines for label in chartist-js
// https://github.com/gionkunz/chartist-js/issues/25
$('#disk-chart svg').height("+=20");
$('#disk-chart .ct-label.ct-horizontal').each(function (index, elem) {
var size = document.createElementNS("http://www.w3.org/2000/svg", 'text');
var currentY = Number(elem.getAttribute('dy'));
size.setAttribute('dx', Number(elem.getAttribute('dx')));
size.setAttribute('dy', currentY + 15);
size.setAttribute('class', 'ct-label ct-horizontal ct-size');
size.textContent = total_sizes[elem.textContent] + " MB";
elem.parentNode.appendChild(size);
});
}
function _exportTableToCSV($table, filename) {
......@@ -257,10 +330,20 @@ function Page_History() {
$('.body').fadeIn("fast");
});
socket.on(config.events.client.disk_usage, function (socket_data) {
debug_socket('received', config.events.client.disk_usage, socket_data);
_create_graph_disk(socket_data);
});
debug_socket('emit', config.events.client.history, '');
socket.emit(config.events.client.history);
debug_socket('emit', config.events.client.disk_usage, '');
socket.emit(config.events.client.disk_usage);
};
// active downlaod tooltip
$("[data-toggle='popover']").popover();
$('#download').on('click', function () {
_exportTableToCSV.apply(this, [$('#history'), 'history.csv']);
});
......
......@@ -262,7 +262,7 @@ footer .info {
/* History page */
.ct-chart {
height: 180px;
width: 50%;
width: 100%;
float: left;
margin-bottom: 30px;
position: relative;
......@@ -279,6 +279,7 @@ footer .info {
#history {
margin-top: 15px;
max-width: 1000px;
}
#history .alt-row {
......@@ -289,6 +290,10 @@ footer .info {
white-space: nowrap;
}
#disk-usage .ct-label.ct-size {
font-size: 0.72em;
}
/* add more colors to graphs */
.ct-series-e .ct-bar,
.ct-chart .ct-series.ct-series-e .ct-line,
......
<% include header.ejs %>
<article class="page">
<article class="">
<header><h2>History</h2></header>
<p class="lead text-muted">
The log of packages
</p>
<div id="charts">
<div id="days-chart" class="ct-chart"></div>
<div id="distributions-chart" class="ct-chart"></div>
<div class="row" id="charts">
<div class="col-md-4">
<p class="lead text-muted">
The log of builds
</p>
<div id="days-chart" class="ct-chart"></div>
</div>
<div class="col-md-4">
<p class="lead text-muted">
Total packages
</p>
<div id="distributions-chart" class="ct-chart"></div>
</div>
<div id="disk-usage" class="col-md-4">
<p class="lead text-muted">
Disk usage <span class="total-size"></span>
</p>
<div id="disk-chart" class="ct-chart"></div>
</div>
</div>
<div class="body" style="display: none">
<a id="download" class="btn btn-primary">Download current view</a>
<a id="download" class="btn btn-primary" data-trigger="hover" data-toggle="popover" title="Export to CSV" data-placement="right" data-content="Save the packages displaied in the table in format CSV. You can filter out packages by selecting distributions, a status, specifying a date or an uploader.">Download current view</a>
<table id="history" class="tablesorter">
<thead>
<tr>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment