mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Closes #6931: Include applied filters on object list view
This commit is contained in:
parent
6845fb0f00
commit
c7ebad0fbb
@ -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
|
||||
|
||||
|
@ -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">
|
||||
|
@ -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 %}
|
@ -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.
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user