Skip to content

Commit 8fe496f

Browse files
committed
Update the global search page with all the fancy filters
The global search page did not allow filtering by any of the things that other pages allowed. This adds that filtering and sorting, as well as a bunch of additional columns. It doesn't show CI status and stats for now.
1 parent de5bc24 commit 8fe496f

File tree

3 files changed

+193
-24
lines changed

3 files changed

+193
-24
lines changed

pgcommitfest/commitfest/templates/patch.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@
4444
{%endif%}
4545
{%if cfbot_branch %}
4646
<button class="btn btn-secondary" title="This adds the following to your clipboard (needs to be run in an existing git repo):
47-
git remote add commitfest https://github.com/postgresql-cfbot/postgresql.git
48-
git fetch commitfest cf/{{patch.id}}
49-
git checkout commitfest/cf/{{patch.id}}" onclick="addGitCheckoutToClipboard({{patch.id}})">Copy git checkout commands</button>
47+
git remote add commitfest https://github.com/postgresql-cfbot/postgresql.git
48+
git fetch commitfest cf/{{patch.id}}
49+
git checkout commitfest/cf/{{patch.id}}" onclick="addGitCheckoutToClipboard({{patch.id}})">Copy git checkout commands</button>
5050
{%endif%}
5151
</a>
5252
</td>

pgcommitfest/commitfest/templates/patchsearch.html

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,119 @@
22
{%load commitfest %}
33
{%block contents%}
44

5-
<form method="GET" action="/search/" class="d-flex gap-2" style="margin-bottom: 10px">
6-
<div class="form-group">
7-
<input type="text" class="form-control" id="searchterm" name="searchterm" placeholder="Global search">
5+
<!-- Search term input -->
6+
<form method="GET" action="/search/" class="d-flex gap-2 mb-3">
7+
<div class="form-group flex-grow-1">
8+
<input type="text" class="form-control" id="searchterm" name="searchterm" value="{{searchterm}}" placeholder="Email Message-ID or keywords" required>
89
</div>
9-
<button type="submit" class="btn btn-secondary">Search</button>
10+
<button type="submit" class="btn btn-secondary">
11+
<i class="bi bi-search"></i> Search
12+
</button>
1013
</form>
1114

