Skip to content

Commit

Permalink
WebUI: introduce graph comparison tool
Browse files Browse the repository at this point in the history
This adds a new page (/compare.html) which enables to compare two
result sets by displaying side-by-side graphs.

This commit also introduces a SubFilter class (a filter based on
another filter), used for the graph comparison.
  • Loading branch information
p-l- committed Dec 18, 2015
1 parent a620ab7 commit 81ee3e2
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 3 deletions.
2 changes: 2 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ web/dokuwiki/doc/screenshots.txt
web/dokuwiki/doc/tests.txt
web/dokuwiki/doc/webui.txt
web/dokuwiki/media/logo.png
web/static/compare.html
web/static/config-sample.js
web/static/droids.png
web/static/favicon-loading.gif
Expand Down Expand Up @@ -352,6 +353,7 @@ web/static/fi/flags/4x3/yt.svg
web/static/fi/flags/4x3/za.svg
web/static/fi/flags/4x3/zm.svg
web/static/fi/flags/4x3/zw.svg
web/static/ivre/compare.js
web/static/ivre/content.js
web/static/ivre/controllers.js
web/static/ivre/filters.js
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def run(self):
'docker/web-apache/doku-conf-local.php']),
('share/ivre/web/static',
['web/static/index.html',
'web/static/compare.html',
'web/static/report.html',
'web/static/upload.html',
'web/static/config-sample.js',
Expand Down Expand Up @@ -134,6 +135,7 @@ def run(self):
# IVRE
('share/ivre/web/static/ivre',
['web/static/ivre/ivre.css',
'web/static/ivre/compare.js',
'web/static/ivre/controllers.js',
'web/static/ivre/filters.js',
'web/static/ivre/graph.js',
Expand Down
156 changes: 156 additions & 0 deletions web/static/compare.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<!DOCTYPE html>

<!--
This file is part of IVRE.
Copyright 2011 - 2015 Pierre LALET <[email protected]>
IVRE is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
IVRE is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with IVRE. If not, see <http://www.gnu.org/licenses/>.
-->

<html ng-app="ivreWebUi">

<head>
<link rel="stylesheet" type="text/css" href="bs/css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="fi/css/flag-icon.css" />
<link rel="stylesheet" type="text/css" href="ivre/ivre.css" />
<link rel="icon" type="image/png" id="favicon" href="favicon.png" />
<script type="text/javascript" src="jq/jquery.js"></script>
<script type="text/javascript" src="bs/js/bootstrap.js"></script>
<script type="text/javascript" src="d3/js/d3.v3.min.js"></script>
<script type="text/javascript" src="d3/js/topojson.v1.min.js"></script>
<script type="text/javascript" src="an/js/angular.js"></script>
<script type="text/javascript">
config = {};
</script>
<script type="text/javascript" src="config.js"></script>
<script type="text/javascript" src="ivre/content.js"></script>
<script type="text/javascript" src="ivre/utils.js"></script>
<script type="text/javascript" src="ivre/graph.js"></script>
<script type="text/javascript" src="ivre/filters.js"></script>
<script type="text/javascript" src="ivre/compare.js"></script>
<script type="text/javascript" src="ivre/controllers.js"></script>
<script type="text/javascript" src="ivre/params.js"></script>
<script type="text/javascript" src="ivre/tooltip.js"></script>
<script type="text/javascript" src="ivre/ivre.js"></script>
<title>IVRE Web UI</title>
</head>

<body onload="init_compare();" ng-controller="IvreCompareCtrl"
style="padding-top: 10px">
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-3">
<table class="table">
<thead>
<tr><th colspan="2">Result counters</th></tr>
</thead>
<tbody>
<tr ng-repeat="filter in all_filters"
ng-class="{succes: filter.count > 0, warning: filter.count === undefined, error: filter.count === 0}">
<td>{{names[filter.name]}}</td>
<td ng-switch="filter.count">
<span ng-switch-when="0">No result!</span>
<span ng-switch-when="undefined">[Counting...]</span>
<span ng-switch-default="">{{filter.count}}</span>
</td>
</tr>
<tr>
<td>Results in all sets </td>
<td>{{all_sets.count}}
</tr>
</tbody>
</table>
</div>
<div class="col-sm-12 col-md-3" ng-controller="IvreFilterListCtrl">
<ul class="nav" ng-controller="IvreFilterListCtrl">
<ivre-filters title="Common filters"></ivre-filters>
</ul>
</div>
<div class="col-sm-12 col-md-3" ng-repeat="set in [1, 2]">
<ul class="nav" ng-controller="IvreFilterListCtrl">
<ivre-filters title="Filters for set {{set}}"
ng-init="tooltipplace=$last?'left':'right'"
parent=""
name="set{{set}}"></ivre-filters>
</ul>
</div>
</div>
<div class="row">
<div class="navbar graph-list center col-sm-12">
<div class="navbar-inner">
<ul class="nav navbar-nav">
<li>
<form id="explore" ng-submit="build_top_chart();">
<input type="text"
placeholder="Top values"
class="form-control input-medium"
oninput="ToolTip.handle(this, HELP_TOPVALUES);"
onfocus="ToolTip.handle(this, HELP_TOPVALUES);"
onblur="ToolTip.remove(this);"
id="topvalues-input"
ng-model="topvaluesfield"
data-trigger="manual"
data-html="true"
data-container="#navbar"
/>
</form>
</li>
<li>
<div class="btn-group" role="group">
<button class="btn btn-default" ng-click="build_ip_plane()"
ng-disabled="!is_ready()">Address space</button>
<button class="btn btn-default" ng-click="build_ip_ports()"
ng-disabled="!is_ready()">IPs &amp; Ports</button>
<button class="btn btn-default"
ng-click="build_ip_map()">Map</button>
<button class="btn btn-default" ng-click="build_ip_timeline()"
ng-disabled="!is_ready()">Timeline</button>
<button class="btn btn-default"
ng-click="build_ip_timeline(86400)"
ng-disabled="!is_ready()">Timeline (24h)</button>
</div>
</li>
</ul>
</div>
</div>
</div>
<div class="row" style="padding-top: 10px">
<div class="col-sm-12 col-md-6">
<div id="chart1" class="chart" style="display: none;">
<div>
<center>
<span name="charttitle"></span>
<i class="icon-remove clickable"
onclick="hidecharts();"></i>
</center>
</div>
<div name="chartcontent"></div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div id="chart2" class="chart" style="display: none;">
<div>
<center>
<span name="charttitle"></span>
<i class="icon-remove clickable"
onclick="hidecharts();"></i>
</center>
</div>
<div name="chartcontent"></div>
</div>
</div>
</div>
</div>
</body>
</html>
25 changes: 25 additions & 0 deletions web/static/ivre/compare.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
var ALL_SETS;

function init_compare() {
if(!(wait_filter(init_compare)))
return;

sync_hash_filter(FILTER)

window.onhashchange();
//var all_sets = [];
for(name in FILTERS) {
if(name.substr(0, 3) === "set") {
var filter = FILTERS[name];
filter.on_query_update();
//all_sets.push(filter);
}
}
// FIXME work w/ arbitrary number of sets
ALL_SETS = new SubFilter("all_sets", FILTERS.set1, FILTERS.set2);
var scope = get_scope("IvreCompareCtrl");
scope.$apply(function() {
scope.all_sets = ALL_SETS;
});
ALL_SETS.need_apply.push(scope);
}
87 changes: 84 additions & 3 deletions web/static/ivre/controllers.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,19 @@ ivreWebUi
templateUrl: 'templates/filters.html',
link: function(scope, elem, attrs) {
scope.title = attrs.title;
scope.filter = new Filter(attrs.name);
switch(attrs.parent) {
case undefined:
scope.filter = new Filter(attrs.name);
break;
case "":
scope.filter = new SubFilter(attrs.name, FILTER);
break;
default:
scope.filter = new SubFilter(attrs.name,
FILTERS[attrs.parent]);
}
scope.filter.scope = scope;
scope.parametersprotected = scope.filter.parametersprotected;
scope.idprefix = attrs.name ? attrs.name + "-" : "";
scope.clear_and_submit = function(index) {
scope.parametersprotected[index] = "";
Expand Down Expand Up @@ -769,7 +780,7 @@ ivreWebUi
});

ivreWebUi
.controller('IvreDiffCtrl', function ($scope) {
.controller('IvreCompareCtrl', function ($scope) {
$scope.all_filters = [];
$scope.apply_on_filter_update = [$scope];
$scope.names = {
Expand All @@ -787,5 +798,75 @@ ivreWebUi
}
}
return true;
}
};
$scope.build_ip_plane = function() {
var totalnbrres, filter, i = 1;
hidecharts();
for(var name in FILTERS) {
if(name.substr(0, 3) === "set") {
filter = FILTERS[name];
totalnbrres = filter.count;
if(totalnbrres === undefined)
return;
if(totalnbrres < config.warn_dots_count || confirm("You are about to ask your browser to display " + totalnbrres + " dots, which is a lot and might slow down, freeze or crash your browser. Do you want to continue?")) {
new GraphPlane($("#chart" + i++), filter.query)
.build();
}
}
}
};
$scope.build_ip_map = function() {
var i = 1;
hidecharts();
for(var name in FILTERS) {
if(name.substr(0, 3) === "set")
new GraphMap($("#chart" + i++),
FILTERS[name].query)
.build();
}
};
$scope.build_ip_timeline = function(modulo) {
var totalnbrres, filter, i = 1;
hidecharts();
for(var name in FILTERS) {
if(name.substr(0, 3) === "set") {
filter = FILTERS[name];
totalnbrres = filter.count;
if(totalnbrres === undefined)
return;
if(totalnbrres < config.warn_dots_count || modulo !== undefined || confirm("You are about to ask your browser to display " + totalnbrres + " dots, which is a lot and might slow down, freeze or crash your browser. Do you want to continue?")) {
new GraphTimeline($("#chart" + i++),
filter.query, modulo)
.build();
}
}
}
};
$scope.build_ip_ports = function() {
var totalnbrres, filter, i = 1;
hidecharts();
for(var name in FILTERS) {
if(name.substr(0, 3) === "set") {
filter = FILTERS[name];
totalnbrres = filter.count;
if(totalnbrres === undefined)
return;
if(totalnbrres < config.warn_dots_count || confirm("You are about to ask your browser to display " + totalnbrres + " dots, which is a lot and might slow down, freeze or crash your browser. Do you want to continue?")) {
new GraphIpPort($("#chart" + i++), filter.query)
.build();
}
}
}
};
$scope.build_top_chart = function() {
var i = 1;
hidecharts();
for(var name in FILTERS) {
if(name.substr(0, 3) === "set")
new GraphTopValues($("#chart" + i++),
FILTERS[name].query,
$scope.topvaluesfield, 10)
.build();
}
};
});
54 changes: 54 additions & 0 deletions web/static/ivre/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,57 @@ var Filter = (function() {

return Filter;
})();

var SubFilter = (function(_super) {

/*
* Special filter that includes the intersection of other filters
*/

function SubFilter(name) {
var args = Array.from(arguments)
_super.call(this, args.shift());
this.children = args;
this._query = "";
var parent = this;
for(var i in this.children) {
var child = this.children[i];
var index = i;
child.add_callback("post_get_results", function() {
// force parent update
parent.prev_query = {"thiswillneverexist": []};
parent.on_param_update();
});
}
};

$.extend(SubFilter.prototype, _super.prototype, {
set_full_query: function() {
if(this.query) {
this.query += " ";
}
this.query += this.children
.map(function(p) {return p.query;})
.filter(function(p) {return p;})
.join(" ");
this.on_query_update();
},

on_param_update: function() {
if(this.scope) {
this.scope.parametersprotected.push(this.scope.lastfiltervalue);
this.scope.lastfiltervalue = "";
this.query = this.scope.parametersprotected
.filter(function(p){return p;})
.join(" ");
}
else
this.query = "";
load_params(this);
this.set_full_query();
this._call_callbacks(this.callbacks.param_update, this.query);
}
});

return SubFilter;
})(Filter);
3 changes: 3 additions & 0 deletions web/static/templates/menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@
<li ng-if="MENU.share_report"><a href="#" onclick="document.location = getPagePath() + 'report.html' + document.location.hash">
<i class="glyphicon glyphicon-th-list"></i> Report
</a></li>
<li><a href="#" onclick="document.location = getPagePath() + 'compare.html' + document.location.hash">
<i class="glyphicon glyphicon-stats"></i> Compare graphs
</a></li>
<li ng-if="MENU.share_htmlexport"><a href="#" onclick="download_blob(exportDOM(), 'ivre_' + getPageName() + '_' + get_hash().replace(' ', '_'))">
<i class="glyphicon glyphicon-export"></i> HTML export
</a></li>
Expand Down

0 comments on commit 81ee3e2

Please sign in to comment.