SciPost Code Repository

Skip to content
Snippets Groups Projects
Commit 3b80b089 authored by Jean-Sébastien Caux's avatar Jean-Sébastien Caux
Browse files

Install basic HTMX-driven searchable listing of nominations

parent eaa4947e
No related branches found
No related tags found
No related merge requests found
......@@ -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
{{ nomination }}
{% 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 %}
{% 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 %}
......@@ -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'
),
]
......@@ -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)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment