Skip to content

Commit 6eb5ae4

Browse files
fixup! views: add series-list view
1 parent 330d2b0 commit 6eb5ae4

File tree

3 files changed

+116
-8
lines changed

3 files changed

+116
-8
lines changed

patchwork/models.py

+27
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from django.contrib.auth.models import User
1515
from django.core.exceptions import ValidationError
1616
from django.core.validators import validate_unicode_slug
17+
from django.db.models import Count
1718
from django.db import models
1819
from django.urls import reverse
1920
from django.utils.functional import cached_property
@@ -880,6 +881,32 @@ def received_total(self):
880881
def received_all(self):
881882
return self.total <= self.received_total
882883

884+
@property
885+
def interest_count(self):
886+
count = self.patches.aggregate(
887+
Count('planning_to_review', distinct=True)
888+
)
889+
return count['planning_to_review__count']
890+
891+
@property
892+
def check_count(self):
893+
"""Generate a list of unique checks for all patchs in the series.
894+
895+
Compile a list of checks associated with this series patches for each
896+
type of check. Only "unique" checks are considered, identified by their
897+
'context' field. This means, given n checks with the same 'context', the
898+
newest check is the only one counted regardless of its value. The end
899+
result will be a association of types to number of unique checks for
900+
said type.
901+
"""
902+
counts = {key: 0 for key, _ in Check.STATE_CHOICES}
903+
904+
for p in self.patches.all():
905+
for check in p.checks:
906+
counts[check.state] += 1
907+
908+
return counts
909+
883910
def add_cover_letter(self, cover):
884911
"""Add a cover letter to the series.
885912

patchwork/templates/patchwork/series-list.html

+13-8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
{% load person %}
1212
{% load listurl %}
1313
{% load patch %}
14+
{% load series %}
1415
{% load project %}
1516
{% load static %}
1617

@@ -37,7 +38,15 @@
3738
</th>
3839

3940
<th>
40-
<span class="series-list-header">Cover Letter</span>
41+
{% project_tags %}
42+
</th>
43+
44+
<th>
45+
<span class="series-list-header" title="Success / Warning / Fail">S/W/F</span>
46+
</th>
47+
48+
<th>
49+
<span class="series-list-header" title="Declared review interest">Review Interest</span>
4150
</th>
4251

4352
<th>
@@ -83,13 +92,9 @@
8392
{{ series.version|default:"-"}}
8493
</td>
8594

86-
<td>
87-
{% if series.cover_letter.content %}
88-
<b>&check;</b>
89-
{% else %}
90-
-
91-
{% endif %}
92-
</td>
95+
<td id="series-tags:{{series.id}}" class="text-nowrap">{{ series|series_tags }}</td>
96+
<td id="series-checks:{{series.id}}" class="text-nowrap">{{ series|series_checks }}</td>
97+
<td id="series-interest:{{series.id}}" class="text-nowrap">{{ series|series_interest }}</td>
9398
<td>{{ series.received_total}}</td>
9499
<td class="text-nowrap">{{ series.date|date:"Y-m-d" }}</td>
95100
<td>{{ series.submitter|personify:project }}</td>

patchwork/templatetags/series.py

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Patchwork - automated patch tracking system
2+
# Copyright (C) 2008 Jeremy Kerr <[email protected]>
3+
# Copyright (C) 2015 Intel Corporation
4+
#
5+
# SPDX-License-Identifier: GPL-2.0-or-later
6+
7+
from django import template
8+
from django.utils.safestring import mark_safe
9+
10+
from patchwork.models import Check
11+
12+
13+
register = template.Library()
14+
15+
16+
@register.filter(name='series_tags')
17+
def series_tags(series):
18+
counts = []
19+
titles = []
20+
21+
for tag in [t for t in series.project.tags if t.show_column]:
22+
count = 0
23+
for patch in series.patches.with_tag_counts(series.project).all():
24+
count += getattr(patch, tag.attr_name)
25+
26+
titles.append('%d %s' % (count, tag.name))
27+
if count == 0:
28+
counts.append('-')
29+
else:
30+
counts.append(str(count))
31+
32+
return mark_safe(
33+
'<span title="%s">%s</span>' % (' / '.join(titles), ' '.join(counts))
34+
)
35+
36+
37+
@register.filter(name='series_checks')
38+
def series_checks(series):
39+
required = [Check.STATE_SUCCESS, Check.STATE_WARNING, Check.STATE_FAIL]
40+
titles = ['Success', 'Warning', 'Fail']
41+
counts = series.check_count
42+
43+
check_elements = []
44+
for state in required[::-1]:
45+
if counts[state]:
46+
color = dict(Check.STATE_CHOICES).get(state)
47+
count = str(counts[state])
48+
else:
49+
color = ''
50+
count = '-'
51+
52+
check_elements.append(
53+
f'<span class="patchlistchecks {color}">{count}</span>'
54+
)
55+
56+
check_elements.reverse()
57+
58+
return mark_safe(
59+
'<span title="%s">%s</span>'
60+
% (' / '.join(titles), ''.join(check_elements))
61+
)
62+
63+
64+
@register.filter(name='series_interest')
65+
def series_interest(series):
66+
reviews = series.interest_count
67+
review_title = (
68+
f'has {reviews} interested reviewers'
69+
if reviews > 0
70+
else 'no interested reviewers'
71+
)
72+
review_class = 'exists' if reviews > 0 else ''
73+
return mark_safe(
74+
'<span class="patchinterest %s" title="%s">%s</span>'
75+
% (review_class, review_title, reviews if reviews > 0 else '-')
76+
)

0 commit comments

Comments
 (0)