feat: implement enhanced submission list
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Luca 2024-02-14 00:54:28 +01:00
parent d709f020f4
commit ca3ca52ab2
6 changed files with 216 additions and 3 deletions

View File

@ -1,7 +1,9 @@
from django import forms
from django.utils.translation import gettext_lazy as _
from django_scopes.forms import SafeModelChoiceField, SafeModelMultipleChoiceField
from i18nfield.forms import I18nModelForm
from pretalx.person.models import User
from pretalx.submission.forms import SubmissionFilterForm
from .models import Assignee, MusicrateSettings, Rating
@ -77,3 +79,7 @@ class AssigneeForm(forms.ModelForm):
model = Assignee
fields = ("user",)
widgets = {"user": forms.Select(attrs={"class": "select2"})}
class EnhancedSubmissionFilterForm(SubmissionFilterForm):
require_all_tags = forms.BooleanField(required=False, label=_("require all"))

View File

@ -24,10 +24,20 @@ def pretalx_musicrate_placeholders(sender, **kwargs):
@receiver(nav_event)
def pretalx_musicrate_qrcode(sender, request, **kwargs):
def pretalx_musicrate_nav_event(sender, request, **kwargs):
if not request.user.has_perm("orga.view_submissions", request.event):
return []
return [
{
"active": request.resolver_match.view_name
== "plugins:pretalx_musicrate:enhanced_list",
"icon": "sticky-note-o",
"label": _("Proposals, but better"),
"url": reverse(
"plugins:pretalx_musicrate:enhanced_list",
kwargs={"event": request.event.slug},
),
},
{
"active": request.resolver_match.view_name
== "plugins:pretalx_musicrate:qrcode",
@ -36,7 +46,7 @@ def pretalx_musicrate_qrcode(sender, request, **kwargs):
"url": reverse(
"plugins:pretalx_musicrate:qrcode", kwargs={"event": request.event.slug}
),
}
},
]

View File

@ -0,0 +1,11 @@
document.addEventListener("DOMContentLoaded", function() {
const updateRequireAllVisibility = () => {
if (document.querySelector("#id_tags").value) {
document.querySelector("#requireAll").classList.remove("d-none")
} else {
document.querySelector("#requireAll").classList.add("d-none")
}
}
$("#id_tags").on("change", updateRequireAllVisibility)
updateRequireAllVisibility()
})

View File

