Skip to content

Commit 2e6f028

Browse files
authored
Revamp the homepage to show you patches you might be interested in (#51)
The homepage was not showing a lot of useful information. It had a list of mostly ancient commitfests, a search box, and a few links to more useful pages. This revamps the homepage with an initial version of a personalized dashboard. The dashboard shows patches that the user is subscribed to, either because they are marked as an author or a reviewer. We then try to group and sort these patches in an attempt to let the user easily find the patches that require their attention. Many things can likely be tweaked/improved. I think this first version is already a huge improvement over the status quo, so I think it's worth committing deploying this mostly as is and then iterating on it based on feedback. This is what it looks like: ![screenshot of homepage](https://github.com/user-attachments/assets/6f464597-30f9-4f4b-9b98-17ac90b64b60) Fixes #36
1 parent b8d3523 commit 2e6f028

File tree

9 files changed

+376
-88
lines changed

9 files changed

+376
-88
lines changed

media/commitfest/css/commitfest.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,7 @@ div.form-group div.controls input.threadpick-input {
8787
font-weight: bold;
8888
color: red;
8989
}
90+
91+
.search-bar {
92+
display: inline-block;
93+
}

pgcommitfest/commitfest/forms.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ def __init__(self, cf, *args, **kwargs):
2626
c = [(-1, "* All")] + list(PatchOnCommitFest._STATUS_CHOICES)
2727
self.fields["status"] = forms.ChoiceField(choices=c, required=False)
2828

29-
q = Q(patch_author__commitfests=cf) | Q(patch_reviewer__commitfests=cf)
29+
if cf:
30+
q = Q(patch_author__commitfests=cf) | Q(patch_reviewer__commitfests=cf)
31+
else:
32+
q = Q()
3033
userchoices = [(-1, "* All"), (-2, "* None"), (-3, "* Yourself")] + [
3134
(u.id, "%s %s (%s)" % (u.first_name, u.last_name, u.username))
3235
for u in User.objects.filter(q)

pgcommitfest/commitfest/models.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ class CommitFest(models.Model):
4444
(STATUS_INPROGRESS, "In Progress"),
4545
(STATUS_CLOSED, "Closed"),
4646
)
47+
_STATUS_LABELS = (
48+
(STATUS_FUTURE, "default"),
49+
(STATUS_OPEN, "info"),
50+
(STATUS_INPROGRESS, "success"),
51+
(STATUS_CLOSED, "danger"),
52+
)
4753
name = models.CharField(max_length=100, blank=False, null=False, unique=True)
4854
status = models.IntegerField(
4955
null=False, blank=False, default=1, choices=_STATUS_CHOICES
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{%extends "base.html"%}
2+
{%block contents%}
3+
<ul>
4+
{%for c in commitfests%}
5+
<li><a href="/{{c.id}}/">{{c}}</a> ({{c.statusstring}}{%if c.startdate%} - {{c.periodstring}}{%endif%})</li>
6+
{%endfor%}
7+
</ul>
8+
{%endblock%}
9+

pgcommitfest/commitfest/templates/base.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<!DOCTYPE html>
33
<html>
44
<head>
5-
<title>{{title}}</title>
5+
<title>{{title|default:'Commitfest' }}</title>
66
<link rel="stylesheet" href="/media/commitfest/css/jquery-ui.css" type="text/css">
77
<link rel="stylesheet" href="/media/commitfest/css/bootstrap.css" />
88
<link rel="stylesheet" href="/media/commitfest/css/bootstrap-theme.min.css" />
@@ -29,7 +29,9 @@
2929
{%if header_activity%} <li class="pull-right active"><a href="{{header_activity_link}}">{{header_activity}}</a></li>{%endif%}
3030
</ul>
3131

32-
<h1>{{title}}</h1>
32+
{%if title %}
33+
<h1>{{title}}</h1>
34+
{%endif%}
3335

3436
{%if messages%}
3537
{%for m in messages%}
Lines changed: 128 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,135 @@
11
{%extends "base.html"%}
2+
{%load commitfest %}
23
{%block contents%}
3-
<p>
4-
{%if inprogresscf%}A commitfest is currently in progress: <a href="/{{inprogresscf.id}}/">{{inprogresscf}}</a>.{%endif%}
5-
</p>
6-
<p>
7-
Useful links that you can use and bookmark:
8-
</p>
9-
<ul>
10-
<li><a href="/current/">All patches in the current commitfest</a></li>
11-
<li><a href="/open/">All patches in the open commitfest</a></li>
12-
<li><a href="/open/new/">Create a new commitfest entry</a></li>
13-
<li><a href="/current/?author=-3">Your entries in the current commitfest</a></li>
14-
<li><a href="/open/?author=-3">Your entries in the open commitfest</a></li>
15-
<li><a href="/current/?reviewer=-3">Entries that you are reviewing in current commitfest</a></li>
16-
</ul>
17-
<h3>Commands</h3>
18-
<form method="GET" action="/search/" class="form-inline">
4+
<a class="btn btn-default" href="/open/new/">New patch</a>
5+
<a class="btn btn-default" href="/current/">Current commitfest</a></li>
6+
<a class="btn btn-default" href="/open/">Open commitfest</a></li>
7+
<a class="btn btn-default" href="/archive/">Archive</a></li>
8+
<button type="button" class="btn btn-default{%if has_filter%} active{%endif%}" id="filterButton" onClick="togglePatchFilterButton('filterButton', 'collapseFilters')">Search/filter</button>
9+
<form method="GET" action="/search/" class="form-inline search-bar pull-right">
1910
<div class="form-group">
20-
<input type="text" class="form-control" id="searchterm" name="searchterm" placeholder="Global search">
11+
<input type="text" class="form-control" id="searchterm" name="searchterm" placeholder="Keyword or Message-ID">
2112
</div>
2213
<button type="submit" class="btn btn-default">Search</button>
2314
</form>
24-
<h3>List of commitfests</h3>
25-
<ul>
26-
{%for c in commitfests%}
27-
<li><a href="/{{c.id}}/">{{c}}</a> ({{c.statusstring}}{%if c.startdate%} - {{c.periodstring}}{%endif%})</li>
28-
{%endfor%}
29-
</ul>
30-
<br/>
15+
<div id="collapseFilters" class="collapse {%if has_filter%}in{%endif%}">
16+
<form id="filterform" method="GET" action="." style="margin-bottom: 0px">
17+
<table class="table table-condensed" style="margin-bottom: 0px">
18+
<thead>
19+
<tr>
20+
{%for f in form%}
21+
{%if not f.is_hidden%}
22+
<td>{{f.label}}</td>
23+
{%else%}
24+
<td></td>
25+
{%endif%}
26+
{%endfor%}
27+
{%comment%} Add one extra for buttons {%endcomment%}
28+
<td></td>
29+
</tr>
30+
</thead>
31+
<tbody>
32+
<tr>
33+
{%for f in form%}
34+
<td>{{f|field_class:"form-control"}}</td>
35+
{%endfor%}
36+
<td>
37+
<input type="submit" class="btn btn-default" value="Filter">
38+
<a class="btn btn-default" href=".">Clear</a>
39+
</td>
40+
</tr>
41+
</tbody>
42+
</table>
43+
</form>
44+
</div>
45+
{%for p in patches %}
46+
{%ifchanged p.is_open%}
47+
{%if not forloop.first%}
48+
</tbody>
49+
</table>
50+
{%endif%}
51+
<h3>{{user.is_authenticated|yesno:"Your personal dashboard,Patches in the current commitfest"}}</h3>
52+
<table class="table table-striped table-bordered table-hover table-condensed">
53+
<thead>
54+
<tr>
55+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(5);">Patch</a>{%if sortkey == 5%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -5%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
56+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(4);">ID</a>{%if sortkey == 4%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -4%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
57+
{%if user.is_authenticated %}
58+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(8);">CF</a>{%if sortkey == 8%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -8%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
59+
{%endif%}
60+
<th>Status</th>
61+
<th>Ver</th>
62+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(7);">CI status</a>{%if sortkey == 7%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -7%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
63+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(6);">Stats</a>{%if sortkey == 6%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -6%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
64+
<th>Author</th>
65+
<th>Reviewers</th>
66+
<th>Committer</th>
67+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(3);">Num cfs</a>{%if sortkey == 3%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -3%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
68+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(2);">Latest mail</a>{%if sortkey == 2%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-down"></i></div>{%elif sortkey == -2%}<div style="float:right;"><i class="glyphicon glyphicon-arrow-up"></i></div>{%endif%}</th>
69+
{%if user.is_staff%}
70+
<th>Select</th>
71+
{%endif%}
72+
</tr>
73+
</thead>
74+
<tbody>
75+
{%endifchanged%}
76+
77+
{%if grouping%}
78+
{%ifchanged p.topic%}
79+
<tr><th colspan="{%if user.is_staff%}13{%elif user.is_authenticated %}12{%else%}11{%endif%}">{{p.topic}}</th></tr>
80+
{%endifchanged%}
81+
{%endif%}
82+
<tr>
83+
<td><a href="/patch/{{p.id}}/">{{p.name}}</a></td>
84+
<td>{{p.id}}</td>
85+
{%if user.is_authenticated %}
86+
<td><a href="/{{p.cf_id}}/"><span class="label label-{{p.cf_status|commitfeststatuslabel}}">{{p.cf_name}}</span></a></td>
87+
{%endif%}
88+
<td><span class="label label-{{p.status|patchstatuslabel}}">{{p.status|patchstatusstring}}</span></td>
89+
<td>{%if p.targetversion%}<span class="label label-default">{{p.targetversion}}</span>{%endif%}</td>
90+
<td class="cfbot-summary">
91+
{%with p.cfbot_results as cfb%}
92+
{%if not cfb %}
93+
<span class="label label-default">Not processed</span>
94+
{%elif p.needs_rebase_since %}
95+
<a href="{{cfb.apply_url}}" title="View git apply logs. Needs rebase since {{p.needs_rebase_since|timesince}}. {%if p.failing_since and p.failing_since != p.needs_rebase_since %}Failing since {{p.failing_since|timesince}}.{%endif%}">
96+
<span class="label label-warning">Needs rebase!</span>
97+
</a>
98+
{%else%}
99+
<a href="https://github.com/postgresql-cfbot/postgresql/compare/cf/{{p.id}}~1...cf/{{p.id}}" title="View last patch set on GitHub"><img class="github-logo" src="/media/commitfest/github-mark.svg"/></a>
100+
<a href="https://cirrus-ci.com/github/postgresql-cfbot/postgresql/cf%2F{{p.id}}"
101+
title="View CI history. {%if p.failing_since%}Failing since {{p.failing_since|timesince}}. {%endif%}{%if cfb.failed_task_names %}Failed jobs: {{cfb.failed_task_names}}{%endif%}">
102+
{%if cfb.failed > 0 or cfb.branch_status == 'failed' or cfb.branch_status == 'timeout' %}
103+
<img src="/media/commitfest/new_failure.svg"/>
104+
{%elif cfb.completed < cfb.total %}
105+
<img src="/media/commitfest/running.svg"/>
106+
{%else%}
107+
<img src="/media/commitfest/new_success.svg"/>
108+
{%endif%}
109+
<span class="run-counters">
110+
{{cfb.completed}}/{{cfb.total}}
111+
</span>
112+
</a>
113+
{%endif%}
114+
</td>
115+
<td>
116+
{%if cfb and cfb.all_additions is not none %}
117+
<span class="additions">+{{ cfb.all_additions }}</span><span class="deletions">&#8722;{{ cfb.all_deletions }}</span>
118+
{%endif%}
119+
</td>
120+
{%endwith%}
121+
<td>{{p.author_names|default:''}}</td>
122+
<td>{{p.reviewer_names|default:''}}</td>
123+
<td>{{p.committer|default:''}}</td>
124+
<td>{{p.num_cfs}}</td>
125+
<td style="white-space: nowrap;" title="{{p.lastmail}}">{%if p.lastmail %}{{p.lastmail|timesince}} ago{%endif%}</td>
126+
{%if user.is_staff%}
127+
<td style="white-space: nowrap;"><input type="checkbox" class="sender_checkbox" id="send_authors_{{p.id}}">Author<br/><input type="checkbox" class="sender_checkbox" id="send_reviewers_{{p.id}}">Reviewer</td>
128+
{%endif%}
129+
</tr>
130+
{%if forloop.last%}
131+
</tbody>
132+
</table>
133+
{%endif%}
134+
{%endfor%}
31135
{%endblock%}

pgcommitfest/commitfest/templatetags/commitfest.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,25 @@
33

44
from uuid import uuid4
55

6-
from pgcommitfest.commitfest.models import PatchOnCommitFest
6+
from pgcommitfest.commitfest.models import CommitFest, PatchOnCommitFest
77

88
register = template.Library()
99

1010

11+
@register.filter(name="commitfeststatusstring")
12+
@stringfilter
13+
def commitfeststatusstring(value):
14+
i = int(value)
15+
return [v for k, v in CommitFest._STATUS_CHOICES if k == i][0]
16+
17+
18+
@register.filter(name="commitfeststatuslabel")
19+
@stringfilter
20+
def commitfeststatuslabel(value):
21+
i = int(value)
22+
return [v for k, v in CommitFest._STATUS_LABELS if k == i][0]
23+
24+
1125
@register.filter(name="patchstatusstring")
1226
@stringfilter
1327
def patchstatusstring(value):

0 commit comments

Comments
 (0)