diff --git a/admin_interface/admin.py b/admin_interface/admin.py
index f39c3bc..313b064 100644
--- a/admin_interface/admin.py
+++ b/admin_interface/admin.py
@@ -163,8 +163,10 @@ class ThemeAdmin(admin.ModelAdmin):
{
"classes": ("wide",),
"fields": (
+ "list_filter_highlight",
"list_filter_dropdown",
"list_filter_sticky",
+ "list_filter_removal_links",
),
},
),
diff --git a/admin_interface/migrations/0027_theme_list_filter_removal_links.py b/admin_interface/migrations/0027_theme_list_filter_removal_links.py
new file mode 100644
index 0000000..f9a2a9a
--- /dev/null
+++ b/admin_interface/migrations/0027_theme_list_filter_removal_links.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.7 on 2022-10-10 21:46
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('admin_interface', '0026_theme_list_filter_highlight'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='theme',
+ name='list_filter_removal_links',
+ field=models.BooleanField(default=False, verbose_name='quick remove links for active filters at top of sidebar'),
+ ),
+ ]
diff --git a/admin_interface/models.py b/admin_interface/models.py
index 8bda743..34a7e47 100644
--- a/admin_interface/models.py
+++ b/admin_interface/models.py
@@ -340,6 +340,10 @@ class Theme(models.Model):
list_filter_sticky = models.BooleanField(
default=True, verbose_name=_("sticky position")
)
+ list_filter_removal_links = models.BooleanField(
+ default=False, verbose_name=_(
+ "quick remove links for active filters at top of sidebar")
+ )
foldable_apps = models.BooleanField(default=True, verbose_name=_("foldable apps"))
diff --git a/admin_interface/static/admin_interface/css/admin-interface.css b/admin_interface/static/admin_interface/css/admin-interface.css
index 1de719d..febb965 100644
--- a/admin_interface/static/admin_interface/css/admin-interface.css
+++ b/admin_interface/static/admin_interface/css/admin-interface.css
@@ -376,12 +376,24 @@
border-radius: var(--admin-interface-module-border-radius);
}
+.admin-interface .module.filtered #changelist-filter .changelist-filter-clear a {
+ font-size: 13px;
+ margin: .3em 0;
+ padding: 0 15px;
+}
+
+.admin-interface .module.filtered #changelist-filter .changelist-filter-clear a:focus,
+.admin-interface .module.filtered #changelist-filter .changelist-filter-clear a:hover,
.admin-interface .module.filtered #changelist-filter #changelist-filter-clear a:focus,
.admin-interface .module.filtered #changelist-filter #changelist-filter-clear a:hover {
color: #666;
text-decoration: none;
}
+.admin-interface .module.filtered #changelist-filter .changelist-filter-clear a span {
+ font-weight: bold;
+}
+
.admin-interface .module.filtered #changelist-filter li a:focus,
.admin-interface .module.filtered #changelist-filter li a:hover {
color: #666;
diff --git a/admin_interface/templates/admin/change_list.html b/admin_interface/templates/admin/change_list.html
new file mode 100644
index 0000000..7c184e6
--- /dev/null
+++ b/admin_interface/templates/admin/change_list.html
@@ -0,0 +1,25 @@
+{% extends "admin/change_list.html" %}
+{% load i18n admin_list admin_interface_tags %}
+{# copied from django 4.0.7 #}
+
+ {% block filters %}
+ {% if cl.has_filters %}
+
+
{% translate 'Filter' %}
+ {% if cl.has_active_filters %}
+ {% get_admin_interface_setting "list_filter_removal_links" as list_filter_removal_links %}
+ {% if list_filter_removal_links %}
+ {% for spec in cl.filter_specs %}{% admin_interface_filter_removal_link cl spec %}{% endfor %}
+
+ {% else %}
+
+ {% endif %}
+ {% endif %}
+ {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
+
+ {% endif %}
+ {% endblock %}
diff --git a/admin_interface/templates/admin_interface/list_filter_removal_link.html b/admin_interface/templates/admin_interface/list_filter_removal_link.html
new file mode 100644
index 0000000..f86e4a4
--- /dev/null
+++ b/admin_interface/templates/admin_interface/list_filter_removal_link.html
@@ -0,0 +1,6 @@
+{% load admin_interface_tags %}
+{% if spec.lookup_val or spec.value %}
+
+{% endif %}
diff --git a/admin_interface/templatetags/admin_interface_tags.py b/admin_interface/templatetags/admin_interface_tags.py
index 525a288..03c9a9b 100644
--- a/admin_interface/templatetags/admin_interface_tags.py
+++ b/admin_interface/templatetags/admin_interface_tags.py
@@ -6,6 +6,7 @@ import re
from django import template
from django.conf import settings
+from django.template.loader import get_template
from django.utils import translation
from admin_interface.cache import get_cached_active_theme, set_cached_active_theme
@@ -65,8 +66,8 @@ def get_admin_interface_languages(context):
return langs_data
-@simple_tag(takes_context=True)
-def get_admin_interface_theme(context):
+@simple_tag()
+def get_admin_interface_theme():
theme = get_cached_active_theme()
if not theme:
theme = Theme.get_active_theme()
@@ -74,6 +75,12 @@ def get_admin_interface_theme(context):
return theme
+@simple_tag()
+def get_admin_interface_setting(setting):
+ theme = get_admin_interface_theme()
+ return getattr(theme, setting)
+
+
@simple_tag(takes_context=False)
def get_admin_interface_version():
return __version__
@@ -88,3 +95,27 @@ def hash_string(text):
@simple_tag(takes_context=False)
def get_admin_interface_nocache():
return hash_string(__version__)
+
+
+@simple_tag()
+def admin_interface_clear_filter_qs(changelist, list_filter):
+ return changelist.get_query_string(remove=list_filter.expected_parameters())
+
+
+@simple_tag()
+def admin_interface_filter_removal_link(changelist, list_filter):
+ tpl = get_template('admin_interface/list_filter_removal_link.html')
+ title = list_filter.title
+
+ choices = [c for c in list_filter.choices(changelist) if c['selected']]
+ try:
+ value = choices[0]['display']
+ except (IndexError, KeyError):
+ value = '...'
+
+ return tpl.render({
+ 'cl': changelist,
+ 'spec': list_filter,
+ 'selected_value': value,
+ 'title': title,
+ })
diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py
index 71165fa..e05ece7 100644
--- a/tests/test_templatetags.py
+++ b/tests/test_templatetags.py
@@ -102,20 +102,7 @@ class AdminInterfaceTemplateTagsTestCase(TestCase):
def test_get_theme(self):
Theme.objects.all().delete()
context = Context({})
- theme = templatetags.get_admin_interface_theme(context)
- self.assertEqual(theme.name, "Django")
- rendered = self.__render_template(
- "{% load admin_interface_tags %}"
- "{% get_admin_interface_theme as theme %}"
- "{{ theme.name }}",
- context,
- )
- self.assertEqual(rendered, "Django")
-
- def test_get_theme_with_request(self):
- Theme.objects.all().delete()
- context = Context({"request": self.request_factory.get("/")})
- theme = templatetags.get_admin_interface_theme(context)
+ theme = templatetags.get_admin_interface_theme()
self.assertEqual(theme.name, "Django")
rendered = self.__render_template(
"{% load admin_interface_tags %}"