diff --git a/src/servala/frontend/templates/frontend/base.html b/src/servala/frontend/templates/frontend/base.html index 1301bec..7c6bc54 100644 --- a/src/servala/frontend/templates/frontend/base.html +++ b/src/servala/frontend/templates/frontend/base.html @@ -93,5 +93,7 @@ })(); + {% block extra_js %} + {% endblock extra_js %} diff --git a/src/servala/frontend/templates/frontend/organizations/service_offering_detail.html b/src/servala/frontend/templates/frontend/organizations/service_offering_detail.html index c2049c7..842e610 100644 --- a/src/servala/frontend/templates/frontend/organizations/service_offering_detail.html +++ b/src/servala/frontend/templates/frontend/organizations/service_offering_detail.html @@ -93,3 +93,14 @@ {% endblock content %} +{% block extra_js %} + {% if wildcard_dns and organization_namespace %} + + + {% endif %} +{% endblock extra_js %} diff --git a/src/servala/frontend/views/service.py b/src/servala/frontend/views/service.py index a0390b8..ba4f0a4 100644 --- a/src/servala/frontend/views/service.py +++ b/src/servala/frontend/views/service.py @@ -132,12 +132,25 @@ class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView def get_instance_form(self): if not self.context_object or not self.context_object.model_form_class: return None - return self.context_object.model_form_class( + + initial = { + "organization": self.request.organization, + "context": self.context_object, + } + + # Pre-populate FQDN field if it exists and control plane has wildcard DNS + form_class = self.context_object.model_form_class + if ( + "spec.parameters.service.fqdn" in form_class.base_fields + and self.context_object.control_plane.wildcard_dns + ): + # Generate initial FQDN: instancename-namespace.wildcard_dns + # We'll set a placeholder that JavaScript will replace dynamically + initial["spec.parameters.service.fqdn"] = "" + + return form_class( data=self.request.POST if self.request.method == "POST" else None, - initial={ - "organization": self.request.organization, - "context": self.context_object, - }, + initial=initial, ) def get_context_data(self, **kwargs): @@ -146,6 +159,10 @@ class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView context["has_control_planes"] = self.planes.exists() context["selected_plane"] = self.selected_plane context["service_form"] = self.get_instance_form() + # Pass data for dynamic FQDN generation + if self.selected_plane and self.selected_plane.wildcard_dns: + context["wildcard_dns"] = self.selected_plane.wildcard_dns + context["organization_namespace"] = self.request.organization.namespace return context def post(self, request, *args, **kwargs): diff --git a/src/servala/static/js/fqdn.js b/src/servala/static/js/fqdn.js new file mode 100644 index 0000000..7b61c9a --- /dev/null +++ b/src/servala/static/js/fqdn.js @@ -0,0 +1,38 @@ + +const initializeFqdnGeneration = () => { + const nameField = document.querySelector('input[name="name"]'); + const fqdnField = document.querySelector('label[for="id_spec.parameters.service.fqdn"] + div input.array-item-input'); + + if (nameField && fqdnField) { + const generateFqdn = (instanceName) => { + if (!instanceName) return ''; + return `${instanceName}-${fqdnConfig.namespace}.${fqdnConfig.wildcardDns}`; + } + + const newNameField = nameField.cloneNode(true); + nameField.parentNode.replaceChild(newNameField, nameField); + const newFqdnField = fqdnField.cloneNode(true); + fqdnField.parentNode.replaceChild(newFqdnField, fqdnField); + + newNameField.addEventListener('input', function() { + if (!newFqdnField.dataset.manuallyEdited) { + newFqdnField.value = generateFqdn(this.value); + } + }); + + newFqdnField.addEventListener('input', function() { + this.dataset.manuallyEdited = 'true'; + }); + + if (newNameField.value && !newFqdnField.value) { + newFqdnField.value = generateFqdn(newNameField.value); + } + } +} + +document.addEventListener('DOMContentLoaded', initializeFqdnGeneration); +document.body.addEventListener('htmx:afterSwap', function(event) { + if (event.detail.target.id === 'service-form') { + initializeFqdnGeneration(); + } +});