Enable HTMX boosting

This commit is contained in:
Jeremy Stretch 2024-02-01 19:58:59 -05:00
parent b3f25a400b
commit 6d06152573
9 changed files with 33 additions and 12 deletions

View File

@ -25,6 +25,7 @@ from netbox.views import generic
from netbox.views.generic.base import BaseObjectView from netbox.views.generic.base import BaseObjectView
from netbox.views.generic.mixins import TableMixin from netbox.views.generic.mixins import TableMixin
from utilities.forms import ConfirmationForm from utilities.forms import ConfirmationForm
from utilities.htmx import render_partial
from utilities.utils import count_related from utilities.utils import count_related
from utilities.views import ContentTypePermissionRequiredMixin, register_model_view from utilities.views import ContentTypePermissionRequiredMixin, register_model_view
from . import filtersets, forms, tables from . import filtersets, forms, tables
@ -320,7 +321,7 @@ class BackgroundTaskListView(TableMixin, BaseRQView):
table = self.get_table(data, request, False) table = self.get_table(data, request, False)
# If this is an HTMX request, return only the rendered table HTML # If this is an HTMX request, return only the rendered table HTML
if request.htmx: if render_partial(request):
return render(request, 'htmx/table.html', { return render(request, 'htmx/table.html', {
'table': table, 'table': table,
}) })
@ -489,8 +490,8 @@ class WorkerListView(TableMixin, BaseRQView):
table = self.get_table(data, request, False) table = self.get_table(data, request, False)
# If this is an HTMX request, return only the rendered table HTML # If this is an HTMX request, return only the rendered table HTML
if request.htmx: if render_partial(request):
if request.htmx.target != 'object_list': if not request.htmx.target:
table.embedded = True table.embedded = True
# Hide selection checkboxes # Hide selection checkboxes
if 'pk' in table.base_columns: if 'pk' in table.base_columns:

View File

@ -18,6 +18,7 @@ from extras.dashboard.utils import get_widget_class
from netbox.constants import DEFAULT_ACTION_PERMISSIONS from netbox.constants import DEFAULT_ACTION_PERMISSIONS
from netbox.views import generic from netbox.views import generic
from utilities.forms import ConfirmationForm, get_field_value from utilities.forms import ConfirmationForm, get_field_value
from utilities.htmx import render_partial
from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.paginator import EnhancedPaginator, get_paginate_count
from utilities.rqworker import get_workers_for_queue from utilities.rqworker import get_workers_for_queue
from utilities.templatetags.builtins.filters import render_markdown from utilities.templatetags.builtins.filters import render_markdown
@ -1168,7 +1169,7 @@ class ScriptResultView(ContentTypePermissionRequiredMixin, View):
} }
# If this is an HTMX request, return only the result HTML # If this is an HTMX request, return only the result HTML
if request.htmx: if render_partial(request):
response = render(request, 'extras/htmx/script_result.html', context) response = render(request, 'extras/htmx/script_result.html', context)
if job.completed or not job.started: if job.completed or not job.started:
response.status_code = 286 response.status_code = 286

View File

@ -22,6 +22,7 @@ from utilities.error_handlers import handle_protectederror
from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
from utilities.forms.bulk_import import BulkImportForm from utilities.forms.bulk_import import BulkImportForm
from utilities.htmx import render_partial
from utilities.permissions import get_permission_for_model from utilities.permissions import get_permission_for_model
from utilities.utils import get_viewname from utilities.utils import get_viewname
from utilities.views import GetReturnURLMixin from utilities.views import GetReturnURLMixin
@ -161,8 +162,8 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
table = self.get_table(self.queryset, request, has_bulk_actions) table = self.get_table(self.queryset, request, has_bulk_actions)
# If this is an HTMX request, return only the rendered table HTML # If this is an HTMX request, return only the rendered table HTML
if request.htmx: if render_partial(request):
if request.htmx.target != 'object_list': if not request.htmx.target:
table.embedded = True table.embedded = True
# Hide selection checkboxes # Hide selection checkboxes
if 'pk' in table.base_columns: if 'pk' in table.base_columns:

View File

