From 39427a59c3dca02e1b4ab5dc9dfda3541104fe9e Mon Sep 17 00:00:00 2001 From: Tero Kivinen Date: Sat, 23 Jul 2022 18:23:54 -0400 Subject: [PATCH 1/5] feat: Add new page as requested in #4242 to list all area directors and their current workload. Include links to the specific dashboards for each area director. This new page is in doc/ad/. --- ietf/templates/doc/ad_list.html | 41 +++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ietf/templates/doc/ad_list.html diff --git a/ietf/templates/doc/ad_list.html b/ietf/templates/doc/ad_list.html new file mode 100644 index 00000000000..f7d603997b9 --- /dev/null +++ b/ietf/templates/doc/ad_list.html @@ -0,0 +1,41 @@ +{% extends "base.html" %} +{# Copyright The IETF Trust 2015, All Rights Reserved #} +{% load origin static %} +{% load ietf_filters %} +{% block pagehead %} + +{% endblock %} +{% block title %}Area directors{% endblock %} +{% block content %} +{% origin %} +

Area Directors Workload

+{% for gt in group_types %} +

{{ gt }}

+ + + + + {% for g in group_names|hash:gt %} + + {% endfor %} + + + + {% for ad in ads %} + + + {% for c in ad.counts|hash:gt %} + {% if forloop.counter0 < groups|hash:gt|length %} + + {% endfor %} + +
Name + {{ g }}
{{ ad.name }}{{ c }} + {% endif %} + {% endfor %} +
+{% endfor %} +{% endblock %} +{% block js %} + +{% endblock %} From 9f277e469cc214268eb112e5434deaa3112b3266 Mon Sep 17 00:00:00 2001 From: Tero Kivinen Date: Sat, 23 Jul 2022 18:45:40 -0400 Subject: [PATCH 2/5] feat: Add new page as requested in #4242 to list all area directors and their current workload. Include links to the specific dashboards for each area director. This new page is in doc/ad/. --- ietf/doc/templatetags/ietf_filters.py | 7 ++ ietf/doc/urls.py | 2 +- ietf/doc/views_search.py | 125 +++++++++++++++++++++++++- 3 files changed, 130 insertions(+), 4 deletions(-) diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index d2450fa62bf..e59b500c1d8 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -779,3 +779,10 @@ def is_valid_url(url): except ValidationError: return False return True + +@register.filter +def hash(h, key): + """ + Get a key from hash + """ + return h[key] diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py index ad8ee81b214..730357a06b0 100644 --- a/ietf/doc/urls.py +++ b/ietf/doc/urls.py @@ -50,7 +50,7 @@ url(r'^$', views_search.search), url(r'^search/?$', views_search.search), url(r'^in-last-call/?$', views_search.drafts_in_last_call), - url(r'^ad/(?P[^/]+)/?$', views_search.docs_for_ad), + url(r'^ad/((?P[^/]+)/)?$', views_search.docs_for_ad), url(r'^ad2/(?P[\w.-]+)/$', RedirectView.as_view(url='/doc/ad/%(name)s/', permanent=True)), url(r'^rfc-status-changes/?$', views_status_change.rfc_status_changes), url(r'^start-rfc-status-change/(?:%(name)s/)?$' % settings.URL_REGEXPS, views_status_change.start_rfc_status_change), diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index 7265964e155..ba44a16f61b 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -307,6 +307,32 @@ def cached_redirect(cache_key, url): return cached_redirect(cache_key, urlreverse('ietf.doc.views_search.search') + search_args) +def ad_dashboard_group_type(doc): + # Return group type for document for dashboard. + # If doc is not defined return list of all possible + # group types + if not doc: + return ('I-D', 'RFC', 'Conflict Review', 'Status Change', 'Charter') + if doc.type.slug=='draft': + if doc.get_state_slug('draft') == 'rfc': + return 'RFC' + elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('RFC Ed Queue Internet-Draft'): + return 'RFC' + elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('Dead', 'I-D Exists', 'AD is watching'): + return None + elif doc.get_state('draft').name in ('Expired', 'Replaced'): + return None + else: + return 'I-D' + elif doc.type.slug=='conflrev': + return 'Conflict Review' + elif doc.type.slug=='statchg': + return 'Status Change' + elif doc.type.slug=='charter': + return "Charter" + else: + return "Document" + def ad_dashboard_group(doc): if doc.type.slug=='draft': @@ -395,14 +421,107 @@ def ad_dashboard_sort_key(doc): def docs_for_ad(request, name): ad = None + ads = [] responsible = Document.objects.values_list('ad', flat=True).distinct() for p in Person.objects.filter(Q(role__name__in=("pre-ad", "ad"), role__group__type="area", role__group__state="active") | Q(pk__in=responsible)).distinct(): - if name == p.full_name_as_key(): - ad = p - break + if not name: + if p in get_active_ads(): + ads.append(p) + else: + if name == p.full_name_as_key(): + ad = p + break + if not name: + doctypes = list(DocTypeName.objects.filter(used=True).exclude(slug='draft').values_list("pk", flat=True)) + + group_types = ad_dashboard_group_type(None) + + groups = {} + group_names = {} + for g in group_types: + groups[g] = {} + group_names[g] = [] + + # Prefill groups in preferred sort order + id = 0 + for g in [ + 'Publication Requested Internet-Draft', + 'Waiting for Writeup Internet-Draft', + 'AD Evaluation Internet-Draft', + 'In Last Call Internet-Draft', + 'IESG Evaluation - Defer Internet-Draft', + 'IESG Evaluation Internet-Draft', + 'Waiting for AD Go-Ahead Internet-Draft', + 'Approved-announcement to be sent Internet-Draft', + 'Approved-announcement sent Internet-Draft']: + groups['I-D'][g] = id + group_names['I-D'].append(g) + id += 1; + id = 0 + for g in ['RFC Ed Queue Internet-Draft', 'RFC']: + groups['RFC'][g] = id + group_names['RFC'].append(g) + id += 1; + id = 0 + for g in ['AD Review Conflict Review', + 'Needs Shepherd Conflict Review', + 'IESG Evaluation Conflict Review', + 'Approved Conflict Review', + 'Withdrawn Conflict Review']: + groups['Conflict Review'][g] = id + group_names['Conflict Review'].append(g) + id += 1; + id = 0 + for g in [ 'Start Chartering/Rechartering (Internal Steering Group/IAB Review) Charter', + 'Replaced Charter', + 'Approved Charter', + 'Not currently under review Charter']: + groups['Charter'][g] = id + group_names['Charter'].append(g) + id += 1; + + for ad in ads: + form = SearchForm({'by':'ad','ad': ad.id, + 'rfcs':'on', 'activedrafts':'on', + 'olddrafts':'on', + 'doctypes': doctypes}) + data = retrieve_search_results(form) + ad.dashboard = urlreverse("ietf.doc.views_search.docs_for_ad") + ad.full_name_as_key() + counts = {} + for g in group_types: + counts[g] = [] + for doc in data: + group_type = ad_dashboard_group_type(doc) + if group_type: + group = ad_dashboard_group(doc) + if group not in groups[group_type]: + groups[group_type][group] = len(groups[group_type]) + group_names[group_type].append(group) + if len(counts[group_type]) < len(groups[group_type]): + counts[group_type].extend([0] * (len(groups[group_type]) - len(counts[group_type]))) + counts[group_type][groups[group_type][group]] += 1 + ad.counts = counts + for ad in ads: + for group_type in group_types: + if len(ad.counts[group_type]) < len(groups[group_type]): + ad.counts[group_type].extend([0] * (len(groups[group_type]) - len(ad.counts[group_type]))) + # Shorten the names of groups + for gt in group_types: + for idx,g in enumerate(group_names[gt]): + for s in [' Internet-Draft', ' Charter', ' Conflict Review', ' Status Change', ' (Internal Steering Group/IAB Review) Charter']: + print(g, s) + if g.endswith(s): + group_names[gt][idx] = g[:-len(s)] + return render(request, 'doc/ad_list.html', { + 'ads': ads, + 'group_types': group_types, + 'group_names': group_names, + 'groups': groups + }) + if not ad: raise Http404 form = SearchForm({'by':'ad','ad': ad.id, From f382bde7eb2b4c0cd1f01064b458edc9540fce02 Mon Sep 17 00:00:00 2001 From: Tero Kivinen Date: Sat, 23 Jul 2022 20:08:07 -0400 Subject: [PATCH 3/5] Fixed issues from the previous commit by renaming hash to get_hash. --- ietf/doc/templatetags/ietf_filters.py | 2 +- ietf/doc/views_search.py | 1 - ietf/templates/doc/ad_list.html | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py index e59b500c1d8..e54cfd76e81 100644 --- a/ietf/doc/templatetags/ietf_filters.py +++ b/ietf/doc/templatetags/ietf_filters.py @@ -781,7 +781,7 @@ def is_valid_url(url): return True @register.filter -def hash(h, key): +def get_hash(h, key): """ Get a key from hash """ diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index ba44a16f61b..da3178691c7 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -512,7 +512,6 @@ def docs_for_ad(request, name): for gt in group_types: for idx,g in enumerate(group_names[gt]): for s in [' Internet-Draft', ' Charter', ' Conflict Review', ' Status Change', ' (Internal Steering Group/IAB Review) Charter']: - print(g, s) if g.endswith(s): group_names[gt][idx] = g[:-len(s)] return render(request, 'doc/ad_list.html', { diff --git a/ietf/templates/doc/ad_list.html b/ietf/templates/doc/ad_list.html index f7d603997b9..f3226bb6a8e 100644 --- a/ietf/templates/doc/ad_list.html +++ b/ietf/templates/doc/ad_list.html @@ -15,7 +15,7 @@

