Feature 15348 - Quick Access Saved Filters (#15862)

* Added dropdown for Saved Filters.

* Added dropdown for Saved Filters.

* Added dropdown for Saved Filters.

* Fixed linter issues in savedFiltersSelect.ts

* Fixed linter issues in netbox.ts

* Fixed linter issues in netbox.ts

* Removed the blue tag with the filters when saved filters is selected.

* Adjusts in table_controls_htmx.html to vertical height of the Quick Search match to the dropdown.

* Adjusts in table_controls_htmx.html to vertical height of the Quick Search match to the dropdown.

* Adjusts in table_controls_htmx.html to vertical height of the Quick Search match to the dropdown.

* Minor adjusts in savedFiltersSelect.ts

* Addressed PR comment.

* Addressed PR comment.

* Addressed PR comment.

* Omit saved filters from 'applied filters'; clean up form widget

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
Julio Oliveira at Encora 2024-06-18 12:58:54 -03:00 committed by GitHub
parent 207c91ef6b
commit 81292df048
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 63 additions and 6 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,30 @@
import { isTruthy } from '../util';
/**
* Handle saved filter change event.
*
* @param event "change" event for the saved filter select
*/
function handleSavedFilterChange(event: Event): void {
const savedFilter = event.currentTarget as HTMLSelectElement;
let baseUrl = savedFilter.baseURI.split('?')[0];
const preFilter = '?';
const selectedOptions = Array.from(savedFilter.options)
.filter(option => option.selected)
.map(option => `filter_id=${option.value}`)
.join('&');
baseUrl += `${preFilter}${selectedOptions}`;
document.location.href = baseUrl;
}
export function initSavedFilterSelect(): void {
const divResults = document.getElementById('results');
if (isTruthy(divResults)) {
const savedFilterSelect = document.getElementById('id_filter_id');
if (isTruthy(savedFilterSelect)) {
savedFilterSelect.addEventListener('change', handleSavedFilterChange);
}
}
}

View File

@ -13,6 +13,7 @@ import { initSideNav } from './sidenav';
import { initDashboard } from './dashboard'; import { initDashboard } from './dashboard';
import { initRackElevation } from './racks'; import { initRackElevation } from './racks';
import { initHtmx } from './htmx'; import { initHtmx } from './htmx';
import { initSavedFilterSelect } from './forms/savedFiltersSelect';
function initDocument(): void { function initDocument(): void {
for (const init of [ for (const init of [
@ -31,6 +32,7 @@ function initDocument(): void {
initDashboard, initDashboard,
initRackElevation, initRackElevation,
initHtmx, initHtmx,
initSavedFilterSelect,
]) { ]) {
init(); init();
} }

View File

@ -7,6 +7,7 @@
// Overrides of external libraries // Overrides of external libraries
@import 'overrides/bootstrap'; @import 'overrides/bootstrap';
@import 'overrides/tabler'; @import 'overrides/tabler';
@import 'overrides/tomselect';
// Transitional styling to ease migration of templates from NetBox v3.x // Transitional styling to ease migration of templates from NetBox v3.x
@import 'transitional/badges'; @import 'transitional/badges';

View File

@ -0,0 +1,8 @@
.ts-wrapper.multi {
.ts-control {
padding: 7px 7px 3px 7px;
div {
margin: 0 4px 4px 0;
}
}
}

View File

@ -1,25 +1,37 @@
{% load helpers %} {% load helpers %}
{% load i18n %} {% load i18n %}
<div class="row mb-3"> <div class="row mb-3" id="results">
<div class="col-auto d-print-none"> <div class="col-auto d-print-none">
<div class="input-group input-group-flat me-2 quicksearch" hx-disinherit="hx-select hx-swap"> <div class="input-group input-group-flat me-2 quicksearch" hx-disinherit="hx-select hx-swap">
<input type="search" results="5" name="q" id="quicksearch" class="form-control px-2 py-1" placeholder="Quick search" <input type="search" results="5" name="q" id="quicksearch" class="form-control" placeholder="{% trans "Quick search" %}"
hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" /> hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search"/>
<span class="input-group-text py-1"> <span class="input-group-text py-1">
<a href="#" id="quicksearch_clear" class="invisible text-secondary"><i class="mdi mdi-close-circle"></i></a> <a href="#" id="quicksearch_clear" class="invisible text-secondary"><i class="mdi mdi-close-circle"></i></a>
</span> </span>
{% block extra_table_controls %}{% endblock %} {% block extra_table_controls %}{% endblock %}
</div> </div>
</div> </div>
<div class="col-auto d-print-none">
<div class="input-group">
<div class="input-group-text">
<i class="mdi mdi-filter" title="{% trans "Saved filter" %}"></i>
</div>
{{ filter_form.filter_id }}
</div>
</div>
<div class="col-auto ms-auto d-print-none"> <div class="col-auto ms-auto d-print-none">
{% if request.user.is_authenticated and table_modal %} {% if request.user.is_authenticated and table_modal %}
<div class="table-configure input-group"> <div class="table-configure input-group">
<button type="button" data-bs-toggle="modal" title="{% trans "Configure Table" %}" data-bs-target="#{{ table_modal }}" <button type="button" data-bs-toggle="modal" title="{% trans "Configure Table" %}"
class="btn"> data-bs-target="#{{ table_modal }}"
class="btn">
<i class="mdi mdi-cog"></i> {% trans "Configure Table" %} <i class="mdi mdi-cog"></i> {% trans "Configure Table" %}
</button> </button>
</div> </div>
{% endif %} {% endif %}
</div> </div>
</div> </div>

View File

@ -281,6 +281,10 @@ def applied_filters(context, model, form, query_params):
if filter_name not in querydict: if filter_name not in querydict:
continue continue
# Skip saved filters, as they're displayed alongside the quick search widget
if filter_name == 'filter_id':
continue
bound_field = form.fields[filter_name].get_bound_field(form, filter_name) bound_field = form.fields[filter_name].get_bound_field(form, filter_name)
querydict.pop(filter_name) querydict.pop(filter_name)
display_value = ', '.join([str(v) for v in get_selected_values(form, filter_name)]) display_value = ', '.join([str(v) for v in get_selected_values(form, filter_name)])