Compare commits

..

No commits in common. "5f75b0465f40e492776a5b23653085d6e9f0f02a" and "db6aad66af61f6d8a2875bc8bc818e943b217e7a" have entirely different histories.

8 changed files with 50 additions and 167 deletions

View file

@ -191,15 +191,6 @@ class ControlPlaneAdmin(admin.ModelAdmin):
), ),
}, },
), ),
(
_("User Information"),
{
"fields": ("user_info",),
"description": _(
"Key-value information displayed to users when selecting this control plane."
),
},
),
) )
def get_exclude(self, request, obj=None): def get_exclude(self, request, obj=None):

View file

@ -1,20 +1,8 @@
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django_jsonform.widgets import JSONFormWidget
from servala.core.models import ControlPlane, ServiceDefinition from servala.core.models import ControlPlane, ServiceDefinition
CONTROL_PLANE_USER_INFO_SCHEMA = {
"type": "object",
"properties": {
"CNAME Record": {
"title": "CNAME Record",
"type": "string",
},
},
"additionalProperties": {"type": "string"},
}
class ControlPlaneAdminForm(forms.ModelForm): class ControlPlaneAdminForm(forms.ModelForm):
certificate_authority_data = forms.CharField( certificate_authority_data = forms.CharField(
@ -35,7 +23,6 @@ class ControlPlaneAdminForm(forms.ModelForm):
class Meta: class Meta:
model = ControlPlane model = ControlPlane
fields = "__all__" fields = "__all__"
widgets = {"user_info": JSONFormWidget(schema=CONTROL_PLANE_USER_INFO_SCHEMA)}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View file

@ -1,43 +0,0 @@
# Generated by Django 5.2.6 on 2025-09-08 07:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("core", "0006_remove_service_instance_soft_delete"),
]
operations = [
migrations.AddField(
model_name="controlplane",
name="user_info",
field=models.JSONField(
blank=True,
help_text="Key-value information displayed to users when selecting this control plane",
null=True,
verbose_name="User Information",
),
),
migrations.AlterField(
model_name="cloudprovider",
name="external_links",
field=models.JSONField(
blank=True,
help_text='JSON array of link objects: {"url": "", "title": ""}. ',
null=True,
verbose_name="External links",
),
),
migrations.AlterField(
model_name="service",
name="external_links",
field=models.JSONField(
blank=True,
help_text='JSON array of link objects: {"url": "", "title": "", "featured": false}. Featured links will be shown on the service list page, all other links will only show on the service and offering detail pages.',
null=True,
verbose_name="External links",
),
),
]

View file

@ -144,14 +144,6 @@ class ControlPlane(ServalaModelMixin, models.Model):
related_name="control_planes", related_name="control_planes",
verbose_name=_("Cloud provider"), verbose_name=_("Cloud provider"),
) )
user_info = models.JSONField(
null=True,
blank=True,
verbose_name=_("User Information"),
help_text=_(
"Key-value information displayed to users when selecting this control plane"
),
)
class Meta: class Meta:
verbose_name = _("Control plane") verbose_name = _("Control plane")

View file

@ -58,8 +58,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-12 col-md-7"> {% if instance.status_conditions %}
{% if instance.status_conditions %} <div class="col-12 col-md-7">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<h4>{% translate "Status" %}</h4> <h4>{% translate "Status" %}</h4>
@ -101,9 +101,8 @@
</div> </div>
</div> </div>
</div> </div>
{% endif %} </div>
{% include "includes/control_plane_user_info.html" with control_plane=instance.context.control_plane %} {% endif %}
</div>
{% if instance.spec and spec_fieldsets %} {% if instance.spec and spec_fieldsets %}
<div class="col-12"> <div class="col-12">
<div class="card"> <div class="card">

View file

