Closes #6931: Include applied filters on object list view

This commit is contained in:
jeremystretch 2021-08-10 13:04:50 -04:00
parent 6845fb0f00
commit c7ebad0fbb
5 changed files with 73 additions and 3 deletions

View File

@ -5,6 +5,7 @@
### Enhancements
* [#6829](https://github.com/netbox-community/netbox/issues/6829) - Extend GraphQL API to support reverse generic relationships
* [#6931](https://github.com/netbox-community/netbox/issues/6931) - Include applied filters on object list view
### Bug Fixes

View File

@ -47,9 +47,14 @@
{# Object list #}
<div class="tab-pane show active" id="object-list" role="tabpanel" aria-labelledby="object-list-tab">
{% if table.paginator.num_pages > 1 %}
{# "Select all" form #}
{# Applied filters #}
{% if filter_form %}
{% applied_filters filter_form request.GET %}
{% endif %}
{# "Select all" form #}
{% if table.paginator.num_pages > 1 %}
{% with bulk_edit_url=content_type.model_class|validated_viewname:"bulk_edit" bulk_delete_url=content_type.model_class|validated_viewname:"bulk_delete" %}
<div id="select-all-box" class="d-none card noprint">
<form method="post" class="form col-md-12">

View File

@ -0,0 +1,9 @@
{% if applied_filters %}
<div class="mb-3">
{% for filter in applied_filters %}
<a href="{{ filter.link_url }}" class="badge rounded-pill bg-primary text-decoration-none me-1">
<i class="mdi mdi-close"></i> {{ filter.link_text }}
</a>
{% endfor %}
</div>
{% endif %}

View File

@ -3,6 +3,7 @@ import re
from django import forms
from django.forms.models import fields_for_model
from utilities.choices import unpack_grouped_choices
from utilities.querysets import RestrictedQuerySet
from .constants import *
@ -11,6 +12,7 @@ __all__ = (
'expand_alphanumeric_pattern',
'expand_ipaddress_pattern',
'form_from_model',
'get_selected_values',
'parse_alphanumeric_range',
'parse_numeric_range',
'restrict_form_fields',
@ -111,6 +113,30 @@ def expand_ipaddress_pattern(string, family):
yield ''.join([lead, format(i, 'x' if family == 6 else 'd'), remnant])
def get_selected_values(form, field_name):
"""
Return the list of selected human-friendly values for a form field
"""
if not hasattr(form, 'cleaned_data'):
form.is_valid()
# Selection field
if hasattr(form.fields[field_name], 'choices'):
try:
choices = dict(unpack_grouped_choices(form.fields[field_name].choices))
return [
label for value, label in choices.items() if value in form.cleaned_data[field_name]
]
except TypeError:
# Field uses dynamic choices. Show all that have been populated.
return [
subwidget.choice_label for subwidget in form[field_name].subwidgets
]
# Non-selection field
return [str(form.cleaned_data[field_name])]
def add_blank_choice(choices):
"""
Add a blank choice to the beginning of a choices list.

View File

@ -13,7 +13,7 @@ from django.utils.html import strip_tags
from django.utils.safestring import mark_safe
from markdown import markdown
from utilities.forms import TableConfigForm
from utilities.forms import get_selected_values, TableConfigForm
from utilities.utils import foreground_color
register = template.Library()
@ -403,3 +403,32 @@ def table_config_form(table, table_name=None):
'table_name': table_name or table.__class__.__name__,
'table_config_form': TableConfigForm(table=table),
}
@register.inclusion_tag('utilities/templatetags/applied_filters.html')
def applied_filters(form, query_params):
"""
Display the active filters for a given filter form.
"""
form.is_valid()
applied_filters = []
for filter_name in form.changed_data:
if filter_name not in query_params:
continue
bound_field = form.fields[filter_name].get_bound_field(form, filter_name)
querydict = query_params.copy()
querydict.pop(filter_name)
display_value = ', '.join(get_selected_values(form, filter_name))
applied_filters.append({
'name': filter_name,
'value': form.cleaned_data[filter_name],
'link_url': f'?{querydict.urlencode()}',
'link_text': f'{bound_field.label}: {display_value}',
})
return {
'applied_filters': applied_filters,
}