stackviz/stackviz/templates/tempest/timeline.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 %}