{{ gt }}

Name - {% for g in group_names|hash:gt %} + {% for g in group_names|get_hash:gt %} {{ g }} {% endfor %} @@ -25,8 +25,8 @@

{{ gt }}

{% for ad in ads %} {{ ad.name }} - {% for c in ad.counts|hash:gt %} - {% if forloop.counter0 < groups|hash:gt|length %} + {% for c in ad.counts|get_hash:gt %} + {% if forloop.counter0 < groups|get_hash:gt|length %} {{ c }} {% endif %} {% endfor %} From 169302c0c3f5b004401449d04ea57f14a86f31be Mon Sep 17 00:00:00 2001 From: Tero Kivinen Date: Sat, 23 Jul 2022 20:31:55 -0400 Subject: [PATCH 4/5] Making outer () to be non matching --- ietf/doc/urls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/doc/urls.py b/ietf/doc/urls.py index 730357a06b0..397901aaf66 100644 --- a/ietf/doc/urls.py +++ b/ietf/doc/urls.py @@ -50,7 +50,7 @@ url(r'^$', views_search.search), url(r'^search/?$', views_search.search), url(r'^in-last-call/?$', views_search.drafts_in_last_call), - url(r'^ad/((?P[^/]+)/)?$', views_search.docs_for_ad), + url(r'^ad/(?:(?P[^/]+)/)?$', views_search.docs_for_ad), url(r'^ad2/(?P[\w.-]+)/$', RedirectView.as_view(url='/doc/ad/%(name)s/', permanent=True)), url(r'^rfc-status-changes/?$', views_status_change.rfc_status_changes), url(r'^start-rfc-status-change/(?:%(name)s/)?$' % settings.URL_REGEXPS, views_status_change.start_rfc_status_change), From 76df542a8e53f978ad28708841d0786c31b6c416 Mon Sep 17 00:00:00 2001 From: Tero Kivinen Date: Sun, 24 Jul 2022 13:25:14 -0400 Subject: [PATCH 5/5] Fixed RFC Ed Queue Internet-Draft to RFC Ed Queue --- ietf/doc/views_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ietf/doc/views_search.py b/ietf/doc/views_search.py index da3178691c7..0f2494d259f 100644 --- a/ietf/doc/views_search.py +++ b/ietf/doc/views_search.py @@ -316,7 +316,7 @@ def ad_dashboard_group_type(doc): if doc.type.slug=='draft': if doc.get_state_slug('draft') == 'rfc': return 'RFC' - elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('RFC Ed Queue Internet-Draft'): + elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('RFC Ed Queue'): return 'RFC' elif doc.get_state_slug('draft') == 'active' and doc.get_state_slug('draft-iesg') and doc.get_state('draft-iesg').name in ('Dead', 'I-D Exists', 'AD is watching'): return None