From 2a28c6a9c6ac9263ff6c5843c519cc620c63cc97 Mon Sep 17 00:00:00 2001 From: James Person Date: Wed, 1 Nov 2023 12:24:05 -0400 Subject: [PATCH 1/4] Form - Limit and page fields --- backend/dissemination/forms.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/dissemination/forms.py b/backend/dissemination/forms.py index bc3e41673e..5db043b3ea 100644 --- a/backend/dissemination/forms.py +++ b/backend/dissemination/forms.py @@ -6,6 +6,7 @@ class SearchForm(forms.Form): (x, str(x)) for x in range(2016, 2024) ) # ((2016, "2016"), (2017, "2017"), ..., (2023, "2023")) + # Query params entity_name = forms.CharField(required=False) uei_or_ein = forms.CharField(required=False) aln = forms.CharField(required=False) @@ -14,3 +15,7 @@ class SearchForm(forms.Form): cog_or_oversight = forms.CharField(required=False) agency_name = forms.CharField(required=False) audit_year = forms.MultipleChoiceField(choices=AY_choices, required=False) + + # Display params + limit = forms.CharField(required=False) + page = forms.CharField(required=False) From de2b61d5099c5bae8c2550e2648d4f38729dad1f Mon Sep 17 00:00:00 2001 From: James Person Date: Wed, 1 Nov 2023 12:24:38 -0400 Subject: [PATCH 2/4] View/HTML/JS - Pagination object implementation --- backend/dissemination/templates/search.html | 155 +++++++++--------- backend/dissemination/views.py | 32 +++- .../static/js/search-results-pagination.js | 38 +++++ 3 files changed, 147 insertions(+), 78 deletions(-) create mode 100644 backend/static/js/search-results-pagination.js diff --git a/backend/dissemination/templates/search.html b/backend/dissemination/templates/search.html index e0308a37c6..0017b70ddf 100644 --- a/backend/dissemination/templates/search.html +++ b/backend/dissemination/templates/search.html @@ -42,14 +42,14 @@

Filters

aria-controls="entity-name">Name (Entity, Auditee, or Auditor) - {% comment %} Fiscal Year {% endcomment %} + {% comment %} Audit Year {% endcomment %}
{% for value, text in form.audit_year.field.choices %} -
+
Filters
+ {% comment %} Hidden page input for use when clicking pagination buttons {% endcomment %} +
-

Search single audit reports

+

Search single audit reports

{% if results %} +
+
+

Sorting

+

+ Use the arrows at the top of each column to sort results. Sorting only applies to the results shown per page. +

+
+
@@ -137,8 +153,8 @@

Search single audit reports

- - + + @@ -146,7 +162,9 @@

Search single audit reports

- + {% comment %} Sorts ascending/descending by the numeric date string (i.e. 20231231) {% endcomment %} +
- Results {{ results|length }} + Results: {{ results_count }} + showing {{ limit }} per page
Acc Date AY Cog or OverViewPDFViewPDF
{{ result.auditee_name }} {{ result.auditee_uei }}{{ result.fac_accepted_date }}{{ result.fac_accepted_date }} + {{ result.audit_year }} {% if result.oversight_agency %} @@ -168,11 +186,13 @@

Search single audit reports

- + @@ -183,70 +203,53 @@

Search single audit reports

- {% else %} -
- an arrow points left, toward the search form -

- Enter your filters and select Search to begin -

