Table filters
* adds table filtering for InterventionTable * adds default ordering * moves user-access filtering from view to InterventionTableFiler * adds generic render_icn method for BaseTable (for usage with fontawesome5) * adds translations * improves table.html template
This commit is contained in:
parent
117c740bad
commit
591bc739ec
113
intervention/filters.py
Normal file
113
intervention/filters.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
"""
|
||||||
|
Author: Michel Peltriaux
|
||||||
|
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||||
|
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||||
|
Created on: 22.07.21
|
||||||
|
|
||||||
|
"""
|
||||||
|
import django_filters
|
||||||
|
from django import forms
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.db.models import QuerySet, Q
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from intervention.models import Intervention
|
||||||
|
|
||||||
|
|
||||||
|
class InterventionTableFilter(django_filters.FilterSet):
|
||||||
|
q = django_filters.Filter(
|
||||||
|
method='_filter_by_keyword',
|
||||||
|
widget=forms.HiddenInput(), # use search bar in template, we only need the filter logic in here!
|
||||||
|
)
|
||||||
|
sa = django_filters.BooleanFilter(
|
||||||
|
method='_filter_show_all',
|
||||||
|
label=_("Show all"),
|
||||||
|
label_suffix=_(""),
|
||||||
|
widget=forms.CheckboxInput()
|
||||||
|
)
|
||||||
|
sr = django_filters.BooleanFilter(
|
||||||
|
method='_filter_show_recorded',
|
||||||
|
label=_("Show recorded"),
|
||||||
|
label_suffix=_(""),
|
||||||
|
widget=forms.CheckboxInput()
|
||||||
|
)
|
||||||
|
# Gemarkung ##ToDo
|
||||||
|
g = django_filters.CharFilter(
|
||||||
|
field_name="name",
|
||||||
|
lookup_expr="icontains",
|
||||||
|
label=_(""),
|
||||||
|
label_suffix=_(""),
|
||||||
|
widget=forms.TextInput(
|
||||||
|
attrs={
|
||||||
|
"placeholder": _("District"),
|
||||||
|
"title": _("Search for district")
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Kreis
|
||||||
|
## ToDo
|
||||||
|
# Flur
|
||||||
|
## ToDo
|
||||||
|
# Zähler
|
||||||
|
## ToDo
|
||||||
|
# Nenner
|
||||||
|
## ToDo
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Intervention
|
||||||
|
fields = []
|
||||||
|
|
||||||
|
def __init__(self, user: User, *args, **kwargs):
|
||||||
|
self.user = user
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def _filter_by_keyword(self, queryset, name, value) -> QuerySet:
|
||||||
|
""" Filters queryset depending on value of search bar input
|
||||||
|
|
||||||
|
Args:
|
||||||
|
queryset ():
|
||||||
|
name ():
|
||||||
|
value ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
# build filter expression
|
||||||
|
q = Q(title__icontains=value) | Q(identifier__icontains=value)
|
||||||
|
return queryset.filter(q)
|
||||||
|
|
||||||
|
def _filter_show_all(self, queryset, name, value) -> QuerySet:
|
||||||
|
""" Filters queryset depending on value of 'show_all' setting
|
||||||
|
|
||||||
|
Args:
|
||||||
|
queryset ():
|
||||||
|
name ():
|
||||||
|
value ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return queryset.filter(
|
||||||
|
users__in=[self.user], # requesting user has access
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def _filter_show_recorded(self, queryset, name, value) -> QuerySet:
|
||||||
|
""" Filters queryset depending on value of 'show_recorded' setting
|
||||||
|
|
||||||
|
Args:
|
||||||
|
queryset ():
|
||||||
|
name ():
|
||||||
|
value ():
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not value:
|
||||||
|
return queryset.filter(
|
||||||
|
recorded_on=None,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return queryset
|
@ -5,11 +5,13 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
|||||||
Created on: 01.12.20
|
Created on: 01.12.20
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from django.http import HttpRequest
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.timezone import localtime
|
from django.utils.timezone import localtime
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from intervention.filters import InterventionTableFilter
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
|
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
|
||||||
from konova.utils.tables import BaseTable
|
from konova.utils.tables import BaseTable
|
||||||
@ -39,6 +41,12 @@ class InterventionTable(BaseTable):
|
|||||||
empty_values=[],
|
empty_values=[],
|
||||||
accessor="recorded_on",
|
accessor="recorded_on",
|
||||||
)
|
)
|
||||||
|
e = tables.Column(
|
||||||
|
verbose_name=_("Editable"),
|
||||||
|
orderable=True,
|
||||||
|
empty_values=[],
|
||||||
|
accessor="users",
|
||||||
|
)
|
||||||
lm = tables.Column(
|
lm = tables.Column(
|
||||||
verbose_name=_("Last edit"),
|
verbose_name=_("Last edit"),
|
||||||
orderable=True,
|
orderable=True,
|
||||||
@ -58,10 +66,16 @@ class InterventionTable(BaseTable):
|
|||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
template_name = "django_tables2/bootstrap4.html"
|
template_name = "django_tables2/bootstrap4.html"
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, request: HttpRequest, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
self.title = _("Interventions")
|
self.title = _("Interventions")
|
||||||
self.add_new_url = reverse("intervention:new")
|
self.add_new_url = reverse("intervention:new")
|
||||||
|
qs = kwargs.get("queryset", None)
|
||||||
|
self.filter = InterventionTableFilter(
|
||||||
|
user=request.user,
|
||||||
|
data=request.GET,
|
||||||
|
queryset=qs,
|
||||||
|
)
|
||||||
|
super().__init__(request, self.filter, *args, **kwargs)
|
||||||
|
|
||||||
def render_id(self, value, record: Intervention):
|
def render_id(self, value, record: Intervention):
|
||||||
""" Renders the id column for an intervention
|
""" Renders the id column for an intervention
|
||||||
@ -128,6 +142,27 @@ class InterventionTable(BaseTable):
|
|||||||
)
|
)
|
||||||
return format_html(html)
|
return format_html(html)
|
||||||
|
|
||||||
|
def render_e(self, value, record: Intervention):
|
||||||
|
""" Renders the registered column for an intervention
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (str): The identifier value
|
||||||
|
record (Intervention): The intervention record
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
html = ""
|
||||||
|
has_access = value.filter(
|
||||||
|
username=self.user.username
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
html += self.render_icn(
|
||||||
|
tooltip=_("Full access granted") if has_access else _("Access not granted"),
|
||||||
|
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",
|
||||||
|
)
|
||||||
|
return format_html(html)
|
||||||
|
|
||||||
def render_ac(self, value, record):
|
def render_ac(self, value, record):
|
||||||
"""
|
"""
|
||||||
Renders possible actions for this record, such as delete.
|
Renders possible actions for this record, such as delete.
|
||||||
|
@ -24,11 +24,13 @@ def index_view(request: HttpRequest):
|
|||||||
A rendered view
|
A rendered view
|
||||||
"""
|
"""
|
||||||
template = "generic_index.html"
|
template = "generic_index.html"
|
||||||
user = request.user
|
|
||||||
|
# Filtering by user access is performed in table filter inside of InterventionTableFilter class
|
||||||
interventions = Intervention.objects.filter(
|
interventions = Intervention.objects.filter(
|
||||||
deleted_on=None, # not deleted
|
deleted_on=None, # not deleted
|
||||||
next_version=None, # only newest versions
|
next_version=None, # only newest versions
|
||||||
users__in=[user], # requesting user has access
|
).order_by(
|
||||||
|
"-created_on"
|
||||||
)
|
)
|
||||||
table = InterventionTable(
|
table = InterventionTable(
|
||||||
request=request,
|
request=request,
|
||||||
|
@ -37,6 +37,10 @@ Declare some basic colours
|
|||||||
color:var(--rlp-red);
|
color:var(--rlp-red);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rlp-r-inv{
|
||||||
|
color:var(--rlp-red);
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
|
@ -126,6 +126,16 @@ class BaseTable(tables.tables.Table):
|
|||||||
icon
|
icon
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def render_icn(self, tooltip: str = None, icn_class: str = None):
|
||||||
|
"""
|
||||||
|
Returns a rendered fontawesome icon
|
||||||
|
"""
|
||||||
|
return format_html(
|
||||||
|
"<em title='{}' class='{}'></em>",
|
||||||
|
tooltip,
|
||||||
|
icn_class,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChoicesColumnForm(BaseForm):
|
class ChoicesColumnForm(BaseForm):
|
||||||
select = forms.ChoiceField(
|
select = forms.ChoiceField(
|
||||||
|
Binary file not shown.
@ -3,13 +3,15 @@
|
|||||||
# This file is distributed under the same license as the PACKAGE package.
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
#: konova/forms.py:69 user/forms.py:38
|
#: intervention/filters.py:21 intervention/filters.py:27
|
||||||
|
#: intervention/filters.py:34 intervention/filters.py:35 konova/forms.py:69
|
||||||
|
#: user/forms.py:38
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-07-21 15:07+0200\n"
|
"POT-Creation-Date: 2021-07-22 09:31+0200\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -20,12 +22,12 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
#: compensation/tables.py:18 compensation/tables.py:71 intervention/forms.py:26
|
#: compensation/tables.py:18 compensation/tables.py:71 intervention/forms.py:26
|
||||||
#: intervention/tables.py:22
|
#: intervention/tables.py:23
|
||||||
msgid "Identifier"
|
msgid "Identifier"
|
||||||
msgstr "Kennung"
|
msgstr "Kennung"
|
||||||
|
|
||||||
#: compensation/tables.py:23 compensation/tables.py:76 intervention/forms.py:33
|
#: compensation/tables.py:23 compensation/tables.py:76 intervention/forms.py:33
|
||||||
#: intervention/tables.py:27
|
#: intervention/tables.py:28
|
||||||
msgid "Title"
|
msgid "Title"
|
||||||
msgstr "Titel"
|
msgstr "Titel"
|
||||||
|
|
||||||
@ -47,17 +49,17 @@ msgid "Compensation"
|
|||||||
msgstr "Kompensation"
|
msgstr "Kompensation"
|
||||||
|
|
||||||
#: compensation/tables.py:54 compensation/tables.py:107
|
#: compensation/tables.py:54 compensation/tables.py:107
|
||||||
#: intervention/tables.py:79 intervention/tables.py:139
|
#: intervention/tables.py:92 intervention/tables.py:179
|
||||||
msgid "Open {}"
|
msgid "Open {}"
|
||||||
msgstr "Öffne {}"
|
msgstr "Öffne {}"
|
||||||
|
|
||||||
#: compensation/tables.py:59 compensation/tables.py:112
|
#: compensation/tables.py:59 compensation/tables.py:112
|
||||||
#: intervention/tables.py:143
|
#: intervention/tables.py:183
|
||||||
msgid "Edit {}"
|
msgid "Edit {}"
|
||||||
msgstr "Bearbeite {}"
|
msgstr "Bearbeite {}"
|
||||||
|
|
||||||
#: compensation/tables.py:63 compensation/tables.py:116
|
#: compensation/tables.py:63 compensation/tables.py:116
|
||||||
#: intervention/tables.py:147
|
#: intervention/tables.py:187
|
||||||
msgid "Delete {}"
|
msgid "Delete {}"
|
||||||
msgstr "Lösche {}"
|
msgstr "Lösche {}"
|
||||||
|
|
||||||
@ -65,6 +67,22 @@ msgstr "Lösche {}"
|
|||||||
msgid "Eco Accounts"
|
msgid "Eco Accounts"
|
||||||
msgstr "Ökokonten"
|
msgstr "Ökokonten"
|
||||||
|
|
||||||
|
#: intervention/filters.py:20
|
||||||
|
msgid "Show all"
|
||||||
|
msgstr "Alle anzeigen"
|
||||||
|
|
||||||
|
#: intervention/filters.py:26
|
||||||
|
msgid "Show recorded"
|
||||||
|
msgstr "Verzeichnete anzeigen"
|
||||||
|
|
||||||
|
#: intervention/filters.py:38
|
||||||
|
msgid "District"
|
||||||
|
msgstr "Gemarkung"
|
||||||
|
|
||||||
|
#: intervention/filters.py:39
|
||||||
|
msgid "Search for district"
|
||||||
|
msgstr "Nach Gemarkung suchen"
|
||||||
|
|
||||||
#: intervention/forms.py:29
|
#: intervention/forms.py:29
|
||||||
msgid "Generated automatically if none was given"
|
msgid "Generated automatically if none was given"
|
||||||
msgstr "Wird automatisch erzeugt, falls nicht angegeben"
|
msgstr "Wird automatisch erzeugt, falls nicht angegeben"
|
||||||
@ -133,57 +151,69 @@ msgstr "Neuer Eingriff"
|
|||||||
msgid "Edit intervention"
|
msgid "Edit intervention"
|
||||||
msgstr "Eingriff bearbeiten"
|
msgstr "Eingriff bearbeiten"
|
||||||
|
|
||||||
#: intervention/tables.py:32
|
#: intervention/tables.py:33
|
||||||
msgid "Checked"
|
msgid "Checked"
|
||||||
msgstr "Geprüft"
|
msgstr "Geprüft"
|
||||||
|
|
||||||
#: intervention/tables.py:38
|
#: intervention/tables.py:39
|
||||||
msgid "Registered"
|
msgid "Registered"
|
||||||
msgstr "Verzeichnet"
|
msgstr "Verzeichnet"
|
||||||
|
|
||||||
#: intervention/tables.py:44
|
#: intervention/tables.py:45
|
||||||
|
msgid "Editable"
|
||||||
|
msgstr "Freigegeben"
|
||||||
|
|
||||||
|
#: intervention/tables.py:51
|
||||||
msgid "Last edit"
|
msgid "Last edit"
|
||||||
msgstr "Zuletzt bearbeitet"
|
msgstr "Zuletzt bearbeitet"
|
||||||
|
|
||||||
#: intervention/tables.py:64
|
#: intervention/tables.py:70
|
||||||
msgid "Interventions"
|
msgid "Interventions"
|
||||||
msgstr "Eingriffe"
|
msgstr "Eingriffe"
|
||||||
|
|
||||||
#: intervention/tables.py:79 intervention/tables.py:136
|
#: intervention/tables.py:92 intervention/tables.py:176
|
||||||
#: intervention/templates/intervention/open.html:8
|
#: intervention/templates/intervention/open.html:8
|
||||||
#: konova/templates/konova/home.html:11 templates/navbar.html:22
|
#: konova/templates/konova/home.html:11 templates/navbar.html:22
|
||||||
msgid "Intervention"
|
msgid "Intervention"
|
||||||
msgstr "Eingriff"
|
msgstr "Eingriff"
|
||||||
|
|
||||||
#: intervention/tables.py:98
|
#: intervention/tables.py:111
|
||||||
msgid "Not checked yet"
|
msgid "Not checked yet"
|
||||||
msgstr "Noch nicht geprüft"
|
msgstr "Noch nicht geprüft"
|
||||||
|
|
||||||
#: intervention/tables.py:102
|
#: intervention/tables.py:115
|
||||||
msgid "Checked on {} by {}"
|
msgid "Checked on {} by {}"
|
||||||
msgstr "Am {} von {} geprüft worden"
|
msgstr "Am {} von {} geprüft worden"
|
||||||
|
|
||||||
#: intervention/tables.py:121
|
#: intervention/tables.py:134
|
||||||
msgid "Not registered yet"
|
msgid "Not registered yet"
|
||||||
msgstr "Noch nicht verzeichnet"
|
msgstr "Noch nicht verzeichnet"
|
||||||
|
|
||||||
#: intervention/tables.py:125
|
#: intervention/tables.py:138
|
||||||
msgid "Registered on {} by {}"
|
msgid "Registered on {} by {}"
|
||||||
msgstr "Am {} von {} verzeichnet worden"
|
msgstr "Am {} von {} verzeichnet worden"
|
||||||
|
|
||||||
|
#: intervention/tables.py:167
|
||||||
|
msgid "Full access granted"
|
||||||
|
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
|
||||||
|
|
||||||
|
#: intervention/tables.py:167
|
||||||
|
msgid "Access not granted"
|
||||||
|
msgstr "Nicht freigegeben - Datensatz nur lesbar"
|
||||||
|
|
||||||
#: intervention/templates/intervention/open.html:12
|
#: intervention/templates/intervention/open.html:12
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Bearbeiten"
|
msgstr "Bearbeiten"
|
||||||
|
|
||||||
#: intervention/views.py:60
|
#: intervention/views.py:63
|
||||||
msgid "Intervention {} added"
|
msgid "Intervention {} added"
|
||||||
msgstr "Eingriff {} hinzugefügt"
|
msgstr "Eingriff {} hinzugefügt"
|
||||||
|
|
||||||
#: intervention/views.py:63 intervention/views.py:116
|
#: intervention/views.py:66 intervention/views.py:119
|
||||||
msgid "Invalid input"
|
msgid "Invalid input"
|
||||||
msgstr "Eingabe fehlerhaft"
|
msgstr "Eingabe fehlerhaft"
|
||||||
|
|
||||||
#: intervention/views.py:113
|
#: intervention/views.py:116
|
||||||
msgid "{} edited"
|
msgid "{} edited"
|
||||||
msgstr "{} bearbeitet"
|
msgstr "{} bearbeitet"
|
||||||
|
|
||||||
@ -371,10 +401,14 @@ msgstr "Starte Suche"
|
|||||||
msgid "Results per page"
|
msgid "Results per page"
|
||||||
msgstr "Treffer pro Seite"
|
msgstr "Treffer pro Seite"
|
||||||
|
|
||||||
#: templates/table.html:70
|
#: templates/table.html:70 templates/table.html:77
|
||||||
msgid "Filter"
|
msgid "Filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/table.html:79
|
||||||
|
msgid "Apply filter"
|
||||||
|
msgstr "Filter anwenden"
|
||||||
|
|
||||||
#: user/forms.py:23
|
#: user/forms.py:23
|
||||||
msgid "Notifications"
|
msgid "Notifications"
|
||||||
msgstr "Benachrichtigungen"
|
msgstr "Benachrichtigungen"
|
||||||
@ -1697,9 +1731,6 @@ msgstr ""
|
|||||||
#~ msgid "Process management"
|
#~ msgid "Process management"
|
||||||
#~ msgstr "Vorgangsverwaltung"
|
#~ msgstr "Vorgangsverwaltung"
|
||||||
|
|
||||||
#~ msgid "Show process"
|
|
||||||
#~ msgstr "Zeige Vorgänge"
|
|
||||||
|
|
||||||
#~ msgid "New process"
|
#~ msgid "New process"
|
||||||
#~ msgstr "Neuer Vorgang"
|
#~ msgstr "Neuer Vorgang"
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@
|
|||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
<div class="row my-1">
|
<div class="row my-1">
|
||||||
<div class="col-sm-12 col-md-8 col-lg-6">
|
<div class="col-sm-12 col-md-8 col-lg-6">
|
||||||
<form method="get" action="{{table.filter}}">
|
<form method="get">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control" aria-label="{% trans 'Search for keywords' %}" placeholder="{% trans 'Search' %}">
|
<input id="id_q" name="q" type="text" class="form-control" aria-label="{% trans 'Search for keywords' %}" placeholder="{% trans 'Search' %}" value="{{ request.GET.q }}">
|
||||||
<div class="input-group-append" title="{% trans 'Start search' %}">
|
<div class="input-group-append" title="{% trans 'Start search' %}">
|
||||||
<button type="submit" class="btn btn-default input-group-text">
|
<button type="submit" class="btn btn-default input-group-text">
|
||||||
<span class="">
|
<span class="">
|
||||||
@ -72,6 +72,10 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="get">
|
<form method="get">
|
||||||
{{ table.filter.form.as_p }}
|
{{ table.filter.form.as_p }}
|
||||||
|
<button class="btn btn-default" title="{% trans 'Filter' %}">
|
||||||
|
{% fa5_icon 'filter' %}
|
||||||
|
{% trans 'Apply filter' %}
|
||||||
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user