[ADD] User setting to keep the sidebar menu minimized

This commit is contained in:
Peter Pfeufer 2025-10-15 01:13:42 +02:00
parent 92a1bd40a3
commit 295361a541
No known key found for this signature in database
9 changed files with 122 additions and 3 deletions

View File

@ -52,4 +52,10 @@ class UserSettingsMiddleware(MiddlewareMixin):
except Exception as e: except Exception as e:
logger.exception(e) logger.exception(e)
# Minimize Menu
try:
request.session["MINIMIZE_SIDEBAR"] = request.user.profile.minimize_sidebar
except Exception as e:
pass # We don't care that an anonymous user has no profile (not logged in)
return response return response

View File

@ -0,0 +1,22 @@
# Generated by Django 4.2.25 on 2025-10-14 22:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentication", "0024_alter_userprofile_language"),
]
operations = [
migrations.AddField(
model_name="userprofile",
name="minimize_sidebar",
field=models.BooleanField(
default=False,
help_text="Keep the sidebar menu minimized",
verbose_name="Minimize Sidebar Menu",
),
),
]

View File

@ -97,7 +97,8 @@ class UserProfile(models.Model):
on_delete=models.SET_DEFAULT, on_delete=models.SET_DEFAULT,
default=get_guest_state_pk) default=get_guest_state_pk)
language = models.CharField( language = models.CharField(
_("Language"), max_length=10, _("Language"),
max_length=10,
choices=Language.choices, choices=Language.choices,
blank=True, blank=True,
default='') default='')
@ -112,6 +113,12 @@ class UserProfile(models.Model):
null=True, null=True,
help_text="Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps" help_text="Bootstrap 5 Themes from https://bootswatch.com/ or Community Apps"
) )
minimize_sidebar = models.BooleanField(
_("Minimize Sidebar Menu"),
default=False,
help_text=_("Keep the sidebar menu minimized")
)
def assign_state(self, state=None, commit=True): def assign_state(self, state=None, commit=True):
if not state: if not state:

View File

@ -88,6 +88,7 @@ class TestUserSettingsMiddlewareLoginFlow(TestCase):
self.request.LANGUAGE_CODE = 'en' self.request.LANGUAGE_CODE = 'en'
self.request.user.profile.language = 'de' self.request.user.profile.language = 'de'
self.request.user.profile.night_mode = True self.request.user.profile.night_mode = True
self.request.user.profile.minimize_sidebar = False
self.request.user.is_anonymous = False self.request.user.is_anonymous = False
self.response = Mock() self.response = Mock()
self.response.content = 'hello world' self.response.content = 'hello world'
@ -173,3 +174,26 @@ class TestUserSettingsMiddlewareLoginFlow(TestCase):
self.response self.response
) )
self.assertEqual(self.request.session["NIGHT_MODE"], True) self.assertEqual(self.request.session["NIGHT_MODE"], True)
def test_middleware_set_mimimize_sidebar(self):
"""
tests the middleware will always set minimize_sidebar to False (default)
"""
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.session["MINIMIZE_SIDEBAR"], False)
def test_middleware_minimize_sidebar_when_set(self):
"""
tests the middleware will set mimimize_sidebar to True from DB
"""
self.request.user.profile.minimize_sidebar = True
response = self.middleware.process_response(
self.request,
self.response
)
self.assertEqual(self.request.session["MINIMIZE_SIDEBAR"], True)

View File

@ -72,6 +72,31 @@
{% theme_select %} {% theme_select %}
{% if user.is_authenticated %}
<li><hr class="dropdown-divider"></li>
<li><h6 class="dropdown-header">{% translate "Sidebar" %}</h6></li>
<li>
<form class="dropdown-item" action="{% url 'minimize_sidebar' %}?next={{ request.path|urlencode }}" method="post">
{% csrf_token %}
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="toggle-sidebar"
onchange="this.form.submit()"
{% if request.session.MINIMIZE_SIDEBAR %}checked{% endif %}
>
<label class="form-check-label" for="toggle-sidebar">
{% translate "Minimize Sidebar" %}
</label>
</div>
</form>
</li>
{% endif %}
{% if user.is_superuser %} {% if user.is_superuser %}
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li><h6 class="dropdown-header">{% translate "Super User" %}</h6></li> <li><h6 class="dropdown-header">{% translate "Super User" %}</h6></li>

View File

@ -1,3 +1,5 @@
/* global sidebarSettings */
$(document).ready(() => { $(document).ready(() => {
'use strict'; 'use strict';
@ -16,7 +18,9 @@ $(document).ready(() => {
} }
}); });
if (!sidebarSettings.minimizeSidebar) {
sidebar.classList.toggle('show', localStorage.getItem(sidebarKey) !== 'closed'); sidebar.classList.toggle('show', localStorage.getItem(sidebarKey) !== 'closed');
}
const activeChildMenuItem = document.querySelector('ul#sidebar-menu ul.collapse a.active'); const activeChildMenuItem = document.querySelector('ul#sidebar-menu ul.collapse a.active');

View File

@ -102,6 +102,11 @@
</main> </main>
<!-- End Body --> <!-- End Body -->
<script>
const sidebarSettings = {
minimizeSidebar: {% if request.session.MINIMIZE_SIDEBAR %}true{% else %}false{% endif %}
};
</script>
{% include "bundles/auth-sidebar-collapse-js.html" %} {% include "bundles/auth-sidebar-collapse-js.html" %}
{% theme_js %} {% theme_js %}

View File

@ -80,7 +80,10 @@ urlpatterns = [
path('night/', views.NightModeRedirectView.as_view(), name='nightmode'), path('night/', views.NightModeRedirectView.as_view(), name='nightmode'),
# Theme Change # Theme Change
path('theme/', views.ThemeRedirectView.as_view(), name='theme') path('theme/', views.ThemeRedirectView.as_view(), name='theme'),
# Minimize Menu
path('minimize-sidebar/', views.MinimizeSidebarRedirectView.as_view(), name='minimize_sidebar')
] ]
url_hooks = get_hooks("url_hook") url_hooks = get_hooks("url_hook")

View File

@ -48,6 +48,29 @@ class ThemeRedirectView(View):
return HttpResponseRedirect(request.GET.get("next", "/")) return HttpResponseRedirect(request.GET.get("next", "/"))
class MinimizeSidebarRedirectView(View):
SESSION_VAR = "MINIMIZE_SIDEBAR"
def post(self, request, *args, **kwargs):
request.session[self.SESSION_VAR] = not self.minimize_sidebar_state(request)
if not request.user.is_anonymous:
try:
request.user.profile.minimize_sidebar = request.session[self.SESSION_VAR]
request.user.profile.save()
except Exception as e:
logger.exception(e)
return HttpResponseRedirect(request.GET.get("next", "/"))
@classmethod
def minimize_sidebar_state(cls, request):
try:
return request.session.get(cls.SESSION_VAR, False)
except AttributeError:
# Session is middleware
# Sometimes request wont have a session attribute
return False
# TODO: error views should be renamed to a proper function name when possible # TODO: error views should be renamed to a proper function name when possible