From 01cafafcdabf1a331c4780ecf034d841d0019659 Mon Sep 17 00:00:00 2001 From: Joseph Nuthalapati Date: Sun, 4 Jan 2026 20:21:13 +0530 Subject: [PATCH] ui: Use HTMX to eliminate full page reloads HTMX implementation is limited to HTML and JS files. No changes to Python files. Signed-off-by: Joseph Nuthalapati --- plinth/templates/base.html | 6 +++++- plinth/views.py | 16 ++++++---------- static/themes/default/js/main.js | 31 +++++++++++++------------------ 3 files changed, 24 insertions(+), 29 deletions(-) diff --git a/plinth/templates/base.html b/plinth/templates/base.html index 4ce902c2c..7e07b2a41 100644 --- a/plinth/templates/base.html +++ b/plinth/templates/base.html @@ -252,7 +252,11 @@ {% block container %} -
+
{% block content_row %} {% include 'messages.html' %} diff --git a/plinth/views.py b/plinth/views.py index c90e23429..ece40a2e7 100644 --- a/plinth/views.py +++ b/plinth/views.py @@ -497,9 +497,8 @@ class AppOperationsView(TemplateView): context['app_id'] = self.app.app_id context['app_info'] = self.app.info context['operations'] = operation.manager.filter(self.app.app_id) - context['refresh_page_sec'] = 0 - if context['operations']: - context['refresh_page_sec'] = 3 + # Refresh periodically while operations are running + context['refresh_page_sec'] = 3 if context['operations'] else 0 return context @@ -532,10 +531,10 @@ class SetupView(TemplateView): != app_module.App.SetupState.NEEDS_SETUP) context['refresh_page_sec'] = None - if context['setup_state'] == app_module.App.SetupState.UP_TO_DATE: - context['refresh_page_sec'] = 0 - elif context['operations']: + if context['operations']: context['refresh_page_sec'] = 3 + elif context['setup_state'] == app_module.App.SetupState.UP_TO_DATE: + context['refresh_page_sec'] = 0 return context @@ -550,10 +549,7 @@ class SetupView(TemplateView): # Give a moment for the setup process to start and show # meaningful status. time.sleep(1) - response = self.render_to_response(self.get_context_data()) - # Post/Response/Get pattern for reloads - response.status_code = 303 - return response + return redirect(request.path) return super().dispatch(request, *args, **kwargs) diff --git a/static/themes/default/js/main.js b/static/themes/default/js/main.js index d32108ca5..b0a8018eb 100644 --- a/static/themes/default/js/main.js +++ b/static/themes/default/js/main.js @@ -33,24 +33,6 @@ document.addEventListener('DOMContentLoaded', function (event) { html.classList.add('js'); }); -/* - * Refresh page if marked for refresh. - */ -document.addEventListener('DOMContentLoaded', function () { - const body = document.querySelector('body'); - if (body.hasAttribute('data-refresh-page-sec')) { - let seconds = body.getAttribute('data-refresh-page-sec'); - seconds = parseInt(seconds, 10); - if (isNaN(seconds)) - return; - - window.setTimeout(() => { - // Refresh the page without resubmitting the POST data. - window.location = window.location.href; - }, seconds * 1000); - } -}); - /* * Return all submit buttons on the page */ @@ -303,3 +285,16 @@ document.addEventListener('click', function (event) { bsCollapse.hide(); } }); + +/* + * Detect when hx-select element is not found in the response and reload the + * page. HTMX unfortunately does not seem to provide a JS event when hx-select + * element is not found in the response. However, in htmx:afterSwap event we can + * see that the target has no children and choose to refresh the whole page. + */ +document.addEventListener('htmx:afterSwap', function (event) { + const target = event.detail.target; + if (target && target.children.length === 0) { + window.location.reload(); + } +});