+ {% if results.has_previous %} +
  • + + + Previous +
  • + {% endif %} + {% for page_number in results.adjusted_elided_pages %} + {% if page_number == results.paginator.ELLIPSIS %} +
  • + +
  • + {% else %} +
  • + {{ page_number }} +
  • + {% endif %} + {% endfor %} + {% if results.has_next %} +
  • + + Next + + +
  • + {% endif %} + + + {% else %} +
    + an arrow points left, toward the search form +

    + Enter your filters and select Search to begin +

    +
    + {% endif %}
    - {% endif %} +
    - - -{% endblock %} + +{% endblock content %} diff --git a/backend/dissemination/views.py b/backend/dissemination/views.py index e3d55bc2d7..c8b2e28ff6 100644 --- a/backend/dissemination/views.py +++ b/backend/dissemination/views.py @@ -1,4 +1,5 @@ -from django.core.exceptions import PermissionDenied +from django.core.exceptions import BadRequest, PermissionDenied +from django.core.paginator import Paginator from django.http import Http404 from django.shortcuts import get_object_or_404, redirect, render from django.views.generic import View @@ -30,6 +31,7 @@ def get(self, request, *args, **kwargs): def post(self, request, *args, **kwargs): form = SearchForm(request.POST) results = [] + context = {} if form.is_valid(): names = form.cleaned_data["entity_name"].splitlines() @@ -42,6 +44,13 @@ def post(self, request, *args, **kwargs): int(year) for year in form.cleaned_data["audit_year"] ] # Cast strings from HTML to int + print(form.cleaned_data) + + # TODO: Add a limit choice field to the form + limit = form.cleaned_data["limit"] or 30 + # Changed in the form via pagination links + page = form.cleaned_data["page"] or 1 + results = search_general( names, uei_or_eins, @@ -51,13 +60,32 @@ def post(self, request, *args, **kwargs): agency_name, audit_years, ) + results_count = results.count() # Total result count + paginator = Paginator( + results, per_page=limit + ) # Paginator object handles results splicing, page count, and pagination buttons + results = paginator.get_page(page) # Results for a given page + results.adjusted_elided_pages = paginator.get_elided_page_range( + page, on_each_side=1 + ) # Pagination buttons, adjust ellipses around the current page + # Reformat these so the date-picker elements in HTML prepopulate if form.cleaned_data["start_date"]: form.cleaned_data["start_date"] = start_date.strftime("%Y-%m-%d") if form.cleaned_data["end_date"]: form.cleaned_data["end_date"] = end_date.strftime("%Y-%m-%d") + else: + raise BadRequest("Form data validation error.", form.errors) + + context = context | { + "form": form, + "limit": limit, + "results": results, + "results_count": results_count, + "page": page, + } - return render(request, "search.html", {"form": form, "results": results}) + return render(request, "search.html", context) class AuditSummaryView(View): diff --git a/backend/static/js/search-results-pagination.js b/backend/static/js/search-results-pagination.js new file mode 100644 index 0000000000..9a103df2ba --- /dev/null +++ b/backend/static/js/search-results-pagination.js @@ -0,0 +1,38 @@ +var FORM = document.forms[1]; +const pagination_links = document.querySelectorAll('[aria-label^="Page"]'); +const next_page_link = document.querySelectorAll('[aria-label="Next page"]'); +const previous_page_link = document.querySelectorAll( + '[aria-label="Previous page"]' +); + +function attachEventHandlers() { + // If any pagination links are clicked, set the form element and submit it for a reload + pagination_links.forEach((link) => { + link.addEventListener('click', (e) => { + e.preventDefault(); + FORM.elements['page'].value = link.textContent; + FORM.submit(); + }); + }); + // If the next or previous page buttons are clicked, set the form element to be +/- 1 and submit for a reload + if (next_page_link[0]) { + next_page_link[0].addEventListener('click', (e) => { + e.preventDefault(); + FORM.elements['page'].value = parseInt(FORM.elements['page'].value) + 1; + FORM.submit(); + }); + } + if (previous_page_link[0]) { + previous_page_link[0].addEventListener('click', (e) => { + e.preventDefault(); + FORM.elements['page'].value = parseInt(FORM.elements['page'].value) - 1; + FORM.submit(); + }); + } +} + +function init() { + attachEventHandlers(); +} + +window.onload = init; From 469ddac6b4785d313efe35db6ce36fa8539ce766 Mon Sep 17 00:00:00 2001 From: James Person Date: Wed, 1 Nov 2023 12:24:53 -0400 Subject: [PATCH 3/4] Search - order by FAC accepted date by default --- backend/dissemination/search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/dissemination/search.py b/backend/dissemination/search.py index a0a63a4bbe..2d264fe268 100644 --- a/backend/dissemination/search.py +++ b/backend/dissemination/search.py @@ -49,6 +49,6 @@ def search_general( fiscal_year_match = Q(audit_year__in=audit_years) query.add(fiscal_year_match, Q.AND) - results = General.objects.filter(query) + results = General.objects.filter(query).order_by("-fac_accepted_date") return results From 7fa16b698064547e1c698ff4f9261cd1e83873d0 Mon Sep 17 00:00:00 2001 From: James Person Date: Wed, 1 Nov 2023 12:52:19 -0400 Subject: [PATCH 4/4] Remove a print --- backend/dissemination/views.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/dissemination/views.py b/backend/dissemination/views.py index c8b2e28ff6..a51e6a15a9 100644 --- a/backend/dissemination/views.py +++ b/backend/dissemination/views.py @@ -44,8 +44,6 @@ def post(self, request, *args, **kwargs): int(year) for year in form.cleaned_data["audit_year"] ] # Cast strings from HTML to int - print(form.cleaned_data) - # TODO: Add a limit choice field to the form limit = form.cleaned_data["limit"] or 30 # Changed in the form via pagination links