This commit is contained in:
parent
ee8fba07ef
commit
a1a150b85e
4 changed files with 87 additions and 35 deletions
|
@ -1,6 +1,6 @@
|
|||
from django import forms
|
||||
|
||||
from servala.core.models import CloudProvider, ServiceCategory
|
||||
from servala.core.models import CloudProvider, ControlPlane, ServiceCategory
|
||||
|
||||
|
||||
class ServiceFilterForm(forms.Form):
|
||||
|
@ -20,3 +20,11 @@ class ServiceFilterForm(forms.Form):
|
|||
offerings__control_planes__cloud_provider=cloud_provider
|
||||
)
|
||||
return queryset
|
||||
|
||||
|
||||
class ControlPlaneSelectForm(forms.Form):
|
||||
control_plane = forms.ModelChoiceField(queryset=ControlPlane.objects.none())
|
||||
|
||||
def __init__(self, *args, planes=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields["control_plane"].queryset = planes
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
{% extends "frontend/base.html" %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load partials %}
|
||||
{% block html_title %}
|
||||
{% block page_title %}
|
||||
{{ offering }}
|
||||
{% endblock page_title %}
|
||||
{% endblock html_title %}
|
||||
{% partialdef service-form %}
|
||||
{% if service_form %}
|
||||
{% if form_error %}
|
||||
<div class="alert alert-danger">
|
||||
{% translate "Oops! Something went wrong with the service form generation. Please try again later." %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% include "includes/form.html" with form=service_form %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endpartialdef %}
|
||||
{% block content %}
|
||||
<section class="section">
|
||||
<div class="card">
|
||||
|
@ -23,17 +35,16 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
{% if offering.control_planes.all.count > 1 %}
|
||||
<p>{% translate "Please choose your zone." %}</p>
|
||||
{% else %}
|
||||
<p>
|
||||
{% blocktranslate trimmed with zone=offering.control_planes.all.first.name %}
|
||||
Your zone will be <strong>{{ zone }}</strong>.
|
||||
{% endblocktranslate %}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if offering.control_planes.all.count == 0 %}
|
||||
<p>{% translate "We currently cannot offer this service, sorry!" %}</p>
|
||||
{% else %}
|
||||
<form hx-trigger="change"
|
||||
hx-get="{{ request.path }}?fragment=service-form"
|
||||
hx-target="#service-form">
|
||||
{{ select_form }}
|
||||
</form>
|
||||
<div id="service-form">{% partial service-form %}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
|
|
@ -5,13 +5,30 @@ from rules.contrib.views import AutoPermissionRequiredMixin, PermissionRequiredM
|
|||
from servala.core.models import Organization
|
||||
|
||||
|
||||
class HtmxUpdateView(AutoPermissionRequiredMixin, UpdateView):
|
||||
class HtmxViewMixin:
|
||||
fragments = []
|
||||
|
||||
@cached_property
|
||||
def is_htmx(self):
|
||||
return self.request.headers.get("HX-Request")
|
||||
|
||||
def _get_fragment(self):
|
||||
if self.request.method == "POST":
|
||||
fragment = self.request.POST.get("fragment")
|
||||
else:
|
||||
fragment = self.request.GET.get("fragment")
|
||||
if fragment and fragment in self.fragments:
|
||||
return fragment
|
||||
|
||||
def get_template_names(self):
|
||||
template_names = super().get_template_names()
|
||||
if self.is_htmx and (fragment := self._get_fragment()):
|
||||
return [f"{template_names[0]}#{fragment}"]
|
||||
return template_names
|
||||
|
||||
|
||||
class HtmxUpdateView(AutoPermissionRequiredMixin, HtmxViewMixin, UpdateView):
|
||||
|
||||
@property
|
||||
def permission_type(self):
|
||||
if self.request.method == "POST" or getattr(
|
||||
|
@ -31,20 +48,6 @@ class HtmxUpdateView(AutoPermissionRequiredMixin, UpdateView):
|
|||
result["has_change_permission"] = self.has_change_permission()
|
||||
return result
|
||||
|
||||
def _get_fragment(self):
|
||||
if self.request.method == "POST":
|
||||
fragment = self.request.POST.get("fragment")
|
||||
else:
|
||||
fragment = self.request.GET.get("fragment")
|
||||
if fragment and fragment in self.fragments:
|
||||
return fragment
|
||||
|
||||
def get_template_names(self):
|
||||
template_names = super().get_template_names()
|
||||
if self.is_htmx and (fragment := self._get_fragment()):
|
||||
return [f"{template_names[0]}#{fragment}"]
|
||||
return template_names
|
||||
|
||||
def get_form_kwargs(self):
|
||||
result = super().get_form_kwargs()
|
||||
if self.is_htmx:
|
||||
|
@ -82,8 +85,8 @@ class OrganizationViewMixin(PermissionRequiredMixin):
|
|||
def get_permission_object(self):
|
||||
return self.organization
|
||||
|
||||
def has_organization_permission(self):
|
||||
return self.request.user.has_perm("core.view_organization", self.organization)
|
||||
|
||||
def has_permission(self):
|
||||
return (
|
||||
self.request.user.has_perm("core.view_organization", self.organization)
|
||||
and super().has_permission()
|
||||
)
|
||||
return self.has_organization_permission() and super().has_permission()
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
from django.utils.functional import cached_property
|
||||
from django.views.generic import DetailView, ListView
|
||||
|
||||
from servala.core.models import Service, ServiceOffering
|
||||
from servala.frontend.forms.service import ServiceFilterForm
|
||||
from servala.frontend.views.mixins import OrganizationViewMixin
|
||||
from servala.core.models import Service, ServiceOffering, ServiceOfferingControlPlane
|
||||
from servala.frontend.forms.service import ControlPlaneSelectForm, ServiceFilterForm
|
||||
from servala.frontend.views.mixins import HtmxViewMixin, OrganizationViewMixin
|
||||
|
||||
|
||||
class ServiceListView(OrganizationViewMixin, ListView):
|
||||
|
@ -44,13 +44,43 @@ class ServiceDetailView(OrganizationViewMixin, DetailView):
|
|||
)
|
||||
|
||||
|
||||
class ServiceOfferingDetailView(OrganizationViewMixin, DetailView):
|
||||
class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView):
|
||||
template_name = "frontend/organizations/service_offering_detail.html"
|
||||
context_object_name = "offering"
|
||||
model = ServiceOffering
|
||||
permission_type = "view"
|
||||
fragments = ("service-form",)
|
||||
|
||||
def has_permission(self):
|
||||
return self.has_organization_permission()
|
||||
|
||||
def get_queryset(self):
|
||||
return ServiceOffering.objects.all().select_related(
|
||||
"service", "service__category", "provider"
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def planes(self):
|
||||
return self.object.control_planes.all()
|
||||
|
||||
@cached_property
|
||||
def select_form(self):
|
||||
data = None
|
||||
if "control_plane" in self.request.GET:
|
||||
data = self.request.GET
|
||||
return ControlPlaneSelectForm(data=data, planes=self.planes)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["select_form"] = self.select_form
|
||||
if "control_plane" in self.request.GET:
|
||||
if self.select_form.is_valid():
|
||||
so_cp = ServiceOfferingControlPlane.objects.filter(
|
||||
control_plane=self.select_form.cleaned_data["control_plane"],
|
||||
service_offering=self.object,
|
||||
).first()
|
||||
if not so_cp:
|
||||
context["form_error"] = True
|
||||
else:
|
||||
context["service_form"] = so_cp.model_form_class()
|
||||
return context
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue