269 lines
7.2 KiB
HTML
269 lines
7.2 KiB
HTML
{% extends 'template.html' %}
|
|
{% load staticfiles %}
|
|
|
|
{% block title %}Tempest: Execution Timeline (run #{{run_id}}){% endblock %}
|
|
|
|
{% block head-extra %}
|
|
<style>
|
|
#timeline-info table {
|
|
table-layout: fixed;
|
|
width: 100%;
|
|
word-wrap: break-word
|
|
}
|
|
|
|
#timeline-info table td:nth-child(1) {
|
|
width: 20%;
|
|
}
|
|
|
|
#timeline-log pre {
|
|
overflow-x: scroll;
|
|
white-space: nowrap;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block body %}
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<h1 class="page-header">Tempest: Execution Timeline (run #{{run_id}})</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading">
|
|
<i class="fa fa-clock-o fa-fw"></i> Timeline
|
|
<div class="pull-right">
|
|
<div class="btn-group">
|
|
<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
|
|
View Run...
|
|
<span class="caret"></span>
|
|
</button>
|
|
<ul class="dropdown-menu pull-right" role="menu">
|
|
{% for run_id in tempest_runs %}
|
|
<li><a href="tempest_timeline_{{run_id}}.html">Run #{{run_id}}</a></li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="timeline-container" class="panel-body">
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading">
|
|
<i class="fa fa-info fa-fw"></i> Info
|
|
</div>
|
|
|
|
<div id="timeline-info" class="panel-body">
|
|
<em>Mouse over an item to view info.</em>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-12">
|
|
<div class="panel panel-default">
|
|
<div class="panel-heading">
|
|
<i class="fa fa-file-text fa-fw"></i> Log Output
|
|
</div>
|
|
|
|
<div id="timeline-details" class="panel-body">
|
|
<em>Click an item to view log details.</em>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="{% static 'js/timeline.js' %}"></script>
|
|
<script>
|
|
var originalInfoContent = null;
|
|
var originalDetailsContent = null;
|
|
|
|
var detailsCache = null;
|
|
var detailsInProgress = false;
|
|
var detailsWaiting = [];
|
|
|
|
var showInfo = function(item) {
|
|
var parent = $("#timeline-info");
|
|
if (originalInfoContent === null) {
|
|
originalInfoContent = parent.html();
|
|
}
|
|
|
|
var e = $("<table>", {
|
|
"class": 'table table-bordered table-hover table-striped'
|
|
});
|
|
|
|
var nameParts = item.name.split(".");
|
|
var pkg = nameParts.slice(0, nameParts.length - 2).join('.');
|
|
|
|
e.append($("<tr>")
|
|
.append($("<td>", { text: 'Name' }))
|
|
.append($("<td>", { text: nameParts[nameParts.length - 1] })));
|
|
|
|
e.append($("<tr>")
|
|
.append($("<td>", { text: 'Class' }))
|
|
.append($("<td>", { text: nameParts[nameParts.length - 2] })));
|
|
|
|
e.append($("<tr>")
|
|
.append($("<td>", { text: 'Module' }))
|
|
.append($("<td>", { text: pkg })));
|
|
|
|
e.append($("<tr>")
|
|
.append($("<td>", { text: 'Status' }))
|
|
.append($("<td>", { text: item.status })));
|
|
|
|
e.append($("<tr>")
|
|
.append($("<td>", { text: 'Tags' }))
|
|
.append($("<td>", { text: item.tags.join(", ") })));
|
|
|
|
e.append($("<tr>")
|
|
.append($("<td>", { text: 'Duration' }))
|
|
.append($("<td>", { text: item.duration + " seconds" })));
|
|
|
|
parent.empty();
|
|
e.appendTo(parent);
|
|
};
|
|
|
|
var hideInfo = function() {
|
|
$("#timeline-info").html(originalInfoContent);
|
|
};
|
|
|
|
var loadDetails = function(callback) {
|
|
if (detailsCache === null) {
|
|
detailsWaiting.push(callback);
|
|
|
|
if (!detailsInProgress) {
|
|
var url = "tempest_api_details_{{run_id}}.json";
|
|
if ("{{use_gzip}}" === "True") {
|
|
url += ".gz";
|
|
}
|
|
|
|
detailsInProgress = true;
|
|
|
|
d3.json(url, function(error, data) {
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
|
|
detailsCache = data;
|
|
detailsWaiting.forEach(function(cb) {
|
|
cb(detailsCache);
|
|
});
|
|
});
|
|
}
|
|
} else {
|
|
callback(detailsCache);
|
|
}
|
|
};
|
|
|
|
var showDetails = function(item) {
|
|
var parent = $("#timeline-details");
|
|
|
|
showInfo(item);
|
|
|
|
loadDetails(function(details) {
|
|
if (!details.hasOwnProperty(item.name)) {
|
|
console.log("Details not found for item:", item.name);
|
|
return;
|
|
}
|
|
|
|
if (originalDetailsContent === null) {
|
|
originalDetailsContent = parent.html();
|
|
}
|
|
|
|
parent.empty();
|
|
for (var prop in details[item.name]) {
|
|
$("<h3>").text(prop).appendTo(parent);
|
|
$("<pre>").text(details[item.name][prop]).appendTo(parent);
|
|
}
|
|
});
|
|
};
|
|
|
|
var hideDetails = function() {
|
|
$("#timeline-details").html(originalDetailsContent);
|
|
};
|
|
|
|
window.addEventListener('load', function() {
|
|
var selectedItem = null;
|
|
var selectedValue = null;
|
|
|
|
var url = "tempest_api_raw_{{run_id}}.json";
|
|
if ("{{use_gzip}}" === "True") {
|
|
url += ".gz";
|
|
}
|
|
|
|
loadTimeline(url, {
|
|
container: $("#timeline-container")[0],
|
|
onClick: function(d) {
|
|
var self = d3.select(this);
|
|
|
|
// deselect old item, if any
|
|
if (selectedItem !== null) {
|
|
if (selectedItem.attr("data-old-fill")) {
|
|
selectedItem.attr("fill", selectedItem.attr("data-old-fill"));
|
|
selectedItem.attr("data-old-fill", null);
|
|
}
|
|
|
|
if (selectedValue.name === d.name) {
|
|
// remove selection on 2nd click - don't continue
|
|
selectedItem = null;
|
|
selectedValue = null;
|
|
hideDetails();
|
|
return;
|
|
}
|
|
|
|
selectedItem = null;
|
|
}
|
|
|
|
// select new item
|
|
if (!self.attr("data-old-fill")) {
|
|
self.attr("data-old-fill", self.attr("fill"));
|
|
}
|
|
|
|
self.attr("fill", "goldenrod");
|
|
selectedItem = self;
|
|
selectedValue = d;
|
|
|
|
showDetails(d);
|
|
},
|
|
|
|
onMouseover: function(d) {
|
|
if (selectedItem !== null) {
|
|
return;
|
|
}
|
|
|
|
var self = d3.select(this);
|
|
if (!self.attr("data-old-fill")) {
|
|
self.attr("data-old-fill", self.attr("fill"));
|
|
}
|
|
|
|
d3.select(this).attr("fill", "darkturquoise");
|
|
|
|
showInfo(d);
|
|
},
|
|
|
|
onMouseout: function(d) {
|
|
if (selectedItem !== null) {
|
|
return;
|
|
}
|
|
|
|
var self = d3.select(this);
|
|
if (self.attr("data-old-fill")) {
|
|
self.attr("fill", self.attr("data-old-fill"));
|
|
self.attr("data-old-fill", null);
|
|
}
|
|
|
|
hideInfo();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|