Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes: #9583 - Add column specific search field to tables #15073

Open
wants to merge 35 commits into
base: feature
Choose a base branch
from

Conversation

DanSheps
Copy link
Member

@DanSheps DanSheps commented Feb 7, 2024

Closes: #9583 - Add column specific search field to tables

The plan is to use the existing filterset to generate form fields on the table column headers to allow for inline-filtering using HTMX requests

Progress

  • Fields are generated for type fields HTMX requests are sent and account for both fields
  • Integrate with "quick search"
  • Works with custom fields
  • Allow dropdown to float outside of the parent div

Todo

  • Add input fields for "name" Not needed - Quick search is suitable for this
  • Fix filter float (Move before field name perhaps) Done
  • Add show/hide filter (Optional) Outside of scope

@DanSheps DanSheps changed the base branch from develop to feature February 7, 2024 19:41
Copy link
Member Author

@DanSheps DanSheps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is mostly there

netbox/netbox/views/generic/bulk_views.py Outdated Show resolved Hide resolved
@@ -5,7 +5,7 @@
<div class="col-auto d-print-none">
<div class="input-group input-group-flat me-2 quicksearch">
<input type="search" results="5" name="q" id="quicksearch" class="form-control px-2 py-1" placeholder="Quick search"
hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
hx-get="" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
Copy link
Member Author

@DanSheps DanSheps Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed full path, as this will allow taking into account filters on the form (to facilitate pushing of the filters from the column as well).

Should not impact functionality

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not impact functionality

Do we know this for sure? IIRC we specify the full path for a reason, I just can't recall why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my testing, I haven't found any issues with it.

netbox/utilities/templatetags/form_helpers.py Show resolved Hide resolved
@jeremystretch jeremystretch added this to the v4.0 milestone Feb 8, 2024
@DanSheps DanSheps marked this pull request as ready for review February 12, 2024 22:09
Copy link
Member

@jeremystretch jeremystretch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing a lot of errors when trying to load the filter fields.

screenshot

This is likely due to having multiple form fields with the same ID (one on the table and one on the "filters" tab).

netbox/utilities/templatetags/form_helpers.py Outdated Show resolved Hide resolved
netbox/utilities/templatetags/form_helpers.py Outdated Show resolved Hide resolved
netbox/utilities/templatetags/form_helpers.py Outdated Show resolved Hide resolved
netbox/templates/inc/table_htmx.html Outdated Show resolved Hide resolved
netbox/templates/inc/table_htmx.html Outdated Show resolved Hide resolved
netbox/templates/inc/table_header_filter_dropdown.html Outdated Show resolved Hide resolved
@@ -5,7 +5,7 @@
<div class="col-auto d-print-none">
<div class="input-group input-group-flat me-2 quicksearch">
<input type="search" results="5" name="q" id="quicksearch" class="form-control px-2 py-1" placeholder="Quick search"
hx-get="{{ request.full_path }}" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
hx-get="" hx-target="#object_list" hx-trigger="keyup changed delay:500ms, search" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not impact functionality

Do we know this for sure? IIRC we specify the full path for a reason, I just can't recall why.

netbox/templates/inc/table_header_filter_dropdown.html Outdated Show resolved Hide resolved
netbox/templates/inc/table_htmx.html Outdated Show resolved Hide resolved
netbox/utilities/templatetags/form_helpers.py Outdated Show resolved Hide resolved
Comment on lines 161 to 167
field.field.widget.attrs.update({
'id': f'table_filter_id_{field.name}',
'hx-get': url if url else '#',
'hx-push-url': "true",
'hx-target': '#object_list',
'hx-trigger': 'hidden.bs.dropdown from:closest .dropdown'
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this approach is tenable: We're using the same form field for both the column and the regular filter form (behind the second tab). Setting HTMX attributes on a non-HTMX form field should be avoided, and overriding its ID may cause problems. IMO we should try to identify a cleaner approach.

Copy link
Member Author

@DanSheps DanSheps Mar 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have went ahead and made a possible modification to this.

In bulk views, I initialize two copies of the form:

  1. A copy of the form for the filtering tab
  2. A copy of the form for the table column filtering

Since this render_table_filter_field tag is only used by the table coumn filtering logic, this shouldn't be a problem anymore.

Let me know if this approach is a more "safer" one while allowing for some code re-use. I can go a little deeper and perhaps modify all filtersets to add a "column filter" tuple to allow a more clean approach to limiting the columns as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT this should work fine, but do we need a full form instance for the columns? It might suffice to make a copy of the relevant fields from the filter form and attach them to their respective columns.

Though with either approach, I feel like we're missing a step. The current implementation depends on the column name and the field name matching (form_field=table.filterset_form|get_filter_field:column.name). This should work ~95% of the time but inevitably we're going to find exceptions. I'd like to see if we can devise a more robust approach, short of duplicating the field definitions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAICT this should work fine, but do we need a full form instance for the columns? It might suffice to make a copy of the relevant fields from the filter form and attach them to their respective columns.

Instead of initializing the form right away, we could copy the form definition and then remove fields that not present on the table before intitialization. This feels like excess code for very little gain however

Though with either approach, I feel like we're missing a step. The current implementation depends on the column name and the field name matching (form_field=table.filterset_form|get_filter_field:column.name). This should work ~95% of the time but inevitably we're going to find exceptions. I'd like to see if we can devise a more robust approach, short of duplicating the field definitions.

I think we should handle this on a case-by-case. The only other option would be looking at the table and building a completely new form class dynamically based on the table field types, however we then would likely lose all the custom filtering unless we tie it with the existing filter form somehow.

@jeremystretch
Copy link
Member

Another concern: There's no way to quickly discern when a column filter has been applied.

Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Jun 29, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Jul 2, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Jul 17, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Jul 22, 2024
Copy link
Contributor

github-actions bot commented Aug 7, 2024

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Aug 7, 2024
Copy link
Contributor

This PR has been automatically closed due to lack of activity.

@github-actions github-actions bot closed this Aug 23, 2024
@jeremystretch jeremystretch reopened this Aug 23, 2024
@jeremystretch jeremystretch removed the pending closure Requires immediate attention to avoid being closed for inactivity label Aug 23, 2024
Copy link
Contributor

github-actions bot commented Sep 8, 2024

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Sep 8, 2024
@DanSheps DanSheps added status: blocked Another issue or external requirement is preventing implementation and removed pending closure Requires immediate attention to avoid being closed for inactivity status: blocked Another issue or external requirement is preventing implementation labels Sep 12, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Oct 12, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Oct 15, 2024
Copy link
Contributor

This PR has been automatically marked as stale because it has not had recent activity. It will be closed automatically if no further action is taken.

@github-actions github-actions bot added the pending closure Requires immediate attention to avoid being closed for inactivity label Nov 16, 2024
@DanSheps DanSheps removed the pending closure Requires immediate attention to avoid being closed for inactivity label Nov 18, 2024
Copy link
Member

@jeremystretch jeremystretch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry it's taken so long to revisit this PR. We're working now on cleaning up the PR backlog.

Comment on lines +181 to +192
if self.filterset_form and table.filterset_form:
filterset_form = self.filterset_form(request.GET)
table.filterset_form = table.filterset_form(request.GET)
elif self.filterset_form and not table.filterset_form:
filterset_form = self.filterset_form(request.GET)
table.filterset_form = self.filterset_form(request.GET)
elif not self.filterset_form and table.filterset_form:
filterset_form = None
table.filterset_form = table.filterset_form(request.GET)
else:
filterset_form = None
table.filterset_form = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we ditch the association of a filterset form on the table directly, and just use the one associated with the view? That would make things a lot cleaner.

Comment on lines +39 to +41
# Check for a table form column map attribute and use that to map form fields if set
if hasattr(form, '_table_form_column_map') and form._table_form_column_map.get(fieldname):
return getfield(form, form._table_form_column_map.get(fieldname))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is _table_form_column_map getting set? If it's not yet needed, let's ditch it for now.

Comment on lines +201 to +204
filter_chits = render_to_string('inc/applied_filters_pane.html', {
'model': model,
'filter_form': filterset_form,
}, request)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO all rendering logic should go within the table itself, and should be consistent for both natural and HTMX requests.

Comment on lines +24 to +26
{% if table.filterset_form %}
{% include 'inc/table_header_filter_dropdown.html' with form_field=table.filterset_form|get_filter_field:column.name %}
{% endif %}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we associate filter field names directly with their corresponding table columns? That would simplify things a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add column-specific search fields to tables
3 participants