@ -16,6 +16,7 @@ from extras.signals import clear_events
from utilities.error_handlers import handle_protectederror from utilities.error_handlers import handle_protectederror
from utilities.exceptions import AbortRequest, PermissionsViolation from utilities.exceptions import AbortRequest, PermissionsViolation
from utilities.forms import ConfirmationForm, restrict_form_fields from utilities.forms import ConfirmationForm, restrict_form_fields
from utilities.htmx import render_partial
from utilities.permissions import get_permission_for_model from utilities.permissions import get_permission_for_model
from utilities.utils import get_viewname, normalize_querydict, prepare_cloned_fields from utilities.utils import get_viewname, normalize_querydict, prepare_cloned_fields
from utilities.views import GetReturnURLMixin from utilities.views import GetReturnURLMixin
@ -135,7 +136,7 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
table = self.get_table(table_data, request, has_bulk_actions) table = self.get_table(table_data, request, has_bulk_actions)
# If this is an HTMX request, return only the rendered table HTML # If this is an HTMX request, return only the rendered table HTML
if request.htmx: if render_partial(request):
return render(request, 'htmx/table.html', { return render(request, 'htmx/table.html', {
'object': instance, 'object': instance,
'table': table, 'table': table,
@ -223,7 +224,7 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView):
restrict_form_fields(form, request.user) restrict_form_fields(form, request.user)
# If this is an HTMX request, return only the rendered form HTML # If this is an HTMX request, return only the rendered form HTML
if request.htmx: if render_partial(request):
return render(request, 'htmx/form.html', { return render(request, 'htmx/form.html', {
'form': form, 'form': form,
}) })
@ -479,7 +480,7 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
instance = self.alter_object(self.queryset.model(), request) instance = self.alter_object(self.queryset.model(), request)
# If this is an HTMX request, return only the rendered form HTML # If this is an HTMX request, return only the rendered form HTML
if request.htmx: if render_partial(request):
return render(request, 'htmx/form.html', { return render(request, 'htmx/form.html', {
'form': form, 'form': form,
}) })

View File

@ -17,6 +17,7 @@ from netbox.forms import SearchForm
from netbox.search import LookupTypes from netbox.search import LookupTypes
from netbox.search.backends import search_backend from netbox.search.backends import search_backend
from netbox.tables import SearchTable from netbox.tables import SearchTable
from utilities.htmx import render_partial
from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.paginator import EnhancedPaginator, get_paginate_count
__all__ = ( __all__ = (
@ -104,7 +105,7 @@ class SearchView(View):
}).configure(table) }).configure(table)
# If this is an HTMX request, return only the rendered table HTML # If this is an HTMX request, return only the rendered table HTML
if request.htmx: if render_partial(request):
return render(request, 'htmx/table.html', { return render(request, 'htmx/table.html', {
'table': table, 'table': table,
}) })

View File

@ -79,6 +79,7 @@ Blocks:
{# Page content #} {# Page content #}
<div class="page-wrapper"> <div class="page-wrapper">
<div id="page-content" hx-boost="true" hx-target="#page-content" hx-select="#page-content" hx-swap="outerHTML">
{# Page header #} {# Page header #}
{% block header %} {% block header %}
@ -122,6 +123,8 @@ Blocks:
{% endif %} {% endif %}
{# /Bottom banner #} {# /Bottom banner #}
</div>
{# Page footer #} {# Page footer #}
<footer class="footer footer-transparent d-print-none py-2"> <footer class="footer footer-transparent d-print-none py-2">
<div class="container-xl d-flex justify-content-between align-items-center"> <div class="container-xl d-flex justify-content-between align-items-center">

12
netbox/utilities/htmx.py Normal file
View File

@ -0,0 +1,12 @@
__all__ = (
'render_partial',
)
PAGE_CONTAINER_ID = 'page-content'
def render_partial(request):
"""
Determines whether to render a partial response.
"""
return request.htmx and request.htmx.target != PAGE_CONTAINER_ID

View File

@ -1,4 +1,5 @@
<div class="card-body htmx-container table-responsive p-0" <div class="card-body htmx-container table-responsive p-0"
hx-get="{% url viewname %}{% if url_params %}?{{ url_params.urlencode }}{% endif %}" hx-get="{% url viewname %}{% if url_params %}?{{ url_params.urlencode }}{% endif %}"
hx-trigger="load" hx-target="this"
hx-trigger="load" hx-select="table" hx-swap="innerHTML"
></div> ></div>

View File

@ -1,6 +1,6 @@
{% load helpers %} {% load helpers %}
<ul class="navbar-nav pt-lg-2"> <ul class="navbar-nav pt-lg-2" hx-boost="true" hx-target="#page-content" hx-select="#page-content" hx-swap="innerHTML">
{% for menu, groups in nav_items %} {% for menu, groups in nav_items %}
<li class="nav-item dropdown"> <li class="nav-item dropdown">