@ -0,0 +1,154 @@
{% extends "orga/base.html" %}
{% load bootstrap4 %}
{% load compress %}
{% load i18n %}
{% load rules %}
{% load static %}
{% load url_replace %}
{% block scripts %}
{% compress js %}
<script src="{% static "orga/js/submission_filter.js" %}"></script>
{% endcompress %}
{% compress js %}
<script src="{% static "pretalx_musicrate/submission_filter.js" %}"></script>
{% endcompress %}
{% endblock %}
{% block content %}
{% has_perm 'orga.change_submission_state' request.user request.event as can_change_submission %}
{% has_perm 'orga.view_speakers' request.user request.event as can_view_speakers %}
<h2>
{{ page_obj.paginator.count }}
{% blocktranslate trimmed count count=page_obj.paginator.count %}
proposal
{% plural %}
proposals
{% endblocktranslate %}
</h2>
<div class="submit-group search-submit-group">
<form class="search-form">
{% bootstrap_form search_form %}
{% if show_submission_types and filter_form.submission_type %}{% bootstrap_field filter_form.submission_type %}{% endif %}
<div class="d-flex flex-column form-group">
{% bootstrap_field filter_form.state layout='inline' %}
<div id="pending" class="d-none">{% bootstrap_field filter_form.pending_state__isnull layout='inline' %}</div>
</div>
{% if filter_form.track %}{% bootstrap_field filter_form.track %}{% endif %}
{% if filter_form.tags %}
<div class="d-flex flex-column form-group">
{% bootstrap_field filter_form.tags layout='inline' %}
<div id="requireAll" class="d-none">{% bootstrap_field filter_form.require_all_tags layout='inline' %}</div>
</div>
{% endif %}
{% if filter_form.content_locale %}{% bootstrap_field filter_form.content_locale %}{% endif %}
<button class="btn btn-success" type="submit">{% translate "Search" %}</button>
</form>
{% if filter_form.is_valid and filter_form.cleaned_data.question %}
<p class="text-muted ml-2">
<span class="fa fa-filter"></span>
{% blocktranslate trimmed with question=filter_form.cleaned_data.question.question %}
List filtered by answers to question "{{ question }}".
{% endblocktranslate %}
<a href="?{% url_replace request 'question' '' 'answer' '' 'answer__options' '' %}" class="text-muted">
<span class="fa fa-times"></span>
{% translate "Remove filter" %}
</a>
</p>
{% endif %}
</div>
<div class="table-responsive">
<table class="table table-sm table-hover table-flip">
<thead>
<tr>
<th>
{% translate "Rating" %}
<a href="?{% url_replace request 'sort' 'rating' %}"><i class="fa fa-caret-down" title="{% translate "Sort by rating (10-0)" %}"></i></a>
<a href="?{% url_replace request 'sort' '-rating' %}"><i class="fa fa-caret-up" title="{% translate "Sort by rating (0-10)" %}"></i></a>
</th>
<th>
{% translate "Title" %}
<a href="?{% url_replace request 'sort' 'title' %}"><i class="fa fa-caret-down" title="{% translate "Sort by title (a-z)" %}"></i></a>
<a href="?{% url_replace request 'sort' '-title' %}"><i class="fa fa-caret-up" title="{% translate "Sort by title (z-a)" %}"></i></a>
</th>
{% if show_submission_types %}
<th>
{% translate "Type" %}
</th>
{% endif %}
<th>
{% translate "State" %}
<a href="?{% url_replace request 'sort' 'state' %}"><i class="fa fa-caret-down" title="{% translate "Sort by state (a-z)" %}"></i></a>
<a href="?{% url_replace request 'sort' '-state' %}"><i class="fa fa-caret-up" title="{% translate "Sort by state (z-a)" %}"></i></a>
</th>
<th>
{% translate "Assignee" %}
<a href="?{% url_replace request 'sort' 'assignee' %}"><i class="fa fa-caret-down" title="{% translate "Sort by assignee (a-z)" %}"></i></a>
<a href="?{% url_replace request 'sort' '-assignee' %}"><i class="fa fa-caret-up" title="{% translate "Sort by assignee (z-a)" %}"></i></a>
</th>
{% if can_change_submission %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
{% for submission in submissions %}
<tr>
<td>
{% if submission.rating %}
{{ submission.rating.value }}
{% else %}
&ndash;
{% endif %}
</td>
<td>
<a href="{{ submission.orga_urls.base }}">
{% if can_view_speakers %}{{ submission.title }}{% else %}{{ submission.anonymised.title|default:submission.title }}{% endif %}
</a>
</td>
{% if show_submission_types %}
<td>
{{ submission.submission_type.name }}
</td>
{% endif %}
<td>
{% include "orga/submission/state_dropdown.html" with submission=submission %}
</td>
<td>
{% if submission.assignee %}
{{ submission.assignee.user.name }}
{% else %}
&ndash;
{% endif %}
{% if can_change_submission %}
<a class="btn btn-sm btn-link"
href="{% url "plugins:pretalx_musicrate:assignee" event=request.event.slug code=submission.code %}"
title="{% translate "edit" %}">
<i class="fa fa-edit"></i>
</a>
{% endif %}
</td>
{% if can_change_submission %}
<td class="action-column">
<a href="{{ submission.orga_urls.edit }}"
title="{% translate "edit" %}"
class="btn btn-sm btn-info">
<i class="fa fa-edit"></i>
</a>
<a href="{{ submission.orga_urls.delete }}?from=list"
title="{% translate "Delete" %}"
class="btn btn-sm btn-danger">
<i class="fa fa-trash"></i>
</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% include "orga/pagination.html" %}
{% endblock %}

View File

@ -2,6 +2,7 @@ from django.urls import include, path
from .views import (
AssigneeView,
EnhancedSubmissionList,
ExportView,
JoinView,
MayAdvanceView,
@ -26,6 +27,11 @@ urlpatterns = [
include(
[
path("export/", ExportView.as_view(), name="export"),
path(
"list/",
EnhancedSubmissionList.as_view(),
name="enhanced_list",
),
path("<code>/", AssigneeView.as_view(), name="assignee"),
]
),

View File

@ -15,9 +15,15 @@ from django.views.generic import FormView, TemplateView, View
from django.views.generic.detail import SingleObjectMixin
from django_context_decorator import context
from pretalx.common.mixins.views import EventPermissionRequired
from pretalx.orga.views.submission import SubmissionList
from pretalx.submission.models import Submission
from .forms import AssigneeForm, MusicrateSettingsForm, RatingForm
from .forms import (
AssigneeForm,
EnhancedSubmissionFilterForm,
MusicrateSettingsForm,
RatingForm,
)
from .models import Juror, Rating
youtube_re = re.compile(
@ -470,3 +476,23 @@ class AssigneeView(EventPermissionRequired, FormView, SingleObjectMixin):
def post(self, *args, **kwargs):
self.object = self.get_object()
return super().post(*args, **kwargs)
class EnhancedSubmissionList(SubmissionList):
sortable_fields = ("code", "rating", "title", "state", "assignee")
template_name = "pretalx_musicrate/enhanced_list.html"
def get_filter_form(self):
return EnhancedSubmissionFilterForm(
data=self.request.GET,
event=self.request.event,
usable_states=self.usable_states,
limit_tracks=self.limit_tracks,
)
def filter_queryset(self, qs):
qs = super().filter_queryset(qs.prefetch_related("assignee"))
if self.request.GET.get("require_all_tags", "") == "on":
for tag in self.request.GET.getlist("tags"):
qs = qs.filter(tags__in=[tag])
return qs