Skip to content

Commit f651320

Browse files
author
Sasha Romijn
committed
Fix ietf-tools#2331 - Show stacked bar graph for in time and late reviews.
On the stats page, a single stacked bar graph is now shown which combines in time and late reviews, replacing the separate graphs for these statistics. Tests for the charts are also expanded to validate the actual graph content for both stacked and non-stacked charts. Commit ready for merge. - Legacy-Id: 16852
1 parent e145832 commit f651320

4 files changed

Lines changed: 53 additions & 16 deletions

File tree

ietf/externals/static/flot/jquery.flot.stack.min.js

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ietf/stats/tests.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
from __future__ import absolute_import, print_function, unicode_literals
66

7+
import calendar
78
import datetime
9+
import json
810

911
from mock import patch
1012
from pyquery import PyQuery
@@ -197,11 +199,27 @@ def test_review_stats(self):
197199
if stats_type != "results":
198200
self.assertTrue(q('.review-stats td:contains("1")'))
199201

200-
# check chart
202+
# check stacked chart
203+
expected_date = datetime.date.today().replace(day=1)
204+
expected_js_timestamp = calendar.timegm(expected_date.timetuple()) * 1000
201205
url = urlreverse(ietf.stats.views.review_stats, kwargs={ "stats_type": "time" })
202206
url += "?team={}".format(review_req.team.acronym)
203207
r = self.client.get(url)
204208
self.assertEqual(r.status_code, 200)
209+
self.assertEqual(json.loads(r.context['data']), [
210+
{"label": "in time", "color": "#3d22b3", "data": [[expected_js_timestamp, 0]]},
211+
{"label": "late", "color": "#b42222", "data": [[expected_js_timestamp, 0]]}
212+
])
213+
q = PyQuery(r.content)
214+
self.assertTrue(q('.stats-time-graph'))
215+
216+
# check non-stacked chart
217+
url = urlreverse(ietf.stats.views.review_stats, kwargs={ "stats_type": "time" })
218+
url += "?team={}".format(review_req.team.acronym)
219+
url += "&completion=not_completed"
220+
r = self.client.get(url)
221+
self.assertEqual(r.status_code, 200)
222+
self.assertEqual(json.loads(r.context['data']), [{"color": "#3d22b3", "data": [[expected_js_timestamp, 0]]}])
205223
q = PyQuery(r.content)
206224
self.assertTrue(q('.stats-time-graph'))
207225

ietf/stats/views.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1175,8 +1175,7 @@ def time_key_fn(t):
11751175
# choice
11761176

11771177
possible_completion_types = add_url_to_choices([
1178-
("completed_in_time", "Completed in time"),
1179-
("completed_late", "Completed late"),
1178+
("completed_in_time_or_late", "Completed (in time or late)"),
11801179
("not_completed", "Not completed"),
11811180
("average_assignment_to_closure_days", "Avg. compl. days"),
11821181
], lambda slug: build_review_stats_url(get_overrides={ "completion": slug, "result": None, "state": None }))
@@ -1198,25 +1197,37 @@ def time_key_fn(t):
11981197
selected_state = get_choice(request, "state", possible_states)
11991198

12001199
if not selected_completion_type and not selected_result and not selected_state:
1201-
selected_completion_type = "completed_in_time"
1202-
1203-
series_data = []
1200+
selected_completion_type = "completed_in_time_or_late"
1201+
1202+
standard_color = '#3d22b3'
1203+
if selected_completion_type == 'completed_in_time_or_late':
1204+
graph_data = [
1205+
{'label': 'in time', 'color': standard_color, 'data': []},
1206+
{'label': 'late', 'color': '#b42222', 'data': []}
1207+
]
1208+
else:
1209+
graph_data = [{'color': standard_color, 'data': []}]
12041210
if selected_completion_type == "completed_combined":
12051211
pass
12061212
else:
12071213
for d, aggr in aggrs:
1208-
v = 0
1209-
if selected_completion_type is not None:
1210-
v = aggr[selected_completion_type]
1214+
v1 = 0
1215+
v2 = None
1216+
js_timestamp = calendar.timegm(d.timetuple()) * 1000
1217+
if selected_completion_type == 'completed_in_time_or_late':
1218+
v1 = aggr['completed_in_time']
1219+
v2 = aggr['completed_late']
1220+
elif selected_completion_type is not None:
1221+
v1 = aggr[selected_completion_type]
12111222
elif selected_result is not None:
1212-
v = aggr["result"][selected_result]
1223+
v1 = aggr["result"][selected_result]
12131224
elif selected_state is not None:
1214-
v = aggr["state"][selected_state]
1225+
v1 = aggr["state"][selected_state]
12151226

1216-
series_data.append((calendar.timegm(d.timetuple()) * 1000, v))
1217-
data = json.dumps([{
1218-
"data": series_data
1219-
}])
1227+
graph_data[0]['data'].append((js_timestamp, v1))
1228+
if v2 is not None:
1229+
graph_data[1]['data'].append((js_timestamp, v2))
1230+
data = json.dumps(graph_data)
12201231

12211232
else: # tabular data
12221233
extracted_data = extract_review_assignment_data(query_teams, query_reviewers, from_time, to_time, ordering=[level])

ietf/templates/stats/review_stats.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ <h3>Counts per month</h3>
220220
tickDecimals: {% if selected_completion_type == "average_assignment_to_closure_days" %}null{% else %}0{% endif %}
221221
},
222222
series: {
223-
color: "#3d22b3",
223+
stack: true,
224224
bars: {
225225
show: true,
226226
barWidth: 20 * 24 * 60 * 60 * 1000,
@@ -257,6 +257,7 @@ <h3>Counts per month</h3>
257257
{% if stats_type == "time" %}
258258
<script src="{% static 'flot/jquery.flot.min.js' %}"></script>
259259
<script src="{% static 'flot/jquery.flot.time.min.js' %}"></script>
260+
<script src="{% static 'flot/jquery.flot.stack.min.js' %}"></script>
260261
<script src="{% static 'ietf/js/review-stats.js' %}"></script>
261262
{% endif %}
262263
{% endblock %}

0 commit comments

Comments
 (0)