@ -7,11 +7,6 @@
{{ offering }} {{ offering }}
{% endblock page_title %} {% endblock page_title %}
{% endblock html_title %} {% endblock html_title %}
{% partialdef control-plane-info %}
{% if selected_plane %}
{% include "includes/control_plane_user_info.html" with control_plane=selected_plane %}
{% endif %}
{% endpartialdef %}
{% partialdef service-form %} {% partialdef service-form %}
{% if service_form %} {% if service_form %}
<div class="card"> <div class="card">
@ -30,69 +25,57 @@
{% endpartialdef %} {% endpartialdef %}
{% block content %} {% block content %}
<section class="section"> <section class="section">
<div class="row"> <div class="card">
<div class="col-12 col-lg-8"> <div class="card-header d-flex align-items-center">
<div class="card"> {% if service.logo %}
<div class="card-header d-flex align-items-center"> <img src="{{ service.logo.url }}"
{% if service.logo %} alt="{{ service.name }}"
<img src="{{ service.logo.url }}" class="me-3"
alt="{{ service.name }}" style="max-width: 48px;
class="me-3" max-height: 48px">
style="max-width: 48px; {% endif %}
max-height: 48px"> <div class="d-flex flex-column">
{% endif %} <h4 class="mb-0">{{ offering }}</h4>
<div class="d-flex flex-column"> <small class="text-muted">{{ offering.service.category }}</small>
<h4 class="mb-0">{{ offering }}</h4> </div>
<small class="text-muted">{{ offering.service.category }}</small> </div>
<div class="card-body">
{% if offering.description %}
<div class="row mb-3">
<div class="col-12">
<p>{{ offering.description|urlize }}</p>
</div> </div>
</div> </div>
<div class="card-body"> {% endif %}
{% if offering.description %} {% if not has_control_planes %}
<div class="row mb-3"> <p>{% translate "We currently cannot offer this service, sorry!" %}</p>
<div class="col-12"> {% else %}
<p>{{ offering.description|urlize }}</p> <form hx-trigger="change"
</div> hx-get="{{ request.path }}?fragment=service-form"
hx-target="#service-form">
{{ select_form }}
</form>
{% endif %}
{% if service.external_links %}
<div class="row mt-3">
<div class="col-12">
<h6 class="mb-3">{% translate "External Links" %}</h6>
<div class="d-flex flex-wrap gap-2">
{% for link in service.external_links %}
<a href="{{ link.url }}"
target="_blank"
rel="noopener noreferrer"
class="btn btn-outline-primary btn-sm">
{{ link.title }}
<i class="bi bi-box-arrow-up-right ms-1"></i>
</a>
{% endfor %}
</div> </div>
{% endif %} </div>
{% if not has_control_planes %}
<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"
hx-swap="outerHTML">
{{ select_form }}
</form>
{% endif %}
{% if service.external_links %}
<div class="row mt-3">
<div class="col-12">
<h6 class="mb-3">{% translate "External Links" %}</h6>
<div class="d-flex flex-wrap gap-2">
{% for link in service.external_links %}
<a href="{{ link.url }}"
target="_blank"
rel="noopener noreferrer"
class="btn btn-outline-primary btn-sm">
{{ link.title }}
<i class="bi bi-box-arrow-up-right ms-1"></i>
</a>
{% endfor %}
</div>
</div>
</div>
{% endif %}
</div> </div>
</div>
<div id="service-form">{% partial service-form %}</div>
</div>
<div class="col-12 col-lg-4">
{% if has_control_planes %}
<div id="control-plane-info"
hx-trigger="load, change from:form"
hx-get="{{ request.path }}?fragment=control-plane-info">{% partial control-plane-info %}</div>
{% endif %} {% endif %}
</div> </div>
</div> </div>
<div id="service-form">{% partial service-form %}</div>
</section> </section>
{% endblock content %} {% endblock content %}

View file

@ -1,26 +0,0 @@
{% load i18n %}
{% comment %}
Reusable snippet for displaying ControlPlane user_info
Usage: {% include "includes/control_plane_user_info.html" with control_plane=control_plane_object %}
{% endcomment %}
{% if control_plane.user_info %}
<div class="card">
<div class="card-header">
<h4 class="card-title">{% translate "Service Provider Zone Information" %}</h4>
</div>
<div class="card-content">
<div class="table-responsive">
<table class="table mb-0 table-lg">
<tbody>
{% for key, value in control_plane.user_info.items %}
<tr>
<th>{{ key }}</th>
<td>{{ value }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}

View file

@ -73,7 +73,7 @@ class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView
context_object_name = "offering" context_object_name = "offering"
model = ServiceOffering model = ServiceOffering
permission_type = "view" permission_type = "view"
fragments = ("service-form", "control-plane-info") fragments = ("service-form",)
def has_permission(self): def has_permission(self):
return self.has_organization_permission() return self.has_organization_permission()