1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Replace custom form templates with TabbedFieldGroups

This commit is contained in:
Jeremy Stretch
2024-03-13 10:59:00 -04:00
parent 8f03a19b5f
commit 2aaa552067
12 changed files with 87 additions and 369 deletions

View File

@ -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 = [

View File

@ -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')

View File

@ -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',

View File

@ -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')

View File

@ -1,58 +0,0 @@
{% extends 'generic/object_edit.html' %}
{% load static %}
{% load form_helpers %}
{% load i18n %}
{% block form %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Circuit Termination" %}</h5>
</div>
{% 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 %}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link{% if not providernetwork_tab_active %} active{% endif %}" role="tab" type="button" data-bs-target="#site" data-bs-toggle="tab">{% trans "Site" %}</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link{% if providernetwork_tab_active %} active{% endif %}" role="tab" type="button" data-bs-toggle="tab" data-bs-target="#providernetwork">{% trans "Provider Network" %}</button>
</li>
</ul>
</div>
</div>
<div class="tab-content p-0 border-0">
<div class="tab-pane{% if not providernetwork_tab_active %} active{% endif %}" id="site">
{% render_field form.site %}
</div>
<div class="tab-pane{% if providernetwork_tab_active %} active{% endif %}" id="providernetwork">
{% render_field form.provider_network %}
</div>
</div>
{% endwith %}
</div>
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Termination Details" %}</h5>
</div>
{% render_field form.port_speed %}
{% render_field form.upstream_speed %}
{% render_field form.xconnect_id %}
{% render_field form.pp_info %}
{% render_field form.description %}
</div>
{% if form.custom_fields %}
<div class="field-group mb-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Custom Fields" %}</h5>
</div>
{% render_custom_fields form %}
</div>
{% endif %}
{% endblock %}

View File

@ -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 %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "IP Address" %}</h5>
</div>
{% 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 %}
</div>
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Tenancy" %}</h5>
</div>
{% render_field form.tenant_group %}
{% render_field form.tenant %}
</div>
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Interface Assignment" %}</h5>
</div>
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.vminterface and not form.initial.fhrpgroup %}active{% endif %}">
{% trans "Device" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="vm_tab" data-bs-toggle="tab" aria-controls="vm" data-bs-target="#vm" class="nav-link {% if form.initial.vminterface %}active{% endif %}">
{% trans "Virtual Machine" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="fhrpgroup_tab" data-bs-toggle="tab" aria-controls="fhrpgroup" data-bs-target="#fhrpgroup" class="nav-link {% if form.initial.fhrpgroup %}active{% endif %}">
{% trans "FHRP Group" %}
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content p-0 border-0">
<div class="tab-pane {% if not form.initial.vminterface and not form.initial.fhrpgroup %}active{% endif %}" id="device" role="tabpanel" aria-labeled-by="device_tab">
{% render_field form.interface %}
</div>
<div class="tab-pane {% if form.initial.vminterface %}active{% endif %}" id="vm" role="tabpanel" aria-labeled-by="vm_tab">
{% render_field form.vminterface %}
</div>
<div class="tab-pane {% if form.initial.fhrpgroup %}active{% endif %}" id="fhrpgroup" role="tabpanel" aria-labeled-by="fhrpgroup_tab">
{% render_field form.fhrpgroup %}
</div>
{% render_field form.primary_for_parent %}
</div>
</div>
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "NAT IP (Inside" %})</h5>
</div>
<div class="row">
{% render_field form.nat_inside %}
</div>
</div>
<div class="field-group my-5">
{% render_field form.comments %}
</div>
{% if form.custom_fields %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Custom Fields" %}</h5>
</div>
{% render_custom_fields form %}
</div>
{% endif %}
{% endblock %}

View File

@ -1,79 +0,0 @@
{% extends 'generic/object_edit.html' %}
{% load form_helpers %}
{% load i18n %}
{% block form %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Service" %}</h5>
</div>
{# Device/VM selection #}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.virtual_machine %}active{% endif %}">
{% trans "Device" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="vm_tab" data-bs-toggle="tab" aria-controls="vm" data-bs-target="#vm" class="nav-link {% if form.initial.virtual_machine %}active{% endif %}">
{% trans "Virtual Machine" %}
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content p-0 border-0">
<div class="tab-pane {% if not form.initial.virtual_machine %}active{% endif %}" id="device" role="tabpanel" aria-labeled-by="device_tab">
{% render_field form.device %}
</div>
<div class="tab-pane {% if form.initial.virtual_machine %}active{% endif %}" id="vm" role="tabpanel" aria-labeled-by="vm_tab">
{% render_field form.virtual_machine %}
</div>
</div>
{# Template or custom #}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="template_tab" data-bs-toggle="tab" data-bs-target="#template" class="nav-link active">
{% trans "From Template" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="custom_tab" data-bs-toggle="tab" data-bs-target="#custom" class="nav-link">
{% trans "Custom" %}
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content p-0 border-0">
<div class="tab-pane active" id="template" role="tabpanel" aria-labeled-by="template_tab">
{% render_field form.service_template %}
</div>
<div class="tab-pane" id="custom" role="tabpanel" aria-labeled-by="custom_tab">
{% render_field form.name %}
{% render_field form.protocol %}
{% render_field form.ports %}
</div>
</div>
{% render_field form.ipaddresses %}
{% render_field form.description %}
{% render_field form.tags %}
</div>
<div class="field-group my-5">
{% render_field form.comments %}
</div>
{% if form.custom_fields %}
<div class="row">
<h5 class="col-9 offset-3">{% trans "Custom Fields" %}</h5>
</div>
{% render_custom_fields form %}
{% endif %}
{% endblock %}

View File

@ -1,66 +0,0 @@
{% extends 'generic/object_edit.html' %}
{% load form_helpers %}
{% load i18n %}
{% block form %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Service" %}</h5>
</div>
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="device_tab" data-bs-toggle="tab" aria-controls="device" data-bs-target="#device" class="nav-link {% if not form.initial.virtual_machine %}active{% endif %}">
{% trans "Device" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="vm_tab" data-bs-toggle="tab" aria-controls="vm" data-bs-target="#vm" class="nav-link {% if form.initial.virtual_machine %}active{% endif %}">
{% trans "Virtual Machine" %}
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content p-0 border-0">
<div class="tab-pane {% if not form.initial.virtual_machine %}active{% endif %}" id="device" role="tabpanel" aria-labeled-by="device_tab">
{% render_field form.device %}
</div>
<div class="tab-pane {% if form.initial.virtual_machine %}active{% endif %}" id="vm" role="tabpanel" aria-labeled-by="vm_tab">
{% render_field form.virtual_machine %}
</div>
</div>
{% render_field form.name %}
<div class="row">
<label class="col-sm-3 col-form-label text-lg-end">{% trans "Port(s)" %}</label>
<div class="col-3">
{{ form.protocol }}
</div>
<div class="col-6">
{{ form.ports }}
</div>
</div>
<div class="row mb-3">
<div class="col-3"></div>
<div class="col-9">
<span class="form-text">{{ form.ports.help_text }}</span>
</div>
</div>
{% render_field form.ipaddresses %}
{% render_field form.description %}
{% render_field form.tags %}
</div>
<div class="field-group my-5">
{% render_field form.comments %}
</div>
{% if form.custom_fields %}
<div class="row">
<h5 class="col-9 offset-3">{% trans "Custom Fields" %}</h5>
</div>
{% render_custom_fields form %}
{% endif %}
{% endblock %}

View File

@ -1,56 +0,0 @@
{% extends 'generic/object_edit.html' %}
{% load helpers %}
{% load form_helpers %}
{% load i18n %}
{% block form %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "L2VPN Termination" %}</h5>
</div>
{% render_field form.l2vpn %}
<div class="row">
<div class="col-9 offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="vlan_tab" data-bs-toggle="tab" aria-controls="vlan" data-bs-target="#vlan" class="nav-link {% if not form.initial.interface and not form.initial.vminterface %}active{% endif %}">
{% trans "VLAN" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="interface_tab" data-bs-toggle="tab" aria-controls="interface" data-bs-target="#interface" class="nav-link {% if form.initial.interface %}active{% endif %}">
{% trans "Device" %}
</button>
</li>
<li role="presentation" class="nav-item">
<button role="tab" type="button" id="vminterface_tab" data-bs-toggle="tab" aria-controls="vminterface" data-bs-target="#vminterface" class="nav-link {% if form.initial.vminterface %}active{% endif %}">
{% trans "Virtual Machine" %}
</button>
</li>
</ul>
</div>
</div>
<div class="row mb-3">
<div class="tab-content p-0 border-0">
<div class="tab-pane {% if not form.initial.interface and not form.initial.vminterface %}active{% endif %}" id="vlan" role="tabpanel" aria-labeled-by="vlan_tab">
{% render_field form.vlan %}
</div>
<div class="tab-pane {% if form.initial.interface %}active{% endif %}" id="interface" role="tabpanel" aria-labeled-by="interface_tab">
{% render_field form.interface %}
</div>
<div class="tab-pane {% if form.initial.vminterface %}active{% endif %}" id="vminterface" role="tabpanel" aria-labeled-by="vminterface_tab">
{% render_field form.vminterface %}
</div>
{% render_field form.tags %}
</div>
</div>
</div>
{% if form.custom_fields %}
<div class="field-group my-5">
<div class="row">
<h5 class="col-9 offset-3">{% trans "Custom Fields" %}</h5>
</div>
{% render_custom_fields form %}
</div>
{% endif %}
{% endblock %}

View File

@ -26,7 +26,7 @@
{% elif layout == 'inline' %}
{# Multiple form fields on the same line #}
<div class="row mb-3">
<label class="col col-form-label text-lg-end">{{ title|default:'' }}</label>
<label class="col col-3 col-form-label text-lg-end">{{ title|default:'' }}</label>
{% for field in items %}
<div class="col mb-1">
{{ field }}
@ -37,7 +37,8 @@
{% elif layout == 'tabs' %}
{# Tabbed groups of fields #}
<div class="row offset-sm-3">
<div class="row">
<div class="col offset-3">
<ul class="nav nav-pills mb-1" role="tablist">
{% for tab in items %}
<li role="presentation" class="nav-item">
@ -48,6 +49,7 @@
{% endfor %}
</ul>
</div>
</div>
<div class="tab-content p-0 border-0">
{% for tab in items %}
<div class="tab-pane {% if tab.active %}active{% endif %}" id="{{ tab.id }}" role="tabpanel" aria-labeled-by="{{ tab.id }}_tab">

View File

@ -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')

View File

@ -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')