Introduce daily bug stats chart

This commit introduces daily bug stats graphs. To do this, this commit
also introduces nvd3 js library for enabling to use lineWithFocusChart.
It is not same style chart of the main pages ones. Because
stackedAreaWithFocusChart is a little bit buggy. So it sometimes shows
wrong charts. And I also think lineWithFocusChart is better than the
stackedArea chart because it is simple enough to understand the trend.

Change-Id: Iacf22cddbd676d1447cfd9ae8ba1e7ce387720f6
This commit is contained in:
Masayuki Igawa 2016-09-19 15:58:10 +02:00 committed by Sean McGinnis
parent b5f3d037ca
commit f10ee2d6bd
9 changed files with 135 additions and 6 deletions

View File

@ -25,23 +25,33 @@ from jinja2 import FileSystemLoader
from launchpadlib.launchpad import Launchpad
def create_files(templatepath, outputpath, projects):
def create_files(templatepath, outputpath, projects, config):
# Create index file
env = Environment(loader=FileSystemLoader(templatepath))
indexfile = os.path.join(outputpath, "index.html")
template = env.get_template('index.html')
daily = config.get('daily')
template.stream(projects=projects,
openstack_status=openstack_status).dump(indexfile)
openstack_status=openstack_status,
daily=daily).dump(indexfile)
# Create each project file
for project in projects:
projectfile = os.path.join(outputpath, "%s.html" % project['project'])
if 'height' in project:
project['height'] = project['height'] - 30
projectfile = os.path.join(outputpath,
"%s.html" % project['project'])
if not os.path.exists(projectfile):
if 'height' in project:
project['height'] = project['height'] - 30
template = env.get_template('project.html')
template.stream(project=project).dump(projectfile)
if daily:
projectfile = os.path.join(outputpath,
"%s-daily.html" % project['project'])
if not os.path.exists(projectfile):
template = env.get_template('project-daily.html')
template.stream(project=project).dump(projectfile)
def update_stats(outputpath, project_name, rotation, daily=False):
@ -175,7 +185,7 @@ if __name__ == '__main__':
openstack_status = config.get('openstack_status')
# Create files in output directory, if needed
create_files(templatepath, outputpath, projects)
create_files(templatepath, outputpath, projects, config)
# Refresh JSON stats files
launchpad = Launchpad.login_anonymously('bugdaystats', 'production',

5
output/js/d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

2
output/js/nv.d3.min.css vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"version":3,"sources":["build/nv.d3.css"],"names":[],"mappings":"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"}

11
output/js/nv.d3.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,41 @@
function convData(jsondata) {
var newEnt = [];
var criticalEnt = [];
var highEnt = [];
var inProgEnt = [];
var totalOpen = [];
var records = jsondata['records'];
for (ent in records) {
console.debug(records[ent]);
var xval = records[ent]['date'] * 1000;
newEnt.push({
x: xval,
y: records[ent]['new']
});
criticalEnt.push({
x: xval,
y: records[ent]['critical']
});
highEnt.push({
x: xval,
y: records[ent]['high']
});
inProgEnt.push({
x: xval,
y: records[ent]['inprogress']
});
totalOpen.push({
x: xval,
y: records[ent]['new']+records[ent]['incomplete']+records[ent]['inprogress']+records[ent]['confirmed']+records[ent]['triaged']
});
}
var bugsData = [
{ key: 'New', values: newEnt, area: false, type: 'line', color: 'pink' },
{ key: 'Critical', values: criticalEnt, area: false, type: 'line', color: 'red'},
{ key: 'High', values: highEnt, area: false, type: 'line', color: 'orange'},
{ key: 'In Progress', values: inProgEnt, area: false, type: 'line', color: 'skyblue'},
{ key: 'Total Open', values: totalOpen, area: false, type: 'line', color: 'lightgreen'}
];
return bugsData;
}

View File

@ -43,6 +43,12 @@
<a href="{{ project.project }}-bug-stats.json">
JSON FILE
</a>
{% if daily %}
&nbsp;/ <a href="{{ project.project }}-daily.html">Daily Stats</a> / <a href="{{ project.project }}-bug-stats-daily.json">
JSON FILE(DAILY)
</a>
{% endif %}
</td>
</tr>
{% endfor %}

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf8" http-equiv="Content-Type"/>
<title>
{{ project.project|capitalize }} Bug Trend
</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.min.js" charset="utf-8">
</script>
<script language="javascript" src="js/nv.d3.min.js"></script>
<link href="js/nv.d3.min.css" rel="stylesheet" type="text/css">
<style>
html, body, #chart, svg {
margin: 0px;
padding: 0px;
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="{{ project.project }}" style="width:100%;height:100%;">
<svg></svg>
</div>
<script language="javascript" src="js/package-triaging-daily.js"></script>
<script type="text/javascript">
var testdata;
d3.json("{{ project.project }}-bug-stats-daily.json", function(error, dataSet){
if(error) return console.warn(error);
nv.addGraph(function() {
var chart = nv.models.lineWithFocusChart();
chart.xAxis.tickFormat(function(d) { return d3.time.format('%m/%d')(new Date(d)); });
chart.x2Axis.tickFormat(function(d) { return d3.time.format('%m/%d')(new Date(d)); });
chart.forceY([0]);
d3.select("#{{ project.project }} svg")
.datum(convData(dataSet))
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
});
</script>
</body>
</html>