From f8ace75f369ae1f7fb4c5e7efc01573776ddef91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric?= Date: Tue, 11 Oct 2022 12:15:21 -0400 Subject: [PATCH] Add option for list filter quick remove. #183 * add option for list filter quick remove * move transform from css to python * make template tag more resilient for unusual filters * fix tests * rename field, move rendering to template, change style * fix tests --- admin_interface/admin.py | 2 ++ .../0027_theme_list_filter_removal_links.py | 18 ++++++++++ admin_interface/models.py | 4 +++ .../admin_interface/css/admin-interface.css | 12 +++++++ .../templates/admin/change_list.html | 25 +++++++++++++ .../list_filter_removal_link.html | 6 ++++ .../templatetags/admin_interface_tags.py | 35 +++++++++++++++++-- tests/test_templatetags.py | 15 +------- 8 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 admin_interface/migrations/0027_theme_list_filter_removal_links.py create mode 100644 admin_interface/templates/admin/change_list.html create mode 100644 admin_interface/templates/admin_interface/list_filter_removal_link.html 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 %} +

+ {% translate "Clear all filters" %} ✖ +

+ {% else %} +

+ ✖ {% translate "Clear all filters" %} +

+ {% 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 %} +
+ {{ title|capfirst }}: {{ selected_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 %}"