diff --git a/netbox/dcim/forms/connections.py b/netbox/dcim/forms/connections.py index 13ab0ae09..aae33e621 100644 --- a/netbox/dcim/forms/connections.py +++ b/netbox/dcim/forms/connections.py @@ -21,15 +21,29 @@ class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm): """ Base form for connecting a Cable to a Device component """ + # Termination A + termination_a_id = DynamicModelChoiceField( + queryset=Interface.objects.all(), + label='Name', + disabled_indicator='_occupied' + ) + + # Termination B termination_b_region = DynamicModelChoiceField( queryset=Region.objects.all(), label='Region', - required=False + required=False, + initial_params={ + 'sites': '$termination_b_site' + } ) termination_b_sitegroup = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), label='Site group', - required=False + required=False, + initial_params={ + 'sites': '$termination_b_site' + } ) termination_b_site = DynamicModelChoiceField( queryset=Site.objects.all(), @@ -73,9 +87,9 @@ class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm): class Meta: model = Cable fields = [ - 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', 'termination_b_rack', - 'termination_b_device', 'termination_b_id', 'type', 'status', 'tenant_group', 'tenant', 'label', 'color', - 'length', 'length_unit', 'tags', + 'termination_a_id', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', + 'termination_b_rack', 'termination_b_device', 'termination_b_id', 'type', 'status', 'tenant_group', + 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', ] widgets = { 'status': StaticSelect, @@ -83,6 +97,10 @@ class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm): 'length_unit': StaticSelect, } + def clean_termination_a_id(self): + # Return the PK rather than the object + return getattr(self.cleaned_data['termination_a_id'], 'pk', None) + def clean_termination_b_id(self): # Return the PK rather than the object return getattr(self.cleaned_data['termination_b_id'], 'pk', None) @@ -167,6 +185,14 @@ class ConnectCableToRearPortForm(ConnectCableToDeviceForm): class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm): + # Termination A + termination_a_id = DynamicModelChoiceField( + queryset=Interface.objects.all(), + label='Side', + disabled_indicator='_occupied' + ) + + # Termination B termination_b_provider = DynamicModelChoiceField( queryset=Provider.objects.all(), label='Provider', @@ -175,12 +201,18 @@ class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm): termination_b_region = DynamicModelChoiceField( queryset=Region.objects.all(), label='Region', - required=False + required=False, + initial_params={ + 'sites': '$termination_b_site' + } ) termination_b_sitegroup = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), label='Site group', - required=False + required=False, + initial_params={ + 'sites': '$termination_b_site' + } ) termination_b_site = DynamicModelChoiceField( queryset=Site.objects.all(), @@ -210,26 +242,44 @@ class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm): class Meta(ConnectCableToDeviceForm.Meta): fields = [ - 'termination_b_provider', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', - 'termination_b_circuit', 'termination_b_id', 'type', 'status', 'tenant_group', 'tenant', 'label', 'color', - 'length', 'length_unit', 'tags', + 'termination_a_id', 'termination_b_provider', 'termination_b_region', 'termination_b_sitegroup', + 'termination_b_site', 'termination_b_circuit', 'termination_b_id', 'type', 'status', 'tenant_group', + 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', ] + def clean_termination_a_id(self): + # Return the PK rather than the object + return getattr(self.cleaned_data['termination_a_id'], 'pk', None) + def clean_termination_b_id(self): # Return the PK rather than the object return getattr(self.cleaned_data['termination_b_id'], 'pk', None) class ConnectCableToPowerFeedForm(TenancyForm, NetBoxModelForm): + # Termination A + termination_a_id = DynamicModelChoiceField( + queryset=Interface.objects.all(), + label='Name', + disabled_indicator='_occupied' + ) + + # Termination B termination_b_region = DynamicModelChoiceField( queryset=Region.objects.all(), label='Region', - required=False + required=False, + initial_params={ + 'sites': '$termination_b_site' + } ) termination_b_sitegroup = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), label='Site group', - required=False + required=False, + initial_params={ + 'sites': '$termination_b_site' + } ) termination_b_site = DynamicModelChoiceField( queryset=Site.objects.all(), @@ -268,11 +318,15 @@ class ConnectCableToPowerFeedForm(TenancyForm, NetBoxModelForm): class Meta(ConnectCableToDeviceForm.Meta): fields = [ - 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', 'termination_b_location', - 'termination_b_powerpanel', 'termination_b_id', 'type', 'status', 'tenant_group', 'tenant', 'label', - 'color', 'length', 'length_unit', 'tags', + 'termination_a_id', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', + 'termination_b_location', 'termination_b_powerpanel', 'termination_b_id', 'type', 'status', 'tenant_group', + 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', ] + def clean_termination_a_id(self): + # Return the PK rather than the object + return getattr(self.cleaned_data['termination_a_id'], 'pk', None) + def clean_termination_b_id(self): # Return the PK rather than the object return getattr(self.cleaned_data['termination_b_id'], 'pk', None) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index b18b6d4b3..204862548 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -12,7 +12,7 @@ from django.utils.html import escape from django.utils.safestring import mark_safe from django.views.generic import View -from circuits.models import Circuit +from circuits.models import Circuit, CircuitTermination from extras.views import ObjectConfigContextView from ipam.models import ASN, IPAddress, Prefix, Service, VLAN, VLANGroup from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable @@ -2850,10 +2850,6 @@ class CableCreateView(generic.ObjectEditView): # Set initial site and rack based on side A termination (if not already set) termination_a_site = getattr(obj.termination_a.parent_object, 'site', None) - if termination_a_site and 'termination_b_region' not in initial_data: - initial_data['termination_b_region'] = termination_a_site.region - if termination_a_site and 'termination_b_site_group' not in initial_data: - initial_data['termination_b_site_group'] = termination_a_site.group if 'termination_b_site' not in initial_data: initial_data['termination_b_site'] = termination_a_site if 'termination_b_rack' not in initial_data: @@ -2861,6 +2857,9 @@ class CableCreateView(generic.ObjectEditView): form = self.form(instance=obj, initial=initial_data) + # Set the queryset of termination A + form.fields['termination_a_id'].queryset = kwargs['termination_a_type'].objects.all() + return render(request, self.template_name, { 'obj': obj, 'obj_type': Cable._meta.verbose_name, diff --git a/netbox/templates/dcim/cable_connect.html b/netbox/templates/dcim/cable_connect.html index 1d50040c7..4edb55bcc 100644 --- a/netbox/templates/dcim/cable_connect.html +++ b/netbox/templates/dcim/cable_connect.html @@ -71,39 +71,28 @@ -
- -
- -
-
{% else %} {# Circuit termination #}
- +
- +
- +
-
- -
- -
-
{% endif %} + {% render_field form.termination_a_id %}