diff --git a/passbook/admin/views/utils.py b/passbook/admin/views/utils.py index e0f1547ec..f9be49555 100644 --- a/passbook/admin/views/utils.py +++ b/passbook/admin/views/utils.py @@ -1,13 +1,15 @@ """passbook admin util views""" -from typing import Any, Dict, Optional +from typing import Any, Dict, List, Optional from urllib.parse import urlparse from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin +from django.contrib.postgres.search import SearchQuery, SearchVector from django.db.models import QuerySet from django.http import Http404 from django.http.request import HttpRequest from django.views.generic import DeleteView, ListView, UpdateView +from django.views.generic.list import MultipleObjectMixin from passbook.lib.utils.reflection import all_subclasses from passbook.lib.views import CreateAssignPermView @@ -32,6 +34,26 @@ class InheritanceListView(ListView): return super().get_queryset().select_subclasses() +class SearchListMixin(MultipleObjectMixin): + """Accept search query using `search` querystring parameter. Requires self.search_fields, + a list of all fields to search. Can contain special lookups like __icontains""" + + search_fields: List[str] + + def get_queryset(self) -> QuerySet: + queryset = super().get_queryset() + if "search" in self.request.GET: + raw_query = self.request.GET["search"] + if raw_query == "": + # Empty query, don't search at all + return queryset + search = SearchQuery(raw_query, search_type="websearch") + return queryset.annotate(search=SearchVector(*self.search_fields)).filter( + search=search + ) + return queryset + + class InheritanceCreateView(CreateAssignPermView): """CreateView for objects using InheritanceManager""" diff --git a/passbook/core/templates/partials/toolbar_search.html b/passbook/core/templates/partials/toolbar_search.html new file mode 100644 index 000000000..aac4c9f30 --- /dev/null +++ b/passbook/core/templates/partials/toolbar_search.html @@ -0,0 +1,13 @@ + +
diff --git a/passbook/static/static/passbook/passbook.js b/passbook/static/static/passbook/passbook.js index 3e0a31645..948b2ca6e 100644 --- a/passbook/static/static/passbook/passbook.js +++ b/passbook/static/static/passbook/passbook.js @@ -7,6 +7,14 @@ document.querySelectorAll("button.pf-c-dropdown__toggle").forEach((b) => { }); }); +document.querySelectorAll("input[type=search]").forEach((si) => { + si.addEventListener("search", (e) => { + if (si.value === "") { + si.parentElement.submit(); + } + }); +}); + // Modal document.querySelectorAll("[data-target='modal']").forEach((m) => { m.addEventListener("click", (e) => {