First commit of the prototype
This commit is contained in:
Коммит
510ac00274
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -0,0 +1,240 @@
|
|||
var crashes;
|
||||
var tableOptions = {
|
||||
'oom': false,
|
||||
'shutdownhang': false,
|
||||
'flash': false,
|
||||
'hideResolved': false,
|
||||
'graphType': null,
|
||||
};
|
||||
|
||||
var onLoad = new Promise(function(resolve, reject) {
|
||||
window.onload = resolve;
|
||||
});
|
||||
|
||||
var loadCrashes = fetch('crashes.json')
|
||||
.then(function(response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function(val) {
|
||||
crashes = val;
|
||||
console.log(crashes);
|
||||
});
|
||||
|
||||
function agoString(val, str) {
|
||||
return val + ' ' + (val == 1 ? str : str + 's') + ' ago';
|
||||
}
|
||||
|
||||
function prettyDate(date) {
|
||||
date = new Date(date);
|
||||
let today = new Date();
|
||||
|
||||
var hoursDiff = Math.round((today.getTime() - date.getTime()) / 3600000);
|
||||
if (hoursDiff < 24) {
|
||||
return agoString(hoursDiff, 'hour');
|
||||
}
|
||||
|
||||
var daysDiff = Math.round((today.getTime() - date.getTime()) / 86400000);
|
||||
if (daysDiff < 10) {
|
||||
return agoString(daysDiff, 'day');
|
||||
}
|
||||
|
||||
var weeksDiff = Math.round((today.getTime() - date.getTime()) / (7 * 86400000));
|
||||
if (weeksDiff < 3) {
|
||||
return agoString(weeksDiff, 'week');
|
||||
}
|
||||
|
||||
var monthsDiff = (today.getMonth() + 12 * today.getFullYear()) - (date.getMonth() + 12 * date.getFullYear());
|
||||
if (monthsDiff < 12) {
|
||||
return agoString(monthsDiff, 'month');
|
||||
}
|
||||
|
||||
return agoString(today.getFullYear() - date.getFullYear(), 'year');
|
||||
}
|
||||
|
||||
function createGraph(data) {
|
||||
let startDay = data.find(d => d == null) === undefined ? 1 : 2;
|
||||
data = data.filter(d => d != null);
|
||||
|
||||
var margin = {top: 20, right: 20, bottom: 30, left: 50},
|
||||
width = 700 - margin.left - margin.right,
|
||||
height = 200 - margin.top - margin.bottom;
|
||||
|
||||
var x = d3.time.scale()
|
||||
.range([0, width]);
|
||||
|
||||
var y = d3.scale.linear()
|
||||
.range([height, 0]);
|
||||
|
||||
var xAxis = d3.svg.axis()
|
||||
.scale(x)
|
||||
.tickFormat(d3.time.format('%d'))
|
||||
.ticks(data.length)
|
||||
.orient('bottom');
|
||||
|
||||
var yAxis = d3.svg.axis()
|
||||
.scale(y)
|
||||
.orient('left');
|
||||
|
||||
var line = d3.svg.line()
|
||||
.x(function(d, i) {
|
||||
var date = new Date();
|
||||
date.setHours(0, 0, 0, 0);
|
||||
date.setDate(date.getDate() - startDay - i);
|
||||
return x(date);
|
||||
})
|
||||
.y(function(d, i) { return y(d); });
|
||||
|
||||
var svgElem = document.createElementNS(d3.ns.prefix.svg, 'svg');
|
||||
var svg = d3.select(svgElem)
|
||||
.attr('width', width + margin.left + margin.right)
|
||||
.attr('height', height + margin.top + margin.bottom)
|
||||
.append('g')
|
||||
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
|
||||
|
||||
x.domain(d3.extent(data, function(d, i) {
|
||||
var date = new Date();
|
||||
date.setHours(0, 0, 0, 0);
|
||||
date.setDate(date.getDate() - startDay - i);
|
||||
return date;
|
||||
}));
|
||||
|
||||
y.domain([0, d3.max(data, function(d) { return d; })]);
|
||||
|
||||
svg.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', 'translate(0,' + height + ')')
|
||||
.call(xAxis);
|
||||
|
||||
svg.append('g')
|
||||
.attr('class', 'y axis')
|
||||
.call(yAxis);
|
||||
|
||||
svg.append('path')
|
||||
.attr('class', 'line')
|
||||
.attr('d', line(data));
|
||||
|
||||
return svgElem;
|
||||
}
|
||||
|
||||
function addRow(signature, obj) {
|
||||
var table = document.getElementById('table');
|
||||
|
||||
var row = table.insertRow(table.rows.length);
|
||||
|
||||
var rank = row.insertCell(0);
|
||||
rank.appendChild(document.createTextNode(obj.tc_rank));
|
||||
|
||||
var key = row.insertCell(1);
|
||||
|
||||
if (!obj.startup_crash) {
|
||||
var startupImage = document.createElement('img');
|
||||
startupImage.title = (obj.startup_percent * 100).toFixed(2) + ' %';
|
||||
startupImage.src = 'rocket_fly.png';
|
||||
startupImage.width = 64 * obj.startup_percent;
|
||||
startupImage.height = 64 * obj.startup_percent;
|
||||
startupImage.style.paddingRight = 5;
|
||||
key.appendChild(startupImage);
|
||||
}
|
||||
|
||||
let signatureLink = document.createElement('a');
|
||||
signatureLink.appendChild(document.createTextNode(signature.length > 50 ? signature.substr(0, 49) + '…' : signature));
|
||||
signatureLink.href = 'https://crash-stats.mozilla.com/signature/?date=<%3D' + crashes.end_date + '&date=>%3D' + crashes.start_date + '&product=Firefox&' + crashes.versions.map(version => 'version=' + version).join('&') + '&signature=' + signature;
|
||||
key.appendChild(signatureLink);
|
||||
|
||||
let today = new Date();
|
||||
let three_days_ago = new Date().setDate(today.getDate() - 3);
|
||||
let ten_days_ago = new Date().setDate(today.getDate() - 10);
|
||||
let bugs = row.insertCell(2);
|
||||
obj.bugs
|
||||
.filter(bug => !tableOptions['hideResolved'] || bug.resolution == '')
|
||||
.sort((bug1, bug2) => new Date(bug2.last_change_time) - new Date(bug1.last_change_time))
|
||||
.forEach(function(bug) {
|
||||
let bugLink = document.createElement('a');
|
||||
bugLink.appendChild(document.createTextNode(bug.id));
|
||||
bugLink.title = (bug.resolution ? bug.resolution + ' - ' : '') + 'Last activity: ' + prettyDate(bug.last_change_time);
|
||||
bugLink.href = 'https://bugzilla.mozilla.org/show_bug.cgi?id=' + bug.id;
|
||||
bugLink.className = bug.resolution != '' ? 'resolved' : '';
|
||||
|
||||
let bugDate = new Date(bug.last_change_time);
|
||||
if (bugDate > three_days_ago) {
|
||||
bugLink.style.color = 'green';
|
||||
} else if (bugDate > ten_days_ago) {
|
||||
bugLink.style.color = 'orange';
|
||||
} else {
|
||||
bugLink.style.color = 'red';
|
||||
}
|
||||
|
||||
bugs.appendChild(bugLink);
|
||||
bugs.appendChild(document.createTextNode(' '));
|
||||
});
|
||||
|
||||
let graph = row.insertCell(3);
|
||||
if (tableOptions['graphType'] === 'Crashes per usage hours') {
|
||||
graph.appendChild(createGraph(obj.crash_stats_per_mega_hours));
|
||||
} else if (tableOptions['graphType'] === 'Crashes per ADI') {
|
||||
graph.appendChild(createGraph(obj.crash_stats_per_mega_adi));
|
||||
} else {
|
||||
graph.appendChild(createGraph(obj.crash_by_day));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function buildTable() {
|
||||
// Order signatures by rank change or kairo's explosiveness.
|
||||
Object.keys(crashes.signatures)
|
||||
.sort((signature1, signature2) => crashes.signatures[signature1].tc_rank - crashes.signatures[signature2].tc_rank)
|
||||
.forEach(function(signature) {
|
||||
if (!tableOptions['oom'] && signature.toLowerCase().includes('oom')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tableOptions['shutdownhang'] && signature.toLowerCase().includes('shutdownhang')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tableOptions['flash'] && signature.match(/F_?[0-9]{10}_+/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
addRow(signature, crashes.signatures[signature]);
|
||||
});
|
||||
}
|
||||
|
||||
function rebuildTable() {
|
||||
while(table.rows.length > 1) {
|
||||
table.deleteRow(table.rows.length - 1);
|
||||
}
|
||||
|
||||
buildTable();
|
||||
}
|
||||
|
||||
onLoad
|
||||
.then(function() {
|
||||
Object.keys(tableOptions)
|
||||
.forEach(function(option) {
|
||||
var elem = document.getElementById(option);
|
||||
tableOptions[option] = elem.checked;
|
||||
|
||||
elem.onchange = function() {
|
||||
tableOptions[option] = elem.checked;
|
||||
rebuildTable();
|
||||
};
|
||||
});
|
||||
|
||||
var graphType = document.getElementById('graphType');
|
||||
tableOptions['graphType'] = graphType.options[graphType.selectedIndex].value;
|
||||
|
||||
graphType.onchange = function() {
|
||||
tableOptions['graphType'] = graphType.options[graphType.selectedIndex].value;
|
||||
rebuildTable();
|
||||
};
|
||||
})
|
||||
.then(function() {
|
||||
return loadCrashes;
|
||||
})
|
||||
.then(function() {
|
||||
buildTable();
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error(err);
|
||||
});
|
|
@ -0,0 +1,30 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>Stability Dashboard</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script src="https://d3js.org/d3.v3.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script src="dash.js"></script>
|
||||
<input type="checkbox" name="oom" id="oom"><label for="oom">Show OOM crashes</label>
|
||||
<input type="checkbox" name="shutdownhang" id="shutdownhang"><label for="shutdownhang">Show shutdownhang crashes</label>
|
||||
<input type="checkbox" name="flash" id="flash"><label for="flash">Show Flash-related crashes</label>
|
||||
<input type="checkbox" name="hideResolved" id="hideResolved"><label for="hideResolved">Hide RESOLVED bugs</label>
|
||||
<br><br>
|
||||
<label for="graphType">Graph type:</label>
|
||||
<select name="graphType" id="graphType">
|
||||
<option selected>Crashes per usage hours</option>
|
||||
<option>Crashes per ADI</option>
|
||||
<option>Raw number of crashes</option>
|
||||
</select>
|
||||
<table id="table">
|
||||
<tr>
|
||||
<th>Rank</th>
|
||||
<th>Signature</th>
|
||||
<th>Bug(s)</th>
|
||||
<th>Evolution</th>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 531 B |
|
@ -0,0 +1,39 @@
|
|||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 8px;
|
||||
padding-top: 40px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 2px solid #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.resolved {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.axis path,
|
||||
.axis line {
|
||||
fill: none;
|
||||
stroke: #000;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
|
||||
.x.axis path {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.line {
|
||||
fill: none;
|
||||
stroke: steelblue;
|
||||
stroke-width: 1.5px;
|
||||
}
|
Загрузка…
Ссылка в новой задаче