Build raw service list view, refactor mixins
This commit is contained in:
parent
f0e34c2419
commit
8484fef8f2
6 changed files with 98 additions and 18 deletions
|
@ -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 %}
|
||||
<form class="search-form" auto-submit>
|
||||
{{ filter_form }}
|
||||
</form>
|
||||
{% for service in services %}
|
||||
<div class="col-12 col-md-6 col-lg-4 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-content">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
{% if service.logo %}
|
||||
<img src="{{ service.logo.url }}"
|
||||
alt="{{ service.name }}"
|
||||
class="me-3"
|
||||
style="max-width: 48px;
|
||||
max-height: 48px">
|
||||
{% endif %}
|
||||
<h5 class="card-title mb-0">{{ service.name }}</h5>
|
||||
</div>
|
||||
{% if service.description %}<p class="card-text">{{ service.description }}</p>{% endif %}
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-end">
|
||||
<a href="#" class="btn btn-primary">{% translate "View Details" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<p>{% translate "No services found." %}</p>
|
||||
{% endfor %}
|
||||
<script src="{% static "js/autosubmit.js" %}" defer></script>
|
||||
{% endblock card_content %}
|
|
@ -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(),
|
||||
|
|
|
@ -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",
|
||||
]
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
|
|
|
@ -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
|
||||
):
|
||||
|
|
25
src/servala/static/js/autosubmit.js
Normal file
25
src/servala/static/js/autosubmit.js
Normal file
|
@ -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()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue