Merge "Open reviews report is added"
This commit is contained in:
@@ -12,6 +12,7 @@
|
|||||||
# implied.
|
# implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
import json
|
||||||
|
|
||||||
import operator
|
import operator
|
||||||
import time
|
import time
|
||||||
@@ -48,27 +49,74 @@ def blueprint_summary(module, blueprint_name):
|
|||||||
return {'blueprint': bpd, 'activity': activity}
|
return {'blueprint': bpd, 'activity': activity}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_day(timestamp, time_now):
|
||||||
|
return int((time_now - timestamp) / 60 / 60 / 24)
|
||||||
|
|
||||||
|
|
||||||
|
def _process_stat(data, key, time_now):
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = sorted(data, key=operator.itemgetter(key))
|
||||||
|
|
||||||
|
days = _get_day(data[0][key], time_now)
|
||||||
|
chart_data = [0] * (days + 1)
|
||||||
|
sum_ages = 0
|
||||||
|
for review in data:
|
||||||
|
age = time_now - review[key]
|
||||||
|
sum_ages += age
|
||||||
|
review[key + '_age'] = utils.make_age_string(age)
|
||||||
|
chart_data[_get_day(review[key], time_now)] += 1
|
||||||
|
|
||||||
|
return {
|
||||||
|
'reviews': data,
|
||||||
|
'average': utils.make_age_string(sum_ages / len(data)),
|
||||||
|
'max': data[0][key + '_age'],
|
||||||
|
'chart_data': json.dumps(chart_data),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route('/reviews/<module>')
|
@blueprint.route('/reviews/<module>')
|
||||||
@decorators.templated()
|
@decorators.templated()
|
||||||
@decorators.exception_handler()
|
@decorators.exception_handler()
|
||||||
def open_reviews(module):
|
def open_reviews(module):
|
||||||
memory_storage = vault.get_memory_storage()
|
memory_storage_inst = vault.get_memory_storage()
|
||||||
now = int(time.time())
|
time_now = int(time.time())
|
||||||
review_ids = (memory_storage.get_record_ids_by_modules([module]) &
|
|
||||||
memory_storage.get_record_ids_by_type('review'))
|
review_marks = {}
|
||||||
records = []
|
reviews = {}
|
||||||
for review in memory_storage.get_records(review_ids):
|
|
||||||
if review['status'] != 'NEW':
|
mark_ids = (memory_storage_inst.get_record_ids_by_modules([module]) &
|
||||||
continue
|
memory_storage_inst.get_record_ids_by_type('mark'))
|
||||||
processed_review = review.copy()
|
|
||||||
helpers.extend_record(processed_review)
|
for mark in memory_storage_inst.get_records(mark_ids):
|
||||||
processed_review['age'] = utils.make_age_string(
|
review_id = mark['review_id']
|
||||||
now - processed_review['date'])
|
if review_id in review_marks:
|
||||||
records.append(processed_review)
|
if mark['date'] > review_marks[review_id]['date']:
|
||||||
|
review_marks[review_id] = mark
|
||||||
|
else:
|
||||||
|
review = memory_storage_inst.get_record_by_primary_key(review_id)
|
||||||
|
if not review:
|
||||||
|
continue # todo because we filter jenkins
|
||||||
|
review_marks[review_id] = mark
|
||||||
|
reviews[review_id] = review
|
||||||
|
|
||||||
|
waiting_on_reviewer = []
|
||||||
|
total_open = 0
|
||||||
|
for review_id, mark in review_marks.iteritems():
|
||||||
|
if reviews[review_id]['open']:
|
||||||
|
total_open += 1
|
||||||
|
if mark['value'] in ['1', '2']:
|
||||||
|
waiting_on_reviewer.append(reviews[review_id])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'module': module,
|
'module': module,
|
||||||
'oldest': sorted(records, key=operator.itemgetter('date'))[:5]
|
'total_open': total_open,
|
||||||
|
'waiting_on_reviewer': len(waiting_on_reviewer),
|
||||||
|
'waiting_on_submitter': total_open - len(waiting_on_reviewer),
|
||||||
|
'latest_revision': _process_stat(
|
||||||
|
waiting_on_reviewer, 'lastUpdated', time_now),
|
||||||
|
'first_revision': _process_stat(waiting_on_reviewer, 'date', time_now),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
3
dashboard/static/js/jqplot.barRenderer.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.barRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
3
dashboard/static/js/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
3
dashboard/static/js/jqplot.categoryAxisRenderer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -3,6 +3,65 @@
|
|||||||
<head>
|
<head>
|
||||||
<title>Open reviews report for {{ module }}</title>
|
<title>Open reviews report for {{ module }}</title>
|
||||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
|
||||||
|
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=PT+Sans+Caption&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
|
||||||
|
<link href='http://fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
|
||||||
|
|
||||||
|
<link rel="icon" href="{{ url_for('static', filename='images/favicon.png') }}" type="image/png"/>
|
||||||
|
|
||||||
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery.jqplot.min.css') }}">
|
||||||
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery.dataTables.css') }}">
|
||||||
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/select2.css') }}">
|
||||||
|
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-1.9.1.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.dataTables.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.jqplot.min.js') }}"></script>
|
||||||
|
<!--[if lt IE 9]><script type="text/javascript" src="{{ url_for('static', filename='js/excanvas.min.js') }}"></script><![endif]-->
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.json2.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.pieRenderer.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.barRenderer.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.categoryAxisRenderer.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.dateAxisRenderer.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasTextRenderer.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasAxisTickRenderer.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.cursor.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.highlighter.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/select2.min.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.tmpl.js') }}"></script>
|
||||||
|
<script type="text/javascript" src="{{ url_for('static', filename='js/stackalytics-ui.js') }}"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function render_bar_chart(chart_id, chart_data) {
|
||||||
|
$.jqplot(chart_id, chart_data, {
|
||||||
|
seriesDefaults: {
|
||||||
|
renderer: $.jqplot.BarRenderer,
|
||||||
|
rendererOptions: {
|
||||||
|
barMargin: 1
|
||||||
|
},
|
||||||
|
pointLabels: {show: true}
|
||||||
|
},
|
||||||
|
axes: {
|
||||||
|
xaxis: {
|
||||||
|
renderer: $.jqplot.CategoryAxisRenderer,
|
||||||
|
label: "Age"
|
||||||
|
},
|
||||||
|
yaxis: {
|
||||||
|
label: "Count"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
render_bar_chart("latest_revision_chart", [{{ latest_revision.chart_data }}]);
|
||||||
|
render_bar_chart("first_revision_chart", [{{ first_revision.chart_data }}]);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.label {
|
.label {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -16,11 +75,44 @@
|
|||||||
</head>
|
</head>
|
||||||
<body style="margin: 2em;">
|
<body style="margin: 2em;">
|
||||||
|
|
||||||
<h1>Open Reviews Report</h1>
|
<h1>Open reviews for {{ module }}</h1>
|
||||||
|
|
||||||
|
<h3>Summary:</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Total open reviews: {{ total_open }}</li>
|
||||||
|
<li>Waiting on reviewer: {{ waiting_on_reviewer }}</li>
|
||||||
|
<li>Waiting on submitter: {{ waiting_on_submitter }}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% if total_open %}
|
||||||
|
<h3>Stats since last revision</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Average wait time: {{ latest_revision.average }}</li>
|
||||||
|
<li>Max wait time: {{ latest_revision.max }}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div id="latest_revision_chart" style="width: 100%; height: 350px;"></div>
|
||||||
|
|
||||||
<h3>Longest waiting reviews (since first revision, total age): </h3>
|
|
||||||
<ol>
|
<ol>
|
||||||
{% for item in oldest %}
|
{% for item in latest_revision.reviews[:5] %}
|
||||||
<li>{{ item.age }} <a href="{{ item.url }}">{{ item.url }}</a> {{ item.subject }}</li>
|
<li>{{ item.lastUpdated_age }} <a href="{{ item.url }}">{{ item.url }}</a> {{ item.subject }} by {{ item.author_name }} ({{ item.company_name }})</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<h3>Stats since first revision</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Average wait time: {{ first_revision.average }}</li>
|
||||||
|
<li>Max wait time: {{ first_revision.max }}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div id="first_revision_chart" style="width: 100%; height: 350px;"></div>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
{% for item in first_revision.reviews[:5] %}
|
||||||
|
<li>{{ item.date_age }} <a href="{{ item.url }}">{{ item.url }}</a> {{ item.subject }} by {{ item.author_name }} ({{ item.company_name }})</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
{% endif %}
|
Reference in New Issue
Block a user