Inline user info in service offering page #250

Merged
tobru merged 4 commits from 243-service-provider-improvements into main 2025-10-27 10:15:09 +00:00
5 changed files with 56 additions and 10 deletions
Showing only changes of commit 75fe0799e0 - Show all commits

View file

@ -5,14 +5,25 @@ 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 = { CONTROL_PLANE_USER_INFO_SCHEMA = {
"type": "object", "type": "array",
"properties": { "items": {
"CNAME Record": { "type": "object",
"title": "CNAME Record", "properties": {
"type": "string", "title": {
"type": "string",
"title": "Title",
},
"content": {
"type": "string",
"title": "Content",
},
"help_text": {
"type": "string",
"title": "Help Text (optional)",
},
}, },
"required": ["title", "content"],
}, },
"additionalProperties": {"type": "string"},
} }

View file

@ -156,7 +156,8 @@ class ControlPlane(ServalaModelMixin, models.Model):
blank=True, blank=True,
verbose_name=_("User Information"), verbose_name=_("User Information"),
help_text=_( help_text=_(
"Key-value information displayed to users when selecting this control plane" 'Array of info objects: [{"title": "", "content": "", "help_text": ""}]. '
"The help_text field is optional and will be shown as a hover popover on an info icon."
), ),
) )
wildcard_dns = models.CharField( wildcard_dns = models.CharField(

View file

@ -248,3 +248,12 @@
</div> </div>
</div> </div>
{% endblock content %} {% endblock content %}
{% block extra_js %}
<script>
// Initialize Bootstrap popovers for help text
document.addEventListener('DOMContentLoaded', function() {
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
[...popoverTriggerList].map(el => new bootstrap.Popover(el));
});
</script>
{% endblock extra_js %}

View file

@ -108,4 +108,19 @@
</script> </script>
<script defer src="{% static "js/fqdn.js" %}"></script> <script defer src="{% static "js/fqdn.js" %}"></script>
{% endif %} {% endif %}
<script>
// Initialize Bootstrap popovers for help text
document.addEventListener('DOMContentLoaded', function() {
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]');
[...popoverTriggerList].map(el => new bootstrap.Popover(el));
});
// Re-initialize popovers after HTMX swaps
document.body.addEventListener('htmx:afterSwap', function(event) {
if (event.detail.target.id === 'control-plane-info') {
const popoverTriggerList = event.detail.target.querySelectorAll('[data-bs-toggle="popover"]');
[...popoverTriggerList].map(el => new bootstrap.Popover(el));
}
});
</script>
{% endblock extra_js %} {% endblock extra_js %}

View file

@ -3,10 +3,20 @@
<div class="table-responsive"> <div class="table-responsive">
<table class="table mb-0 table-lg"> <table class="table mb-0 table-lg">
<tbody> <tbody>
{% for key, value in control_plane.user_info.items %} {% for info in control_plane.user_info %}
<tr> <tr>
<th>{{ key }}</th> <th>
<td>{{ value }}</td> {{ info.title }}
{% if info.help_text %}
<i class="bi bi-info-circle ms-1"
data-bs-toggle="popover"
data-bs-trigger="hover focus"
data-bs-placement="top"
data-bs-content="{{ info.help_text }}"
style="cursor: help"></i>
{% endif %}
</th>
<td>{{ info.content }}</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>