15+
<!-- Filter form (same as other pages) -->
16+
<div id="collapseFilters" class="collapse show">
17+
<form id="filterform" method="GET" action="/search/" style="margin-bottom: 0px">
18+
<input type="hidden" name="searchterm" value="{{searchterm}}">
19+
<table class="table" style="margin-bottom: 0px">
20+
<thead>
21+
<tr>
22+
{%for f in form%}
23+
{%if not f.is_hidden%}
24+
<td>{{f.label}}</td>
25+
{%else%}
26+
<td></td>
27+
{%endif%}
28+
{%endfor%}
29+
<td></td>
30+
</tr>
31+
</thead>
32+
<tbody>
33+
<tr>
34+
{%for f in form%}
35+
<td>
36+
{%if not f.name in form.selectize_fields%}{{f|field_class:"form-control"}}{%else%}{{f}}{%endif%}
37+
</td>
38+
{%endfor%}
39+
<td>
40+
<input type="submit" class="btn btn-secondary" value="Filter">
41+
<a class="btn btn-secondary" href="/search/?searchterm={{searchterm}}">Clear</a>
42+
</td>
43+
</tr>
44+
</tbody>
45+
</table>
46+
</form>
47+
</div>
48+
49+
{% if patches %}
50+
<p class="text-muted">Found {{patches|length}} patch{% if patches|length != 1 %}es{% endif %} matching "{{searchterm}}"</p>
51+
{% endif %}
52+
1253
<table class="table table-striped table-bordered table-hover">
1354
<thead>
1455
<tr>
15-
<th>Patch</th>
56+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(5);">Patch</a>{%if sortkey == 5%}<div style="float:right;"><i class="bi bi-sort-alpha-down"></i></div>{%elif sortkey == -5%}<div style="float:right;"><i class="bi bi-sort-alpha-up"></i></div>{%endif%}</th>
57+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(4);">ID</a>{%if sortkey == 4%}<div style="float:right;"><i class="bi bi-sort-numeric-down"></i></div>{%elif sortkey == -4%}<div style="float:right;"><i class="bi bi-sort-numeric-up"></i></div>{%endif%}</th>
58+
<th>
59+
<a href="#" style="color:#333333;" onclick="return sortpatches(8);">CF</a>
60+
<i class="bi bi-question-circle text-muted" style="font-size: 0.8em; margin-left: 3px;" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" title="Color coding:<br>Green = In Progress<br>Blue = Open<br>Red = Closed"></i>
61+
{%if sortkey == 8%}<div style="float:right;"><i class="bi bi-sort-numeric-down"></i></div>{%elif sortkey == -8%}<div style="float:right;"><i class="bi bi-sort-numeric-up"></i></div>{%endif%}
62+
</th>
1663
<th>Status</th>
64+
<th>Tags</th>
65+
<th>Ver</th>
1766
<th>Author</th>
67+
<th>Reviewers</th>
68+
<th>Committer</th>
69+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(3);">Num cfs</a>{%if sortkey == 3%}<div style="float:right;"><i class="bi bi-sort-numeric-down-alt"></i></div>{%elif sortkey == -3%}<div style="float:right;"><i class="bi bi-sort-numeric-up-alt"></i></div>{%endif%}</th>
70+
<th><a href="#" style="color:#333333;" onclick="return sortpatches(2);">Latest mail</a>{%if sortkey == 2%}<div style="float:right;"><i class="bi bi-sort-down"></i></div>{%elif sortkey == -2%}<div style="float:right;"><i class="bi bi-sort-up"></i></div>{%endif%}</th>
1871
</tr>
1972
</thead>
2073
<tbody>
2174
{%for p in patches %}
22-
{%with p.patchoncommitfest_set.all as cfs %}
23-
<tr>
24-
<td>{%with cfs|first as firstcf%}<a href="/{{firstcf.commitfest_id}}/{{p.id}}/">{{p}}</a>{%endwith%}</td>
25-
<td>{%for c in cfs %}
26-
<div style="margin-bottom: 3px;">{{c.commitfest}}: <span class="badge bg-secondary">{{c.statusstring}}</span></div>
27-
{%endfor%}</td>
28-
<td>{{p.authors_string|default:''}}</td>
29-
</tr>
30-
{%endwith%}
75+
<tr>
76+
<td><a href="/patch/{{p.id}}/">{{p.name}}</a></td>
77+
<td>{{p.id}}</td>
78+
<td>
79+
{%with p.patchoncommitfest_set.all|first as poc%}
80+
{%if poc%}<a href="/{{poc.commitfest.id}}/"><span class="badge bg-{{poc.commitfest.status|commitfeststatuslabel}}" title="{{poc.commitfest.status|commitfeststatusstring}}">{{poc.commitfest.name}}</span></a>{%endif%}
81+
{%endwith%}
82+
</td>
83+
<td>
84+
{%with p.patchoncommitfest_set.all|first as poc%}
85+
{%if poc%}<span class="badge bg-{{poc.status|patchstatuslabel}}">{{poc.status|patchstatusstring}}</span>{%endif%}
86+
{%endwith%}
87+
</td>
88+
<td style="width: min-content;">
89+
{%for tag in p.tags.all%}
90+
<a href="?searchterm={{searchterm}}&tag={{tag.id}}">
91+
<span class="badge" style="background-color: {{tag.color}};" title="{{tag.description}}">{{tag.name}}</span>
92+
</a>
93+
{%endfor%}
94+
</td>
95+
<td>{%if p.targetversion%}<span class="badge bg-secondary">{{p.targetversion}}</span>{%endif%}</td>
96+
<td>
97+
{% for author in p.authors.all %}
98+
{{author.get_full_name|default:author.username}}{% if not forloop.last %}, {% endif %}
99+
{% endfor %}
100+
</td>
101+
<td>
102+
{% for reviewer in p.reviewers.all %}
103+
{{reviewer.get_full_name|default:reviewer.username}}{% if not forloop.last %}, {% endif %}
104+
{% endfor %}
105+
</td>
106+
<td>{% if p.committer %}{{p.committer.fullname}}{% endif %}</td>
107+
<td>{{p.patchoncommitfest_set.count}}</td>
108+
<td style="white-space: nowrap;" title="{{p.modified}}">
109+
{%if p.modified and userprofile.show_relative_timestamps %}{% cfwhen p.modified %}{%elif p.modified %}{{p.modified|date:"Y-m-d"}}<br/>{{p.modified|date:"H:i"}}{%endif%}
110+
</td>
111+
</tr>
31112
{%endfor%}
32113
</tbody>
33114
</table>
34115

35116
{%endblock%}
117+
118+
{%block morescript%}
119+
{%include "selectize_js.html" %}
120+
{%endblock%}

pgcommitfest/commitfest/views.py

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.contrib.auth.decorators import login_required
44
from django.contrib.auth.models import User
55
from django.db import connection, transaction
6-
from django.db.models import Q
6+
from django.db.models import Count, Q
77
from django.http import (
88
Http404,
99
HttpResponse,
@@ -692,25 +692,109 @@ def global_search(request):
692692
patches = patches_by_messageid(cleaned_id)
693693

694694
if not patches:
695-
patches = (
696-
Patch.objects.select_related()
697-
.filter(name__icontains=searchterm)
698-
.order_by(
699-
"created",
695+
patches_query = (
696+
Patch.objects.select_related("targetversion", "committer")
697+
.prefetch_related(
698+
"authors",
699+
"reviewers",
700+
"tags",
701+
"patchoncommitfest_set__commitfest",
702+
"mailthread_set",
700703
)
701-
.all()
704+
.select_related("cfbot_branch")
705+
.filter(name__icontains=searchterm)
702706
)
703707

708+
# Apply filters using the same logic as patchlist
709+
if request.GET.get("status", "-1") != "-1":
710+
try:
711+
status = int(request.GET["status"])
712+
patches_query = patches_query.filter(
713+
patchoncommitfest__status=status
714+
).distinct()
715+
except ValueError:
716+
pass
717+
718+
if request.GET.get("targetversion", "-1") != "-1":
719+
if request.GET["targetversion"] == "-2":
720+
patches_query = patches_query.filter(targetversion_id__isnull=True)
721+
else:
722+
try:
723+
ver_id = int(request.GET["targetversion"])
724+
patches_query = patches_query.filter(targetversion_id=ver_id)
725+
except ValueError:
726+
pass
727+
728+
if request.GET.getlist("tag"):
729+
try:
730+
tag_ids = [int(t) for t in request.GET.getlist("tag")]
731+
for tag_id in tag_ids:
732+
patches_query = patches_query.filter(tags__id=tag_id)
733+
patches_query = patches_query.distinct()
734+
except ValueError:
735+
pass
736+
737+
# Apply sorting based on sortkey parameter (adapted for Django ORM)
738+
sortkey = request.GET.get("sortkey", "1")
739+
if sortkey == "2": # Latest mail
740+
patches_query = patches_query.order_by("-modified") # Use modified as proxy
741+
elif sortkey == "-2":
742+
patches_query = patches_query.order_by("modified")
743+
elif sortkey == "3": # Num cfs
744+
patches_query = patches_query.annotate(
745+
num_cfs=Count("patchoncommitfest")
746+
).order_by("-num_cfs")
747+
elif sortkey == "-3":
748+
patches_query = patches_query.annotate(
749+
num_cfs=Count("patchoncommitfest")
750+
).order_by("num_cfs")
751+
elif sortkey == "4": # ID
752+
patches_query = patches_query.order_by("id")
753+
elif sortkey == "-4":
754+
patches_query = patches_query.order_by("-id")
755+
elif sortkey == "5": # Patch name
756+
patches_query = patches_query.order_by("name")
757+
elif sortkey == "-5":
758+
patches_query = patches_query.order_by("-name")
759+
elif sortkey == "8": # CF
760+
patches_query = patches_query.order_by("patchoncommitfest__commitfest__id")
761+
elif sortkey == "-8":
762+
patches_query = patches_query.order_by("-patchoncommitfest__commitfest__id")
763+
else: # Default: Created (sortkey 1)
764+
patches_query = patches_query.order_by("created")
765+
766+
patches = patches_query.all()
767+
704768
if len(patches) == 1:
705769
patch = patches[0]
706770
return HttpResponseRedirect(f"/patch/{patch.id}/")
707771

772+
# Use the existing filter form
773+
form = CommitFestFilterForm(request.GET)
774+
775+
# Get user profile for timestamp preferences
776+
userprofile = None
777+
if request.user.is_authenticated:
778+
try:
779+
from pgcommitfest.userprofile.models import UserProfile
780+
781+
userprofile = UserProfile.objects.get(user=request.user)
782+
except UserProfile.DoesNotExist:
783+
pass
784+
708785
return render(
709786
request,
710787
"patchsearch.html",
711788
{
712789
"patches": patches,
713790
"title": "Patch search results",
791+
"searchterm": searchterm,
792+
"form": form,
793+
"cf": None, # No specific commitfest context
794+
"sortkey": int(request.GET.get("sortkey") or "1"),
795+
"tags_data": get_tags_data(),
796+
"all_tags": {t.id: t for t in Tag.objects.all()},
797+
"userprofile": userprofile,
714798
},
715799
)
716800

0 commit comments

Comments
 (0)