diff --git a/src/servala/frontend/templates/frontend/organizations/services.html b/src/servala/frontend/templates/frontend/organizations/services.html new file mode 100644 index 0000000..6c6bba9 --- /dev/null +++ b/src/servala/frontend/templates/frontend/organizations/services.html @@ -0,0 +1,39 @@ +{% extends "frontend/base.html" %} +{% load i18n static %} +{% block html_title %} + {% block page_title %} + {% translate "Services" %} + {% endblock page_title %} +{% endblock html_title %} +{% block card_content %} +
+ {% for service in services %} +{{ service.description }}
{% endif %} +{% translate "No services found." %}
+ {% endfor %} + +{% endblock card_content %} diff --git a/src/servala/frontend/urls.py b/src/servala/frontend/urls.py index 59a7ccc..43a4a51 100644 --- a/src/servala/frontend/urls.py +++ b/src/servala/frontend/urls.py @@ -20,6 +20,11 @@ urlpatterns = [ views.OrganizationUpdateView.as_view(), name="organization.details", ), + path( + "services/", + views.OrganizationServicesView.as_view(), + name="organization.services", + ), path( "", views.OrganizationDashboardView.as_view(), diff --git a/src/servala/frontend/views/__init__.py b/src/servala/frontend/views/__init__.py index 4ff574a..a9f323a 100644 --- a/src/servala/frontend/views/__init__.py +++ b/src/servala/frontend/views/__init__.py @@ -5,6 +5,7 @@ from .organization import ( OrganizationDashboardView, OrganizationUpdateView, ) +from .service import OrganizationServicesView __all__ = [ "IndexView", @@ -12,5 +13,6 @@ __all__ = [ "OrganizationCreateView", "OrganizationDashboardView", "OrganizationUpdateView", + "OrganizationServicesView", "ProfileView", ] diff --git a/src/servala/frontend/views/mixins.py b/src/servala/frontend/views/mixins.py index 055366f..e27c28d 100644 --- a/src/servala/frontend/views/mixins.py +++ b/src/servala/frontend/views/mixins.py @@ -57,3 +57,29 @@ class HtmxUpdateView(AutoPermissionRequiredMixin, UpdateView): if self.is_htmx and self._get_fragment(): return self.get(self.request, *self.args, **self.kwargs) return result + + +class OrganizationViewMixin(PermissionRequiredMixin): + model = Organization + context_object_name = "organization" + permission_required = "core.view_organization" + + @cached_property + def organization(self): + return self.request.organization + + def get_object(self): + return self.organization + + @cached_property + def object(self): + return self.get_object() + + def get_permission_object(self): + return self.organization + + def has_permission(self): + return ( + self.request.user.has_perm("core.view_organization", self.organization) + and super().has_permission() + ) diff --git a/src/servala/frontend/views/organization.py b/src/servala/frontend/views/organization.py index c91a251..7bfdee5 100644 --- a/src/servala/frontend/views/organization.py +++ b/src/servala/frontend/views/organization.py @@ -1,11 +1,10 @@ from django.shortcuts import redirect -from django.utils.functional import cached_property from django.views.generic import CreateView, DetailView from rules.contrib.views import AutoPermissionRequiredMixin from servala.core.models import Organization from servala.frontend.forms import OrganizationForm -from servala.frontend.views.mixins import HtmxUpdateView +from servala.frontend.views.mixins import HtmxUpdateView, OrganizationViewMixin class OrganizationCreateView(AutoPermissionRequiredMixin, CreateView): @@ -20,22 +19,6 @@ class OrganizationCreateView(AutoPermissionRequiredMixin, CreateView): return redirect(instance.urls.base) -class OrganizationViewMixin: - model = Organization - context_object_name = "organization" - - @cached_property - def organization(self): - return self.request.organization - - def get_object(self): - return self.organization - - @cached_property - def object(self): - return self.get_object() - - class OrganizationDashboardView( AutoPermissionRequiredMixin, OrganizationViewMixin, DetailView ): diff --git a/src/servala/static/js/autosubmit.js b/src/servala/static/js/autosubmit.js new file mode 100644 index 0000000..c8e54cb --- /dev/null +++ b/src/servala/static/js/autosubmit.js @@ -0,0 +1,25 @@ +/** + * Auto-submit functionality for forms + * + * This script looks for forms with the 'auto-submit' attribute + * and automatically submits them when any input, select, or textarea + * within the form changes, useful for search/filter forms. + */ +document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('form[auto-submit]').forEach(form => { + const formElements = form.querySelectorAll('input, select, textarea') + + formElements.forEach(element => { + if (element.type === 'checkbox' || element.type === 'radio') { + element.addEventListener('change', () => { + form.submit() + }) + } + else if (element.tagName.toLowerCase() === 'select') { + element.addEventListener('change', () => { + form.submit() + }) + } + }) + }) +})