Generate wildcard DNS in frontend

ref #203
This commit is contained in:
Tobias Kunze 2025-10-14 17:05:22 +02:00
parent 573b7a5eb5
commit 3375a1c8f3
4 changed files with 73 additions and 5 deletions

View file

@ -93,5 +93,7 @@
})(); })();
</script> </script>
<!-- Ybug code end --> <!-- Ybug code end -->
{% block extra_js %}
{% endblock extra_js %}
</body> </body>
</html> </html>

View file

@ -93,3 +93,14 @@
</div> </div>
</section> </section>
{% endblock content %} {% endblock content %}
{% block extra_js %}
{% if wildcard_dns and organization_namespace %}
<script>
const fqdnConfig = {
wildcardDns: '{{ wildcard_dns }}',
namespace: '{{ organization_namespace }}'
};
</script>
<script defer src="{% static "js/fqdn.js" %}"></script>
{% endif %}
{% endblock extra_js %}

View file

@ -132,12 +132,25 @@ class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView
def get_instance_form(self): def get_instance_form(self):
if not self.context_object or not self.context_object.model_form_class: if not self.context_object or not self.context_object.model_form_class:
return None 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, data=self.request.POST if self.request.method == "POST" else None,
initial={ initial=initial,
"organization": self.request.organization,
"context": self.context_object,
},
) )
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -146,6 +159,10 @@ class ServiceOfferingDetailView(OrganizationViewMixin, HtmxViewMixin, DetailView
context["has_control_planes"] = self.planes.exists() context["has_control_planes"] = self.planes.exists()
context["selected_plane"] = self.selected_plane context["selected_plane"] = self.selected_plane
context["service_form"] = self.get_instance_form() 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 return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):

View file

@ -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();
}
});