From 4495899c0201308e4f6c1270bdb4c67bb6e6d4fb Mon Sep 17 00:00:00 2001 From: Tobias Kunze Date: Fri, 4 Apr 2025 17:46:33 +0200 Subject: [PATCH] Add filter and search to instance list --- src/servala/frontend/forms/service.py | 57 +++++++++++- .../organizations/service_instances.html | 92 +++++++++++-------- src/servala/frontend/views/service.py | 20 +++- 3 files changed, 128 insertions(+), 41 deletions(-) diff --git a/src/servala/frontend/forms/service.py b/src/servala/frontend/forms/service.py index 3b7a547..428f1bc 100644 --- a/src/servala/frontend/forms/service.py +++ b/src/servala/frontend/forms/service.py @@ -1,7 +1,13 @@ from django import forms from django.utils.translation import gettext_lazy as _ -from servala.core.models import CloudProvider, ControlPlane, ServiceCategory +from servala.core.models import ( + CloudProvider, + ControlPlane, + Service, + ServiceCategory, + ServiceOffering, +) class ServiceFilterForm(forms.Form): @@ -33,3 +39,52 @@ class ControlPlaneSelectForm(forms.Form): def __init__(self, *args, planes=None, **kwargs): super().__init__(*args, **kwargs) self.fields["control_plane"].queryset = planes + + +class ServiceInstanceFilterForm(forms.Form): + name = forms.CharField(required=False, label=_("Name")) + service = forms.ModelChoiceField( + queryset=Service.objects.all(), required=False, label=_("Service") + ) + provider = forms.ModelChoiceField( + queryset=ServiceOffering.objects.all() + .values_list("provider", flat=True) + .distinct(), + required=False, + label=_("Provider"), + ) + control_plane = forms.ModelChoiceField( + queryset=ControlPlane.objects.all(), + required=False, + label=_("Service Provider Zone"), + ) + status = forms.ChoiceField( + choices=( + ("active", _("Active")), + ("deleted", _("Deleted")), + ), + required=False, + label=_("Status"), + ) + + def filter_queryset(self, queryset): + if self.is_valid(): + data = self.cleaned_data + if data["name"]: + queryset = queryset.filter(name__icontains=data["name"]) + if data["service"]: + queryset = queryset.filter( + context__service_definition__service=data["service"] + ) + if data["provider"]: + queryset = queryset.filter( + context__service_offering__provider=data["provider"] + ) + if data["control_plane"]: + queryset = queryset.filter(context__control_plane=data["control_plane"]) + if data["status"]: + if data["status"] == "active": + queryset = queryset.filter(is_deleted=False) + else: + queryset = queryset.filter(is_deleted=True) + return queryset diff --git a/src/servala/frontend/templates/frontend/organizations/service_instances.html b/src/servala/frontend/templates/frontend/organizations/service_instances.html index d335049..e5c7c0e 100644 --- a/src/servala/frontend/templates/frontend/organizations/service_instances.html +++ b/src/servala/frontend/templates/frontend/organizations/service_instances.html @@ -5,41 +5,59 @@ {% translate "Instances" %} {% endblock page_title %} {% endblock html_title %} -{% block card_content %} - - - - - - - - - - - - - {% for instance in instances %} - - - - - - - - - {% empty %} - - - - {% endfor %} - -
{% translate "Name" %}{% translate "Service" %}{% translate "Service Provider" %}{% translate "Service Provider Zone" %}{% translate "Created At" %}{% translate "Status" %}
- {{ instance.name }} - {{ instance.context.service_definition.service.name }}{{ instance.context.service_offering.provider.name }}{{ instance.context.control_plane.name }}{{ instance.created_at|date:"SHORT_DATETIME_FORMAT" }} - {% if instance.is_deleted %} - {% translate "Deleted" %} - {% else %} - {% translate "Active" %} - {% endif %} -
{% translate "No service instances found." %}
+{% block content %} +
+
+
+
+
+ {{ filter_form }} +
+
+
+
+
+
+
+ + + + + + + + + + + + + {% for instance in instances %} + + + + + + + + + {% empty %} + + + + {% endfor %} + +
{% translate "Name" %}{% translate "Service" %}{% translate "Service Provider" %}{% translate "Service Provider Zone" %}{% translate "Created At" %}{% translate "Status" %}
+ {{ instance.name }} + {{ instance.context.service_definition.service.name }}{{ instance.context.service_offering.provider.name }}{{ instance.context.control_plane.name }}{{ instance.created_at|date:"SHORT_DATETIME_FORMAT" }} + {% if instance.is_deleted %} + {% translate "Deleted" %} + {% else %} + {% translate "Active" %} + {% endif %} +
{% translate "No service instances found." %}
+
+
+
+
+ {% endblock %} diff --git a/src/servala/frontend/views/service.py b/src/servala/frontend/views/service.py index c955cde..380f393 100644 --- a/src/servala/frontend/views/service.py +++ b/src/servala/frontend/views/service.py @@ -10,7 +10,11 @@ from servala.core.models import ( ServiceInstance, ServiceOffering, ) -from servala.frontend.forms.service import ControlPlaneSelectForm, ServiceFilterForm +from servala.frontend.forms.service import ( + ControlPlaneSelectForm, + ServiceFilterForm, + ServiceInstanceFilterForm, +) from servala.frontend.views.mixins import HtmxViewMixin, OrganizationViewMixin @@ -151,11 +155,21 @@ class ServiceInstanceListView(OrganizationViewMixin, ListView): model = ServiceInstance permission_type = "view" + @cached_property + def filter_form(self): + return ServiceInstanceFilterForm(data=self.request.GET or None) + def get_queryset(self): - """Return all service instances for the current organization.""" - return ServiceInstance.objects.filter(organization=self.request.organization) + """Return all service instances for the current organization with filtering.""" + queryset = ServiceInstance.objects.filter( + organization=self.request.organization + ) + if self.filter_form.is_valid(): + queryset = self.filter_form.filter_queryset(queryset) + return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["organization"] = self.request.organization + context["filter_form"] = self.filter_form return context