From 91f33d328936f85569e796ca0a1ba95f51ffe355 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 13 Dec 2021 16:51:59 -0500 Subject: [PATCH] #8057: Enable dynamic tables for object list views --- netbox/netbox/views/generic.py | 7 ++++ netbox/templates/base/base.html | 3 ++ netbox/templates/generic/object_list.html | 7 ++-- netbox/templates/htmx/table.html | 5 +++ netbox/templates/inc/paginator_htmx.html | 43 +++++++++++++++++++++++ netbox/templates/inc/table_htmx.html | 41 +++++++++++++++++++++ netbox/utilities/htmx.py | 5 +++ 7 files changed, 107 insertions(+), 4 deletions(-) create mode 100644 netbox/templates/htmx/table.html create mode 100644 netbox/templates/inc/paginator_htmx.html create mode 100644 netbox/templates/inc/table_htmx.html create mode 100644 netbox/utilities/htmx.py diff --git a/netbox/netbox/views/generic.py b/netbox/netbox/views/generic.py index 1c2ff9917..9b6ae691b 100644 --- a/netbox/netbox/views/generic.py +++ b/netbox/netbox/views/generic.py @@ -23,6 +23,7 @@ from utilities.exceptions import AbortTransaction, PermissionsViolation from utilities.forms import ( BootstrapMixin, BulkRenameForm, ConfirmationForm, CSVDataField, CSVFileField, ImportForm, restrict_form_fields, ) +from utilities.htmx import is_htmx from utilities.permissions import get_permission_for_model from utilities.tables import paginate_table from utilities.utils import normalize_querydict, prepare_cloned_fields @@ -185,6 +186,12 @@ class ObjectListView(ObjectPermissionRequiredMixin, View): table = self.get_table(request, permissions) paginate_table(table, request) + # If this is an HTMX request, return only the rendered table HTML + if is_htmx(request): + return render(request, 'htmx/table.html', { + 'table': table, + }) + context = { 'content_type': content_type, 'table': table, diff --git a/netbox/templates/base/base.html b/netbox/templates/base/base.html index 43e5c2dfb..52d9c6603 100644 --- a/netbox/templates/base/base.html +++ b/netbox/templates/base/base.html @@ -160,6 +160,9 @@ })(); + {# TODO: Package HTMX JS locally #} + + {# Page layout #} {% block layout %}{% endblock %} diff --git a/netbox/templates/generic/object_list.html b/netbox/templates/generic/object_list.html index 61e799eee..1436958d7 100644 --- a/netbox/templates/generic/object_list.html +++ b/netbox/templates/generic/object_list.html @@ -95,10 +95,11 @@ {# Object table #}
-
+
- {% render_table table 'inc/table.html' %} + {% render_table table 'inc/table_htmx.html' %}
+ {% include 'inc/paginator_htmx.html' with paginator=table.paginator page=table.page %}
@@ -125,8 +126,6 @@ - {# Paginator #} - {% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
{# Filter form #} diff --git a/netbox/templates/htmx/table.html b/netbox/templates/htmx/table.html new file mode 100644 index 000000000..711708e32 --- /dev/null +++ b/netbox/templates/htmx/table.html @@ -0,0 +1,5 @@ +{# Render an HTML table element #} +{% load render_table from django_tables2 %} + +{% render_table table 'inc/table_htmx.html' %} +{% include 'inc/paginator_htmx.html' with paginator=table.paginator page=table.page %} diff --git a/netbox/templates/inc/paginator_htmx.html b/netbox/templates/inc/paginator_htmx.html new file mode 100644 index 000000000..c3b50cbd4 --- /dev/null +++ b/netbox/templates/inc/paginator_htmx.html @@ -0,0 +1,43 @@ +{% load helpers %} + +
+
+ {% if paginator.num_pages > 1 %} +
+ {% if page.has_previous %} + + + + {% endif %} + {% for p in page.smart_pages %} + {% if p %} + + {{ p }} + + {% else %} + + {% endif %} + {% endfor %} + {% if page.has_next %} + + + + {% endif %} +
+ {% endif %} +
+
+ +
+
diff --git a/netbox/templates/inc/table_htmx.html b/netbox/templates/inc/table_htmx.html new file mode 100644 index 000000000..58b5e7294 --- /dev/null +++ b/netbox/templates/inc/table_htmx.html @@ -0,0 +1,41 @@ +{% load django_tables2 %} + + + {% if table.show_header %} + + + {% for column in table.columns %} + {% if column.orderable %} + {{ column.header }} + {% else %} + {{ column.header }} + {% endif %} + {% endfor %} + + + {% endif %} + + {% for row in table.page.object_list|default:table.rows %} + + {% for column, cell in row.items %} + {{ cell }} + {% endfor %} + + {% empty %} + {% if table.empty_text %} + + — {{ table.empty_text }} — + + {% endif %} + {% endfor %} + + {% if table.has_footer %} + + + {% for column in table.columns %} + {{ column.footer }} + {% endfor %} + + + {% endif %} + diff --git a/netbox/utilities/htmx.py b/netbox/utilities/htmx.py new file mode 100644 index 000000000..8fc568e2b --- /dev/null +++ b/netbox/utilities/htmx.py @@ -0,0 +1,5 @@ +def is_htmx(request): + """ + Returns True if the request was made by HTMX; False otherwise. + """ + return 'Hx-Request' in request.headers