Show additional ControlPlane information to users
This commit is contained in:
parent
db6aad66af
commit
09baaa5786
7 changed files with 159 additions and 50 deletions
|
|
@ -191,6 +191,15 @@ 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):
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,20 @@
|
||||||
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": {
|
||||||
|
"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(
|
||||||
|
|
@ -23,6 +35,7 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 5.2.4 on 2025-09-04 11:29
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("core", "0005_organization_sale_order_fields"),
|
||||||
|
]
|
||||||
|
|
||||||
|
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",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -144,6 +144,14 @@ 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")
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% if instance.status_conditions %}
|
|
||||||
<div class="col-12 col-md-7">
|
<div class="col-12 col-md-7">
|
||||||
|
{% if instance.status_conditions %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<h4>{% translate "Status" %}</h4>
|
<h4>{% translate "Status" %}</h4>
|
||||||
|
|
@ -101,8 +101,29 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if instance.context.control_plane.user_info %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h4 class="card-title">{% translate "Service Provider Information" %}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table mb-0 table-lg">
|
||||||
|
<tbody>
|
||||||
|
{% for key, value in instance.context.control_plane.user_info.items %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ key }}</th>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% 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">
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,29 @@
|
||||||
{{ offering }}
|
{{ offering }}
|
||||||
{% endblock page_title %}
|
{% endblock page_title %}
|
||||||
{% endblock html_title %}
|
{% endblock html_title %}
|
||||||
|
{% partialdef control-plane-info %}
|
||||||
|
{% if selected_plane and selected_plane.user_info %}
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h4 class="card-title">{% translate "Service Provider Information" %}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table mb-0 table-lg">
|
||||||
|
<tbody>
|
||||||
|
{% for key, value in selected_plane.user_info.items %}
|
||||||
|
<tr>
|
||||||
|
<th>{{ key }}</th>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endpartialdef %}
|
||||||
{% partialdef service-form %}
|
{% partialdef service-form %}
|
||||||
{% if service_form %}
|
{% if service_form %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|
@ -25,6 +48,8 @@
|
||||||
{% endpartialdef %}
|
{% endpartialdef %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<section class="section">
|
<section class="section">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-lg-8">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header d-flex align-items-center">
|
<div class="card-header d-flex align-items-center">
|
||||||
{% if service.logo %}
|
{% if service.logo %}
|
||||||
|
|
@ -52,7 +77,8 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<form hx-trigger="change"
|
<form hx-trigger="change"
|
||||||
hx-get="{{ request.path }}?fragment=service-form"
|
hx-get="{{ request.path }}?fragment=service-form"
|
||||||
hx-target="#service-form">
|
hx-target="#service-form"
|
||||||
|
hx-swap="outerHTML">
|
||||||
{{ select_form }}
|
{{ select_form }}
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
@ -77,5 +103,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="service-form">{% partial service-form %}</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 %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
|
||||||
|
|
@ -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",)
|
fragments = ("service-form", "control-plane-info")
|
||||||
|
|
||||||
def has_permission(self):
|
def has_permission(self):
|
||||||
return self.has_organization_permission()
|
return self.has_organization_permission()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue