From 3b80b0895ab49caf6aa8740b408c4e57ffc38324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20Caux?= <git@jscaux.org> Date: Fri, 28 Jan 2022 18:07:49 +0100 Subject: [PATCH] Install basic HTMX-driven searchable listing of nominations --- scipost_django/colleges/forms.py | 51 +++++++++++++++++-- .../templates/colleges/_hx_nomination_li.html | 1 + .../templates/colleges/_hx_nominations.html | 22 ++++++++ .../templates/colleges/nominations.html | 42 +++++++++++++++ scipost_django/colleges/urls.py | 12 +++++ scipost_django/colleges/views.py | 43 ++++++++++++++-- 6 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 scipost_django/colleges/templates/colleges/_hx_nomination_li.html create mode 100644 scipost_django/colleges/templates/colleges/_hx_nominations.html create mode 100644 scipost_django/colleges/templates/colleges/nominations.html diff --git a/scipost_django/colleges/forms.py b/scipost_django/colleges/forms.py index 06f13cf2b..6c04ab986 100644 --- a/scipost_django/colleges/forms.py +++ b/scipost_django/colleges/forms.py @@ -8,7 +8,7 @@ from django import forms from django.db.models import Q from crispy_forms.helper import FormHelper -from crispy_forms.layout import Layout, Field +from crispy_forms.layout import Layout, Div, Field from crispy_bootstrap5.bootstrap5 import FloatingField from dal import autocomplete @@ -18,9 +18,15 @@ from submissions.models import Submission from scipost.forms import RequestFormMixin from scipost.models import Contributor -from .models import Fellowship, PotentialFellowship, PotentialFellowshipEvent -from .constants import POTENTIAL_FELLOWSHIP_IDENTIFIED, POTENTIAL_FELLOWSHIP_NOMINATED,\ +from .models import ( + College, Fellowship, + PotentialFellowship, PotentialFellowshipEvent, + FellowshipNomination, +) +from .constants import ( + POTENTIAL_FELLOWSHIP_IDENTIFIED, POTENTIAL_FELLOWSHIP_NOMINATED, POTENTIAL_FELLOWSHIP_EVENT_DEFINED, POTENTIAL_FELLOWSHIP_EVENT_NOMINATED +) class FellowshipSelectForm(forms.Form): @@ -270,3 +276,42 @@ class PotentialFellowshipEventForm(forms.ModelForm): self.fields['comments'].widget.attrs.update({ 'placeholder': 'NOTA BENE: careful, will be visible to all who have voting rights' }) + + +############### +# Nominations # +############### + +class FellowshipNominationSearchForm(forms.Form): + """Filter a FellowshipNomination queryset using basic search fields.""" + + college = forms.ModelChoiceField( + queryset=College.objects.all(), + required=False + ) + profile = forms.ModelChoiceField( + queryset=Profile.objects.all(), + widget=autocomplete.ModelSelect2(url='/profiles/profile-autocomplete'), + required=False + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.layout = Layout( + Div( + Div(FloatingField('college'), css_class='col-lg-6'), + Div(FloatingField('profile'), css_class='col-lg-6'), + css_class='row' + ) + ) + + def search_results(self): + if self.cleaned_data.get('profile'): + nominations = FellowshipNomination.objects.filter( + profile=self.cleaned_data.get('profile')) + else: + nominations = FellowshipNomination.objects.all() + if self.cleaned_data.get('college'): + nominations = nominations.filter(college=self.cleaned_data.get('college')) + return nominations diff --git a/scipost_django/colleges/templates/colleges/_hx_nomination_li.html b/scipost_django/colleges/templates/colleges/_hx_nomination_li.html new file mode 100644 index 000000000..a5aaf6406 --- /dev/null +++ b/scipost_django/colleges/templates/colleges/_hx_nomination_li.html @@ -0,0 +1 @@ +{{ nomination }} diff --git a/scipost_django/colleges/templates/colleges/_hx_nominations.html b/scipost_django/colleges/templates/colleges/_hx_nominations.html new file mode 100644 index 000000000..1265eec30 --- /dev/null +++ b/scipost_django/colleges/templates/colleges/_hx_nominations.html @@ -0,0 +1,22 @@ +{% for nomination in page_obj %} + <li class="p-2 mb-2" id="nomination_{{ nomination.id }}"> + {% include 'colleges/_hx_nomination_li.html' with nomination=nomination %} + </li> +{% empty %} + <li>No Nomination could be found</li> +{% endfor %} +{% if page_obj.has_next %} + <li hx-post="{% url 'colleges:_hx_nominations' %}?page={{ page_obj.next_page_number }}" + hx-include="#search-form" + hx-trigger="revealed" + hx-swap="afterend" + hx-indicator="#indicator-search-page-{{ page_obj.number }}" + > + <div id="indicator-search-page-{{ page_obj.number }}" class="htmx-indicator p-2"> + <button class="btn btn-warning" type="button" disabled> + <strong>Loading page {{ page_obj.next_page_number }} out of {{ page_obj.paginator.num_pages }}</strong> + <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div> + </button> + </div> + </li> +{% endif %} diff --git a/scipost_django/colleges/templates/colleges/nominations.html b/scipost_django/colleges/templates/colleges/nominations.html new file mode 100644 index 000000000..e3840f52b --- /dev/null +++ b/scipost_django/colleges/templates/colleges/nominations.html @@ -0,0 +1,42 @@ +{% extends 'colleges/base.html' %} + +{% load crispy_forms_tags %} + +{% block breadcrumb_items %} + {{ block.super }} + <a href="{% url 'colleges:colleges' %}" class="breadcrumb-item">Colleges</a> + <span class="breadcrumb-item">Nominations</span> +{% endblock %} + +{% block meta_description %}{{ block.super }} Nominations{% endblock meta_description %} +{% block pagetitle %}: Nominations{% endblock pagetitle %} + +{% block content %} + + <h1 class="highlight">Fellowship Nominations</h1> + + <div class="card"> + <div class="card-header"> + Search / filter + </div> + <div class="card-body"> + <form + hx-post="{% url 'colleges:_hx_nominations' %}" + hx-trigger="load, keyup delay:500ms, change" + hx-target="#search-results" + hx-indicator="#indicator-search" + > + <div id="search-form">{% crispy form %}</div> + </form> + </div> + </div> + <div id="indicator-search" class="htmx-indicator p-2"> + <button class="btn btn-warning" type="button" disabled> + <strong>Loading...</strong> + <div class="spinner-grow spinner-grow-sm ms-2" role="status" aria-hidden="true"></div> + </button> + </div> + <ul id="search-results" class="list-unstyled mt-2"></ul> + + +{% endblock content %} diff --git a/scipost_django/colleges/urls.py b/scipost_django/colleges/urls.py index a5bee2f2f..3205efe29 100644 --- a/scipost_django/colleges/urls.py +++ b/scipost_django/colleges/urls.py @@ -158,4 +158,16 @@ urlpatterns = [ views.PotentialFellowshipListView.as_view(), name='potential_fellowships' ), + + # Nominations + path( + 'nominations', + views.nominations, + name='nominations' + ), + path( + '_hx_nominations', + views._hx_nominations, + name='_hx_nominations' + ), ] diff --git a/scipost_django/colleges/views.py b/scipost_django/colleges/views.py index c76603285..64b3b8224 100644 --- a/scipost_django/colleges/views.py +++ b/scipost_django/colleges/views.py @@ -9,6 +9,7 @@ from dal import autocomplete from django.contrib import messages from django.contrib.auth.models import Group from django.contrib.auth.decorators import login_required, permission_required, user_passes_test +from django.core.paginator import Paginator from django.urls import reverse, reverse_lazy from django.http import Http404 from django.shortcuts import get_object_or_404, render, redirect @@ -25,10 +26,14 @@ from .constants import ( POTENTIAL_FELLOWSHIP_INVITED, POTENTIAL_FELLOWSHIP_ACTIVE_IN_COLLEGE, potential_fellowship_statuses_dict, POTENTIAL_FELLOWSHIP_EVENT_VOTED_ON, POTENTIAL_FELLOWSHIP_EVENT_EMAILED) -from .forms import FellowshipDynSelForm, FellowshipForm, FellowshipRemoveSubmissionForm,\ - FellowshipAddSubmissionForm, SubmissionAddFellowshipForm,\ - FellowshipRemoveProceedingsForm, FellowshipAddProceedingsForm, \ - PotentialFellowshipForm, PotentialFellowshipStatusForm, PotentialFellowshipEventForm +from .forms import ( + FellowshipDynSelForm, FellowshipForm, + FellowshipRemoveSubmissionForm, FellowshipAddSubmissionForm, + SubmissionAddFellowshipForm, + FellowshipRemoveProceedingsForm, FellowshipAddProceedingsForm, + PotentialFellowshipForm, PotentialFellowshipStatusForm, PotentialFellowshipEventForm, + FellowshipNominationSearchForm, +) from .models import College, Fellowship, PotentialFellowship, PotentialFellowshipEvent from scipost.forms import EmailUsersForm, SearchTextForm @@ -513,3 +518,33 @@ class PotentialFellowshipEventCreateView(PermissionsMixin, CreateView): form.instance.noted_by = self.request.user.contributor messages.success(self.request, 'Event added successfully') return super().form_valid(form) + + +############### +# Nominations # +############### + + +@login_required +@user_passes_test(is_edadmin_or_senior_fellow) +def nominations(request): + """ + List Nominations. + """ + context = { + 'form': FellowshipNominationSearchForm() + } + return render(request, 'colleges/nominations.html', context) + + +def _hx_nominations(request): + form = FellowshipNominationSearchForm(request.POST or None) + if form.is_valid(): + nominations = form.search_results() + else: + nominations = FellowshipNomination.objects.all() + paginator = Paginator(nominations, 16) + page_nr = request.GET.get('page') + page_obj = paginator.get_page(page_nr) + context = { 'page_obj': page_obj } + return render(request, 'colleges/_hx_nominations.html', context) -- GitLab