From b94764e178056a2118eff3f53f567207219e737d Mon Sep 17 00:00:00 2001
From: Hasan Ramezani <hasan.r67@gmail.com>
Date: Tue, 21 Jan 2020 15:14:11 +0100
Subject: [PATCH] Fixed #27888 -- Added link to clear all filters in the admin
 changelist view.

---
 .../contrib/admin/static/admin/css/changelists.css   |  6 ++++++
 .../contrib/admin/templates/admin/change_list.html   |  5 +++++
 docs/releases/3.1.txt                                |  3 +++
 tests/admin_changelist/tests.py                      | 12 ++++++++++++
 4 files changed, 26 insertions(+)

diff --git a/django/contrib/admin/static/admin/css/changelists.css b/django/contrib/admin/static/admin/css/changelists.css
index 30a6386a316..3eefd00fb14 100644
--- a/django/contrib/admin/static/admin/css/changelists.css
+++ b/django/contrib/admin/static/admin/css/changelists.css
@@ -187,6 +187,12 @@
     color: #036;
 }
 
+#changelist-filter #changelist-filter-clear a {
+    font-size: 13px;
+    padding-bottom: 10px;
+    border-bottom: 1px solid #eaeaea;
+}
+
 /* DATE DRILLDOWN */
 
 .change-list ul.toplinks {
diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html
index 8b275362af9..4dc9ed52d7a 100644
--- a/django/contrib/admin/templates/admin/change_list.html
+++ b/django/contrib/admin/templates/admin/change_list.html
@@ -60,6 +60,11 @@
         {% if cl.has_filters %}
           <div id="changelist-filter">
             <h2>{% translate 'Filter' %}</h2>
+            {% if cl.has_filters or cl.search_fields %}
+              {% if cl.preserved_filters %}<h3 id="changelist-filter-clear">
+                <a href="?{% if cl.is_popup %}_popup=1{% endif %}">&#10006; {% translate "Clear all filters" %}</a>
+              </h3>{% endif %}
+            {% endif %}
             {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
           </div>
         {% endif %}
diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt
index ced98c2e470..709c3917bc5 100644
--- a/docs/releases/3.1.txt
+++ b/docs/releases/3.1.txt
@@ -37,6 +37,9 @@ Minor features
   :attr:`.ModelAdmin.list_filter` allows filtering on empty values (empty
   strings and nulls) in the admin changelist view.
 
+* Filters in the right sidebar of the admin changelist view now contains a link
+  to clear all filters.
+
 :mod:`django.contrib.admindocs`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py
index 8cb6f7eff9c..933d2ac1d29 100644
--- a/tests/admin_changelist/tests.py
+++ b/tests/admin_changelist/tests.py
@@ -707,6 +707,18 @@ class ChangeListTests(TestCase):
         link = reverse('admin:admin_changelist_parent_change', args=(p.pk,))
         self.assertNotContains(response, '<a href="%s">' % link)
 
+    def test_clear_all_filters_link(self):
+        self.client.force_login(self.superuser)
+        link = '<a href="?">&#10006; Clear all filters</a>'
+        response = self.client.get(reverse('admin:auth_user_changelist'))
+        self.assertNotContains(response, link)
+        for data in (
+            {SEARCH_VAR: 'test'},
+            {'is_staff__exact': '0'},
+        ):
+            response = self.client.get(reverse('admin:auth_user_changelist'), data=data)
+            self.assertContains(response, link)
+
     def test_tuple_list_display(self):
         swallow = Swallow.objects.create(origin='Africa', load='12.34', speed='22.2')
         swallow2 = Swallow.objects.create(origin='Africa', load='12.34', speed='22.2')