Add tooltip for URLs

pull/14/merge
Raphaël Vinot 2017-10-04 15:13:42 +02:00
parent 678985c94a
commit 0ac38a0f2c
3 changed files with 116 additions and 7 deletions

View File

@ -6,15 +6,23 @@ import json
from har2tree import CrawledTree
from scrapysplashwrapper import crawl
from flask import Flask, render_template, request
from flask import Flask, render_template, request, session
from flask_bootstrap import Bootstrap
from glob import glob
import os
from datetime import datetime
import pickle
import tempfile
app = Flask(__name__)
app.secret_key = 'changeme'
if app.secret_key == 'changeme':
raise Exception('FFS, please set a proper secret key...')
Bootstrap(app)
app.config['BOOTSTRAP_SERVE_LOCAL'] = True
app.debug = True
@ -23,11 +31,25 @@ HAR_DIR = 'scraped'
SPLASH = 'http://127.0.0.1:8050'
@app.before_request
def session_management():
# make the session last indefinitely until it is cleared
session.permanent = True
def load_tree(report_dir):
if session.get('tree'):
# TODO delete file
pass
session.clear()
har_files = sorted(glob(os.path.join(HAR_DIR, report_dir, '*.har')))
ct = CrawledTree(har_files)
ct.find_parents()
ct.join_trees()
temp = tempfile.NamedTemporaryFile(delete=False)
pickle.dump(ct, temp)
temp.close()
session["tree"] = temp.name
return ct.jsonify(), ct.start_time.isoformat(), ct.user_agent, ct.root_url
@ -63,6 +85,25 @@ def get_report_dirs():
return sorted(os.listdir(HAR_DIR), reverse=True)
@app.route('/tree/hostname/<node_uuid>', methods=['GET'])
def hostnode_details(node_uuid):
with open(session["tree"], 'rb') as f:
ct = pickle.load(f)
hostnode = ct.root_hartree.get_host_node_by_uuid(node_uuid)
urls = []
for url in hostnode.urls:
urls.append(url.jsonify())
return json.dumps(urls)
@app.route('/tree/url/<node_uuid>', methods=['GET'])
def urlnode_details(node_uuid):
with open(session["tree"], 'rb') as f:
ct = pickle.load(f)
urlnode = ct.root_hartree.get_url_node_by_uuid(node_uuid)
return urlnode.jsonify()
@app.route('/tree/<int:tree_id>', methods=['GET'])
def tree(tree_id):
report_dir = get_report_dirs()[tree_id]

View File

@ -49,3 +49,24 @@
padding-bottom: 5px;
padding-left: 5px;
}
.tooltip {
position: absolute;
text-align: left;
padding: 2px;
font: 12px sans-serif;
background: lightsteelblue;
border: 0px;
border-radius: 8px;
z-index: 1;
border: 2px solid;
padding-top: 5px;
padding-right: 5px;
padding-bottom: 5px;
padding-left: 5px;
}
.tooltip text {
font: 15px sans-serif;
z-index: 2;
}

View File

@ -6,7 +6,11 @@ var margin = {top: 20, right: 200, bottom: 30, left: 90},
height = 10000 - margin.top - margin.bottom;
var node_width = 0;
var node_height = 35;
var node_height = 45;
var hostnode_tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var init = d3.select("body").append("svg")
.attr("width", width + margin.right + margin.left)
@ -29,7 +33,12 @@ var background = init.append('rect')
.attr('y', 0)
.attr('width', width)
.attr('height', height)
.style('fill', "url(#backstripes)");
.style('fill', "url(#backstripes)")
.on('click', function(d) {
hostnode_tooltip.transition()
.duration(500)
.style("opacity", 0);
});
// append the svg object to the body of the page
// appends a 'group' element to 'svg'
@ -71,6 +80,41 @@ function getBB(selection) {
})
}
function urlnode_click(uuid) {
var url = "url/" + uuid;
d3.json(url, function(error, u) {
if (error) throw error;
console.log(u)
})
}
function hostnode_click(d) {
// Modal display
var url = "hostname/" + d.data.uuid;
var pageX=d3.event.pageX;
var pageY=d3.event.pageY;
hostnode_tooltip.selectAll("ul").remove();
d3.json(url, function(error, urls) {
if (error) throw error;
hostnode_tooltip.transition()
.duration(200)
.style("opacity", .9)
.style("left", (pageX) + "px")
.style("top", (pageY - 28) + "px");
var list = hostnode_tooltip.append('ul')
.attr("class", "list-group");
urls.forEach(function(url){
jdata = JSON.parse(url)
var entry = list.append('li')
.attr("class", "list-group-item")
.attr("url_uuid", jdata['uuid'])
.text(jdata['name'])
.on('click', urlnode_click(jdata['uuid']));
})
});
}
function update(source) {
// reinitialize max_depth
@ -101,8 +145,7 @@ function update(source) {
.attr('class', 'node')
.attr("transform", function(d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.on('click', click);
});
// Add Circle for the nodes
nodeEnter.append('circle')
@ -110,11 +153,13 @@ function update(source) {
.attr('r', 1e-6)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
})
.on('click', click);
// Avoid hiding the content after the circle
var nodeContent = nodeEnter
.append('svg')
.attr('height',node_height)
.attr('x', 10)
.attr('y', -20);
@ -128,7 +173,8 @@ function update(source) {
.text(function(d) {
d.data.total_width = 0; // reset total_width
return d.data.name;
});
})
.on('click', hostnode_click);
// This value has to be set once for all for the whole tree and cannot be updated
// on click as clicking only updates a part of the tree
@ -361,4 +407,5 @@ function update(source) {
}
update(d);
}
}