Modify the reviewer overview page to display up to 10 historic reviews
per person from the past year instead of only 5. Add basic reviewer stats to the assignment select box. - Legacy-Id: 12279
This commit is contained in:
parent
c3e8cabafb
commit
cde7cfacd5
|
@ -299,6 +299,7 @@ class ReviewTests(TestCase):
|
|||
self.assertIn("unavailable indefinitely", reviewer_label)
|
||||
self.assertIn("skip next 1", reviewer_label)
|
||||
self.assertIn("#1", reviewer_label)
|
||||
self.assertIn("no response 0/1", reviewer_label)
|
||||
|
||||
# assign
|
||||
empty_outbox()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import datetime, math, itertools
|
||||
import datetime, math
|
||||
from collections import defaultdict
|
||||
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
|
@ -21,7 +21,7 @@ from ietf.review.utils import (can_manage_review_requests_for_team,
|
|||
current_unavailable_periods_for_reviewers,
|
||||
email_reviewer_availability_change,
|
||||
reviewer_rotation_list,
|
||||
extract_review_request_data)
|
||||
latest_review_requests_for_reviewers)
|
||||
from ietf.group.models import Role
|
||||
from ietf.group.utils import get_group_or_404, construct_group_menu_context
|
||||
from ietf.person.fields import PersonEmailChoiceField
|
||||
|
@ -130,12 +130,7 @@ def reviewer_overview(request, acronym, group_type=None):
|
|||
|
||||
today = datetime.date.today()
|
||||
|
||||
extracted_data = extract_review_request_data(teams=[group], time_from=today - datetime.timedelta(days=365), ordering=["reviewer"])
|
||||
req_data_for_reviewer = {}
|
||||
for reviewer, req_data_items in itertools.groupby(extracted_data, key=lambda data: data.reviewer):
|
||||
l = list(req_data_items)
|
||||
l.reverse()
|
||||
req_data_for_reviewer[reviewer] = l
|
||||
req_data_for_reviewers = latest_review_requests_for_reviewers(group)
|
||||
review_state_by_slug = { n.slug: n for n in ReviewRequestStateName.objects.all() }
|
||||
|
||||
for person in reviewers:
|
||||
|
@ -152,13 +147,12 @@ def reviewer_overview(request, acronym, group_type=None):
|
|||
and (p.start_date is None or p.start_date <= today) and (p.end_date is None or today <= p.end_date)
|
||||
for p in person.unavailable_periods)
|
||||
|
||||
MAX_REQS = 5
|
||||
req_data = req_data_for_reviewer.get(person.pk, [])
|
||||
open_reqs = sum(1 for d in req_data if d.state in ("requested", "accepted"))
|
||||
MAX_CLOSED_REQS = 10
|
||||
req_data = req_data_for_reviewers.get(person.pk, [])
|
||||
open_reqs = sum(1 for d in req_data if d.state in ["requested", "accepted"])
|
||||
latest_reqs = []
|
||||
for d in req_data:
|
||||
# any open requests pushes the others out
|
||||
if ((d.state in ("requested", "accepted") and len(latest_reqs) < MAX_REQS) or (len(latest_reqs) + open_reqs < MAX_REQS)):
|
||||
if d.state in ["requested", "accepted"] or len(latest_reqs) < MAX_CLOSED_REQS + open_reqs:
|
||||
latest_reqs.append((d.req_pk, d.doc, d.reviewed_rev, d.deadline,
|
||||
review_state_by_slug.get(d.state),
|
||||
int(math.ceil(d.assignment_to_closure_days)) if d.assignment_to_closure_days is not None else None))
|
||||
|
|
|
@ -294,6 +294,23 @@ def sum_raw_review_request_aggregations(raw_aggregations):
|
|||
|
||||
return state_dict, late_state_dict, result_dict, assignment_to_closure_days_list, assignment_to_closure_days_count
|
||||
|
||||
def latest_review_requests_for_reviewers(team, days_back=365):
|
||||
"""Collect and return stats for reviewers on latest requests, in
|
||||
extract_review_request_data format."""
|
||||
|
||||
extracted_data = extract_review_request_data(
|
||||
teams=[team],
|
||||
time_from=datetime.date.today() - datetime.timedelta(days=days_back),
|
||||
ordering=["reviewer"],
|
||||
)
|
||||
|
||||
req_data_for_reviewers = {
|
||||
reviewer: list(reversed(list(req_data_items)))
|
||||
for reviewer, req_data_items in itertools.groupby(extracted_data, key=lambda data: data.reviewer)
|
||||
}
|
||||
|
||||
return req_data_for_reviewers
|
||||
|
||||
def make_new_review_request_from_existing(review_req):
|
||||
obj = ReviewRequest()
|
||||
obj.time = review_req.time
|
||||
|
@ -717,6 +734,9 @@ def make_assignment_choices(email_queryset, review_req):
|
|||
# unavailable periods
|
||||
unavailable_periods = current_unavailable_periods_for_reviewers(team)
|
||||
|
||||
# reviewers statistics
|
||||
req_data_for_reviewers = latest_review_requests_for_reviewers(team)
|
||||
|
||||
ranking = []
|
||||
for e in possible_emails:
|
||||
settings = reviewer_settings.get(e.person_id)
|
||||
|
@ -763,10 +783,26 @@ def make_assignment_choices(email_queryset, review_req):
|
|||
if settings.skip_next > 0:
|
||||
explanations.append("skip next {}".format(settings.skip_next))
|
||||
|
||||
# index
|
||||
index = rotation_index.get(e.person_id, 0)
|
||||
scores.append(-index)
|
||||
explanations.append("#{}".format(index + 1))
|
||||
|
||||
# stats
|
||||
stats = []
|
||||
req_data = req_data_for_reviewers.get(e.person_id, [])
|
||||
|
||||
currently_open = sum(1 for d in req_data if d.state in ["requested", "accepted"])
|
||||
if currently_open > 0:
|
||||
stats.append("currently {} open".format(currently_open))
|
||||
could_have_completed = [d for d in req_data if d.state in ["part-completed", "completed", "no-response"]]
|
||||
if could_have_completed:
|
||||
no_response = sum(1 for d in could_have_completed if d.state == "no-response")
|
||||
stats.append("no response {}/{}".format(no_response, len(could_have_completed)))
|
||||
|
||||
if stats:
|
||||
explanations.append(", ".join(stats))
|
||||
|
||||
label = unicode(e.person)
|
||||
if explanations:
|
||||
label = u"{}: {}".format(label, u"; ".join(explanations))
|
||||
|
|
Loading…
Reference in a new issue