diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py
index 0809cb2f4..9e29f6477 100644
--- a/netbox/circuits/forms/model_forms.py
+++ b/netbox/circuits/forms/model_forms.py
@@ -7,6 +7,7 @@ from ipam.models import ASN
from netbox.forms import NetBoxModelForm
from tenancy.forms import TenancyForm
from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField
+from utilities.forms.rendering import TabbedFieldGroups
from utilities.forms.widgets import DatePicker, NumberWithOptions
__all__ = (
@@ -146,6 +147,21 @@ class CircuitTerminationForm(NetBoxModelForm):
selector=True
)
+ fieldsets = (
+ (_('Circuit Termination'), (
+ 'circuit',
+ 'term_side',
+ 'description',
+ 'tags',
+ TabbedFieldGroups(
+ (_('Site'), 'site'),
+ (_('Provider Network'), 'provider_network'),
+ ),
+ 'mark_connected',
+ )),
+ (_('Termination Details'), ('port_speed', 'upstream_speed', 'xconnect_id', 'pp_info')),
+ )
+
class Meta:
model = CircuitTermination
fields = [
diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py
index 64dd82682..0c01d6eb9 100644
--- a/netbox/circuits/views.py
+++ b/netbox/circuits/views.py
@@ -412,7 +412,6 @@ class CircuitContactsView(ObjectContactsView):
class CircuitTerminationEditView(generic.ObjectEditView):
queryset = CircuitTermination.objects.all()
form = forms.CircuitTerminationForm
- template_name = 'circuits/circuittermination_edit.html'
@register_model_view(CircuitTermination, 'delete')
diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py
index 07f782f7f..85f9591a8 100644
--- a/netbox/ipam/forms/model_forms.py
+++ b/netbox/ipam/forms/model_forms.py
@@ -16,7 +16,7 @@ from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
SlugField,
)
-from utilities.forms.rendering import ObjectAttribute
+from utilities.forms.rendering import InlineFields, ObjectAttribute, TabbedFieldGroups
from utilities.forms.widgets import DatePicker
from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface
@@ -308,6 +308,20 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
)
comments = CommentField()
+ fieldsets = (
+ (_('IP Address'), ('address', 'status', 'role', 'vrf', 'dns_name', 'description', 'tags')),
+ (_('Tenancy'), ('tenant_group', 'tenant')),
+ (_('Assignment'), (
+ TabbedFieldGroups(
+ (_('Device'), 'interface'),
+ (_('Virtual Machine'), 'vminterface'),
+ (_('FHRP Group'), 'fhrpgroup'),
+ ),
+ 'primary_for_parent',
+ )),
+ (_('NAT IP (Inside)'), ('nat_inside',)),
+ )
+
class Meta:
model = IPAddress
fields = [
@@ -709,6 +723,20 @@ class ServiceForm(NetBoxModelForm):
)
comments = CommentField()
+ fieldsets = (
+ (_('Service'), (
+ TabbedFieldGroups(
+ (_('Device'), 'device'),
+ (_('Virtual Machine'), 'virtual_machine'),
+ ),
+ 'name',
+ InlineFields(_('Port(s)'), 'protocol', 'ports'),
+ 'ipaddresses',
+ 'description',
+ 'tags',
+ )),
+ )
+
class Meta:
model = Service
fields = [
@@ -723,6 +751,22 @@ class ServiceCreateForm(ServiceForm):
required=False
)
+ fieldsets = (
+ (_('Service'), (
+ TabbedFieldGroups(
+ (_('Device'), 'device'),
+ (_('Virtual Machine'), 'virtual_machine'),
+ ),
+ TabbedFieldGroups(
+ (_('From Template'), 'service_template'),
+ (_('Custom'), 'name', 'protocol', 'ports'),
+ ),
+ 'ipaddresses',
+ 'description',
+ 'tags',
+ )),
+ )
+
class Meta(ServiceForm.Meta):
fields = [
'device', 'virtual_machine', 'service_template', 'name', 'protocol', 'ports', 'ipaddresses', 'description',
diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py
index 79716f082..6870d1e9e 100644
--- a/netbox/ipam/views.py
+++ b/netbox/ipam/views.py
@@ -781,7 +781,6 @@ class IPAddressView(generic.ObjectView):
class IPAddressEditView(generic.ObjectEditView):
queryset = IPAddress.objects.all()
form = forms.IPAddressForm
- template_name = 'ipam/ipaddress_edit.html'
def alter_object(self, obj, request, url_args, url_kwargs):
@@ -1235,14 +1234,12 @@ class ServiceView(generic.ObjectView):
class ServiceCreateView(generic.ObjectEditView):
queryset = Service.objects.all()
form = forms.ServiceCreateForm
- template_name = 'ipam/service_create.html'
@register_model_view(Service, 'edit')
class ServiceEditView(generic.ObjectEditView):
queryset = Service.objects.all()
form = forms.ServiceForm
- template_name = 'ipam/service_edit.html'
@register_model_view(Service, 'delete')
diff --git a/netbox/templates/circuits/circuittermination_edit.html b/netbox/templates/circuits/circuittermination_edit.html
deleted file mode 100644
index 18198cb72..000000000
--- a/netbox/templates/circuits/circuittermination_edit.html
+++ /dev/null
@@ -1,58 +0,0 @@
-{% extends 'generic/object_edit.html' %}
-{% load static %}
-{% load form_helpers %}
-{% load i18n %}
-
-{% block form %}
-
-
-
{% trans "Circuit Termination" %}
-
- {% render_field form.circuit %}
- {% render_field form.term_side %}
- {% render_field form.tags %}
- {% render_field form.mark_connected %}
- {% with providernetwork_tab_active=form.initial.provider_network %}
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
- {% render_field form.site %}
-
-
- {% render_field form.provider_network %}
-
-
- {% endwith %}
-
-
-
-
-
{% trans "Termination Details" %}
-
- {% render_field form.port_speed %}
- {% render_field form.upstream_speed %}
- {% render_field form.xconnect_id %}
- {% render_field form.pp_info %}
- {% render_field form.description %}
-
-
- {% if form.custom_fields %}
-
-
-
{% trans "Custom Fields" %}
-
- {% render_custom_fields form %}
-
- {% endif %}
-{% endblock %}
diff --git a/netbox/templates/ipam/ipaddress_edit.html b/netbox/templates/ipam/ipaddress_edit.html
deleted file mode 100644
index d9157f5ef..000000000
--- a/netbox/templates/ipam/ipaddress_edit.html
+++ /dev/null
@@ -1,93 +0,0 @@
-{% extends 'generic/object_edit.html' %}
-{% load static %}
-{% load form_helpers %}
-{% load helpers %}
-{% load i18n %}
-
-{% block tabs %}
- {% include 'ipam/inc/ipaddress_edit_header.html' with active_tab='add' %}
-{% endblock tabs %}
-
-{% block form %}
-
-
-
{% trans "IP Address" %}
-
- {% render_field form.address %}
- {% render_field form.status %}
- {% render_field form.role %}
- {% render_field form.vrf %}
- {% render_field form.dns_name %}
- {% render_field form.description %}
- {% render_field form.tags %}
-
-
-
-
-
{% trans "Tenancy" %}
-
- {% render_field form.tenant_group %}
- {% render_field form.tenant %}
-
-
-
-
-
{% trans "Interface Assignment" %}
-
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
-
-
- {% render_field form.interface %}
-
-
- {% render_field form.vminterface %}
-
-
- {% render_field form.fhrpgroup %}
-
- {% render_field form.primary_for_parent %}
-
-
-
-
-
-
{% trans "NAT IP (Inside" %})
-
-
- {% render_field form.nat_inside %}
-
-
-
-
- {% render_field form.comments %}
-
-
- {% if form.custom_fields %}
-
-
-
{% trans "Custom Fields" %}
-
- {% render_custom_fields form %}
-
- {% endif %}
-{% endblock %}
diff --git a/netbox/templates/ipam/service_create.html b/netbox/templates/ipam/service_create.html
deleted file mode 100644
index d145999c0..000000000
--- a/netbox/templates/ipam/service_create.html
+++ /dev/null
@@ -1,79 +0,0 @@
-{% extends 'generic/object_edit.html' %}
-{% load form_helpers %}
-{% load i18n %}
-
-{% block form %}
-
-
-
{% trans "Service" %}
-
-
- {# Device/VM selection #}
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
- {% render_field form.device %}
-
-
- {% render_field form.virtual_machine %}
-
-
-
- {# Template or custom #}
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
- {% render_field form.service_template %}
-
-
- {% render_field form.name %}
- {% render_field form.protocol %}
- {% render_field form.ports %}
-
-
- {% render_field form.ipaddresses %}
- {% render_field form.description %}
- {% render_field form.tags %}
-
-
-
- {% render_field form.comments %}
-
-
- {% if form.custom_fields %}
-
-
{% trans "Custom Fields" %}
-
- {% render_custom_fields form %}
- {% endif %}
-{% endblock %}
diff --git a/netbox/templates/ipam/service_edit.html b/netbox/templates/ipam/service_edit.html
deleted file mode 100644
index 33eda76e1..000000000
--- a/netbox/templates/ipam/service_edit.html
+++ /dev/null
@@ -1,66 +0,0 @@
-{% extends 'generic/object_edit.html' %}
-{% load form_helpers %}
-{% load i18n %}
-
-{% block form %}
-
-
-
{% trans "Service" %}
-
-
-
-
-
- -
-
-
- -
-
-
-
-
-
-
-
- {% render_field form.device %}
-
-
- {% render_field form.virtual_machine %}
-
-
- {% render_field form.name %}
-
-
-
- {{ form.protocol }}
-
-
- {{ form.ports }}
-
-
-
-
-
- {{ form.ports.help_text }}
-
-
- {% render_field form.ipaddresses %}
- {% render_field form.description %}
- {% render_field form.tags %}
-
-
-
- {% render_field form.comments %}
-
-
- {% if form.custom_fields %}
-
-
{% trans "Custom Fields" %}
-
- {% render_custom_fields form %}
- {% endif %}
-{% endblock %}
diff --git a/netbox/templates/vpn/l2vpntermination_edit.html b/netbox/templates/vpn/l2vpntermination_edit.html
deleted file mode 100644
index 14b30c78d..000000000
--- a/netbox/templates/vpn/l2vpntermination_edit.html
+++ /dev/null
@@ -1,56 +0,0 @@
-{% extends 'generic/object_edit.html' %}
-{% load helpers %}
-{% load form_helpers %}
-{% load i18n %}
-
-{% block form %}
-
-
-
{% trans "L2VPN Termination" %}
-
- {% render_field form.l2vpn %}
-
-
-
- -
-
-
- -
-
-
- -
-
-
-
-
-
-
-
-
- {% render_field form.vlan %}
-
-
- {% render_field form.interface %}
-
-
- {% render_field form.vminterface %}
-
- {% render_field form.tags %}
-
-
-
- {% if form.custom_fields %}
-
-
-
{% trans "Custom Fields" %}
-
- {% render_custom_fields form %}
-
-{% endif %}
-{% endblock %}
diff --git a/netbox/utilities/templates/form_helpers/render_fieldset.html b/netbox/utilities/templates/form_helpers/render_fieldset.html
index d4c7981f7..d978997af 100644
--- a/netbox/utilities/templates/form_helpers/render_fieldset.html
+++ b/netbox/utilities/templates/form_helpers/render_fieldset.html
@@ -26,7 +26,7 @@
{% elif layout == 'inline' %}
{# Multiple form fields on the same line #}
-
+
{% for field in items %}
{{ field }}
@@ -37,16 +37,18 @@
{% elif layout == 'tabs' %}
{# Tabbed groups of fields #}
-
-
- {% for tab in items %}
- -
-
-
- {% endfor %}
-
+
+
+
+ {% for tab in items %}
+ -
+
+
+ {% endfor %}
+
+
{% for tab in items %}
diff --git a/netbox/vpn/forms/model_forms.py b/netbox/vpn/forms/model_forms.py
index 9e5e17a09..efb8a7eda 100644
--- a/netbox/vpn/forms/model_forms.py
+++ b/netbox/vpn/forms/model_forms.py
@@ -7,6 +7,7 @@ from ipam.models import IPAddress, RouteTarget, VLAN
from netbox.forms import NetBoxModelForm
from tenancy.forms import TenancyForm
from utilities.forms.fields import CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField
+from utilities.forms.rendering import TabbedFieldGroups
from utilities.forms.utils import add_blank_choice, get_field_value
from utilities.forms.widgets import HTMXSelect
from virtualization.models import VirtualMachine, VMInterface
@@ -444,6 +445,18 @@ class L2VPNTerminationForm(NetBoxModelForm):
label=_('Interface')
)
+ fieldsets = (
+ (None, (
+ 'l2vpn',
+ TabbedFieldGroups(
+ (_('VLAN'), 'vlan'),
+ (_('Device'), 'interface'),
+ (_('Virtual Machine'), 'vminterface'),
+ ),
+ 'tags',
+ )),
+ )
+
class Meta:
model = L2VPNTermination
fields = ('l2vpn', 'tags')
diff --git a/netbox/vpn/views.py b/netbox/vpn/views.py
index 9bf424af9..af1f653c8 100644
--- a/netbox/vpn/views.py
+++ b/netbox/vpn/views.py
@@ -479,7 +479,6 @@ class L2VPNTerminationView(generic.ObjectView):
class L2VPNTerminationEditView(generic.ObjectEditView):
queryset = L2VPNTermination.objects.all()
form = forms.L2VPNTerminationForm
- template_name = 'vpn/l2vpntermination_edit.html'
@register_model_view(L2VPNTermination, 'delete')