Update cable connection forms

This commit is contained in:
jeremystretch 2022-04-29 15:16:35 -04:00
parent 1f4ad444ae
commit 5d37f9f975
18 changed files with 185 additions and 212 deletions

View File

@ -962,14 +962,8 @@ class InventoryItemRoleSerializer(NetBoxModelSerializer):
class CableSerializer(NetBoxModelSerializer): class CableSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail') url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
termination_a_type = ContentTypeField( # termination_a = serializers.SerializerMethodField(read_only=True)
queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS) # termination_b = serializers.SerializerMethodField(read_only=True)
)
termination_b_type = ContentTypeField(
queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)
)
termination_a = serializers.SerializerMethodField(read_only=True)
termination_b = serializers.SerializerMethodField(read_only=True)
status = ChoiceField(choices=LinkStatusChoices, required=False) status = ChoiceField(choices=LinkStatusChoices, required=False)
tenant = NestedTenantSerializer(required=False, allow_null=True) tenant = NestedTenantSerializer(required=False, allow_null=True)
length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False) length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False)
@ -977,9 +971,8 @@ class CableSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = Cable model = Cable
fields = [ fields = [
'id', 'url', 'display', 'termination_a_type', 'termination_a_ids', 'termination_a', 'termination_b_type', 'id', 'url', 'display', 'type', 'status', 'tenant', 'label', 'color',
'termination_b_ids', 'termination_b', 'type', 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'length', 'length_unit', 'tags', 'custom_fields', 'created', 'last_updated',
'tags', 'custom_fields', 'created', 'last_updated',
] ]
def _get_termination(self, obj, side): def _get_termination(self, obj, side):

View File

@ -17,18 +17,47 @@ __all__ = (
) )
class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm): class BaseCableConnectionForm(TenancyForm, NetBoxModelForm):
""" a_terminations = DynamicModelMultipleChoiceField(
Base form for connecting a Cable to a Device component queryset=Interface.objects.all(),
""" label='Name',
# Termination A disabled_indicator='_occupied'
termination_a_ids = DynamicModelMultipleChoiceField( )
b_terminations = DynamicModelMultipleChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied' disabled_indicator='_occupied'
) )
# Termination B def save(self, commit=True):
instance = super().save(commit=commit)
# Create CableTermination instances
terminations = []
terminations.extend([
CableTermination(cable=instance, cable_end='A', termination=termination)
for termination in self.cleaned_data['a_terminations']
])
terminations.extend([
CableTermination(cable=instance, cable_end='B', termination=termination)
for termination in self.cleaned_data['b_terminations']
])
if commit:
CableTermination.objects.bulk_create(terminations)
else:
instance.terminations = [
*self.cleaned_data['a_terminations'],
*self.cleaned_data['b_terminations'],
]
return instance
class ConnectCableToDeviceForm(BaseCableConnectionForm):
"""
Base form for connecting a Cable to a Device component
"""
termination_b_region = DynamicModelChoiceField( termination_b_region = DynamicModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
label='Region', label='Region',
@ -83,17 +112,12 @@ class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm):
'rack_id': '$termination_b_rack', 'rack_id': '$termination_b_rack',
} }
) )
termination_b_ids = DynamicModelMultipleChoiceField(
queryset=Interface.objects.all(),
label='Name',
disabled_indicator='_occupied'
)
class Meta: class Meta:
model = Cable model = Cable
fields = [ fields = [
'termination_a_ids', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', 'a_terminations', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site',
'termination_b_rack', 'termination_b_device', 'termination_b_ids', 'type', 'status', 'tenant_group', 'termination_b_rack', 'termination_b_device', 'b_terminations', 'type', 'status', 'tenant_group',
'tenant', 'label', 'color', 'length', 'length_unit', 'tags', 'tenant', 'label', 'color', 'length', 'length_unit', 'tags',
] ]
widgets = { widgets = {
@ -102,17 +126,9 @@ class ConnectCableToDeviceForm(TenancyForm, NetBoxModelForm):
'length_unit': StaticSelect, 'length_unit': StaticSelect,
} }
def clean_termination_a_ids(self):
# Return the PK rather than the object
return [getattr(obj, 'pk') for obj in self.cleaned_data['termination_a_ids']]
def clean_termination_b_ids(self):
# Return the PK rather than the object
return [getattr(obj, 'pk') for obj in self.cleaned_data['termination_b_ids']]
class ConnectCableToConsolePortForm(ConnectCableToDeviceForm): class ConnectCableToConsolePortForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=ConsolePort.objects.all(), queryset=ConsolePort.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -123,7 +139,7 @@ class ConnectCableToConsolePortForm(ConnectCableToDeviceForm):
class ConnectCableToConsoleServerPortForm(ConnectCableToDeviceForm): class ConnectCableToConsoleServerPortForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=ConsoleServerPort.objects.all(), queryset=ConsoleServerPort.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -134,7 +150,7 @@ class ConnectCableToConsoleServerPortForm(ConnectCableToDeviceForm):
class ConnectCableToPowerPortForm(ConnectCableToDeviceForm): class ConnectCableToPowerPortForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=PowerPort.objects.all(), queryset=PowerPort.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -145,7 +161,7 @@ class ConnectCableToPowerPortForm(ConnectCableToDeviceForm):
class ConnectCableToPowerOutletForm(ConnectCableToDeviceForm): class ConnectCableToPowerOutletForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=PowerOutlet.objects.all(), queryset=PowerOutlet.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -156,7 +172,7 @@ class ConnectCableToPowerOutletForm(ConnectCableToDeviceForm):
class ConnectCableToInterfaceForm(ConnectCableToDeviceForm): class ConnectCableToInterfaceForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -168,7 +184,7 @@ class ConnectCableToInterfaceForm(ConnectCableToDeviceForm):
class ConnectCableToFrontPortForm(ConnectCableToDeviceForm): class ConnectCableToFrontPortForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=FrontPort.objects.all(), queryset=FrontPort.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -179,7 +195,7 @@ class ConnectCableToFrontPortForm(ConnectCableToDeviceForm):
class ConnectCableToRearPortForm(ConnectCableToDeviceForm): class ConnectCableToRearPortForm(ConnectCableToDeviceForm):
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=RearPort.objects.all(), queryset=RearPort.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -189,15 +205,7 @@ class ConnectCableToRearPortForm(ConnectCableToDeviceForm):
) )
class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm): class ConnectCableToCircuitTerminationForm(BaseCableConnectionForm):
# Termination A
termination_a_ids = DynamicModelMultipleChoiceField(
queryset=Interface.objects.all(),
label='Side',
disabled_indicator='_occupied'
)
# Termination B
termination_b_provider = DynamicModelChoiceField( termination_b_provider = DynamicModelChoiceField(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label='Provider', label='Provider',
@ -236,7 +244,7 @@ class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm):
'site_id': '$termination_b_site', 'site_id': '$termination_b_site',
} }
) )
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=CircuitTermination.objects.all(), queryset=CircuitTermination.objects.all(),
label='Side', label='Side',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -247,29 +255,13 @@ class ConnectCableToCircuitTerminationForm(TenancyForm, NetBoxModelForm):
class Meta(ConnectCableToDeviceForm.Meta): class Meta(ConnectCableToDeviceForm.Meta):
fields = [ fields = [
'termination_a_ids', 'termination_b_provider', 'termination_b_region', 'termination_b_sitegroup', 'a_terminations', 'termination_b_provider', 'termination_b_region', 'termination_b_sitegroup',
'termination_b_site', 'termination_b_circuit', 'termination_b_ids', 'type', 'status', 'tenant_group', 'termination_b_site', 'termination_b_circuit', 'b_terminations', 'type', 'status', 'tenant_group',
'tenant', 'label', 'color', 'length', 'length_unit', 'tags', '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): class ConnectCableToPowerFeedForm(BaseCableConnectionForm):
# 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_ids = DynamicModelMultipleChoiceField(
queryset=Interface.objects.all(),
label='Name',
disabled_indicator='_occupied'
)
# Termination B
termination_b_region = DynamicModelChoiceField( termination_b_region = DynamicModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
label='Region', label='Region',
@ -312,7 +304,7 @@ class ConnectCableToPowerFeedForm(TenancyForm, NetBoxModelForm):
'location_id': '$termination_b_location', 'location_id': '$termination_b_location',
} }
) )
termination_b_ids = DynamicModelMultipleChoiceField( b_terminations = DynamicModelMultipleChoiceField(
queryset=PowerFeed.objects.all(), queryset=PowerFeed.objects.all(),
label='Name', label='Name',
disabled_indicator='_occupied', disabled_indicator='_occupied',
@ -323,15 +315,7 @@ class ConnectCableToPowerFeedForm(TenancyForm, NetBoxModelForm):
class Meta(ConnectCableToDeviceForm.Meta): class Meta(ConnectCableToDeviceForm.Meta):
fields = [ fields = [
'termination_a_ids', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', 'a_terminations', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site',
'termination_b_location', 'termination_b_powerpanel', 'termination_b_ids', 'type', 'status', 'tenant_group', 'termination_b_location', 'termination_b_powerpanel', 'b_terminations', 'type', 'status', 'tenant_group',
'tenant', 'label', 'color', 'length', 'length_unit', 'tags', '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)

View File

@ -168,6 +168,16 @@ class Cable(NetBoxModel):
def get_status_color(self): def get_status_color(self):
return LinkStatusChoices.colors.get(self.status) return LinkStatusChoices.colors.get(self.status)
def get_a_terminations(self):
return [
term.termination for term in CableTermination.objects.filter(cable=self, cable_end='A')
]
def get_b_terminations(self):
return [
term.termination for term in CableTermination.objects.filter(cable=self, cable_end='B')
]
class CableTermination(models.Model): class CableTermination(models.Model):
""" """

View File

@ -81,34 +81,27 @@ def update_connected_endpoints(instance, created, raw=False, **kwargs):
# TODO: Update link peer fields # TODO: Update link peer fields
# Cache the Cable on its termination points # Cache the Cable on its termination points
for term in instance.termination_a: for term in instance.terminations.all():
if term.cable != instance: if term.termination.cable != instance:
logger.debug(f"Updating termination A for cable {instance}: {term}") logger.debug(f"Updating termination A for cable {instance}: {term}")
term.cable = instance term.termination.cable = instance
# term._link_peer = instance.termination_b
term.save()
for term in instance.termination_b:
if term.cable != instance:
logger.debug(f"Updating termination B for cable {instance}")
term.cable = instance
# term._link_peer = instance.termination_a
term.save() term.save()
# Create/update cable paths # # Create/update cable paths
if created: # if created:
for termination in [*instance.termination_a, *instance.termination_b]: # for term in instance.terminations.all():
if isinstance(termination, PathEndpoint): # if isinstance(term.termination, PathEndpoint):
create_cablepath(termination) # create_cablepath(term.termination)
else: # else:
rebuild_paths(termination) # rebuild_paths(term.termination)
elif instance.status != instance._orig_status: # elif instance.status != instance._orig_status:
# We currently don't support modifying either termination of an existing Cable. (This # # We currently don't support modifying either termination of an existing Cable. (This
# may change in the future.) However, we do need to capture status changes and update # # may change in the future.) However, we do need to capture status changes and update
# any CablePaths accordingly. # # any CablePaths accordingly.
if instance.status != LinkStatusChoices.STATUS_CONNECTED: # if instance.status != LinkStatusChoices.STATUS_CONNECTED:
CablePath.objects.filter(path__contains=instance).update(is_active=False) # CablePath.objects.filter(path__contains=instance).update(is_active=False)
else: # else:
rebuild_paths(instance) # rebuild_paths(instance)
@receiver(post_delete, sender=Cable) @receiver(post_delete, sender=Cable)

View File

@ -139,9 +139,9 @@ CONSOLEPORT_BUTTONS = """
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{% url 'dcim:consoleport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.consoleserverport&return_url={% url 'dcim:device_consoleports' pk=object.pk %}">Console Server Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:consoleport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.consoleserverport&return_url={% url 'dcim:device_consoleports' pk=object.pk %}">Console Server Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:consoleport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_consoleports' pk=object.pk %}">Front Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:consoleport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_consoleports' pk=object.pk %}">Front Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:consoleport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_consoleports' pk=object.pk %}">Rear Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:consoleport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_consoleports' pk=object.pk %}">Rear Port</a></li>
</ul> </ul>
</span> </span>
{% else %} {% else %}
@ -171,9 +171,9 @@ CONSOLESERVERPORT_BUTTONS = """
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{% url 'dcim:consoleserverport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.consoleport&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}">Console Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:consoleserverport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.consoleport&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}">Console Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:consoleserverport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}">Front Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:consoleserverport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}">Front Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:consoleserverport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}">Rear Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:consoleserverport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}">Rear Port</a></li>
</ul> </ul>
</span> </span>
{% else %} {% else %}
@ -203,8 +203,8 @@ POWERPORT_BUTTONS = """
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{% url 'dcim:powerport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.poweroutlet&return_url={% url 'dcim:device_powerports' pk=object.pk %}">Power Outlet</a></li> <li><a class="dropdown-item" href="{% url 'dcim:powerport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.poweroutlet&return_url={% url 'dcim:device_powerports' pk=object.pk %}">Power Outlet</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:powerport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.powerfeed&return_url={% url 'dcim:device_powerports' pk=object.pk %}">Power Feed</a></li> <li><a class="dropdown-item" href="{% url 'dcim:powerport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.powerfeed&return_url={% url 'dcim:device_powerports' pk=object.pk %}">Power Feed</a></li>
</ul> </ul>
</span> </span>
{% else %} {% else %}
@ -230,7 +230,7 @@ POWEROUTLET_BUTTONS = """
<a href="#" class="btn btn-outline-dark btn-sm disabled"><i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i></a> <a href="#" class="btn btn-outline-dark btn-sm disabled"><i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i></a>
<a href="#" class="btn btn-outline-dark btn-sm disabled"><i class="mdi mdi-lan-connect" aria-hidden="true"></i></a> <a href="#" class="btn btn-outline-dark btn-sm disabled"><i class="mdi mdi-lan-connect" aria-hidden="true"></i></a>
{% if not record.mark_connected %} {% if not record.mark_connected %}
<a href="{% url 'dcim:poweroutlet_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.powerport&return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" title="Connect" class="btn btn-success btn-sm"> <a href="{% url 'dcim:poweroutlet_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.powerport&return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" title="Connect" class="btn btn-success btn-sm">
<i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> <i class="mdi mdi-ethernet-cable" aria-hidden="true"></i>
</a> </a>
{% else %} {% else %}
@ -280,10 +280,10 @@ INTERFACE_BUTTONS = """
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.interface&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Interface</a></li> <li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.interface&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Interface</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Front Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Front Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Rear Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Rear Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=circuits.circuittermination&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Circuit Termination</a></li> <li><a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ record.pk }}&termination_b_type=circuits.circuittermination&return_url={% url 'dcim:device_interfaces' pk=object.pk %}">Circuit Termination</a></li>
</ul> </ul>
</span> </span>
{% else %} {% else %}
@ -319,12 +319,12 @@ FRONTPORT_BUTTONS = """
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.interface&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Interface</a></li> <li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.interface&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Interface</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.consoleserverport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Console Server Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.consoleserverport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Console Server Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.consoleport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Console Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.consoleport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Console Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Front Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Front Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Rear Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Rear Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=circuits.circuittermination&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Circuit Termination</a></li> <li><a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=circuits.circuittermination&return_url={% url 'dcim:device_frontports' pk=object.pk %}">Circuit Termination</a></li>
</ul> </ul>
</span> </span>
{% else %} {% else %}
@ -356,12 +356,12 @@ REARPORT_BUTTONS = """
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span>
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.interface&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Interface</a></li> <li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.interface&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Interface</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.consoleserverport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Console Server Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.consoleserverport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Console Server Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.consoleport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Console Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.consoleport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Console Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Front Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.frontport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Front Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Rear Port</a></li> <li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=dcim.rearport&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Rear Port</a></li>
<li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ record.pk }}&termination_b_type=circuits.circuitterminations&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Circuit Termination</a></li> <li><a class="dropdown-item" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ record.pk }}&termination_b_type=circuits.circuitterminations&return_url={% url 'dcim:device_rearports' pk=object.pk %}">Circuit Termination</a></li>
</ul> </ul>
</span> </span>
{% else %} {% else %}

View File

@ -2829,24 +2829,14 @@ class CableCreateView(generic.ObjectEditView):
# Always return a new instance # Always return a new instance
return self.queryset.model() return self.queryset.model()
def alter_object(self, obj, request, url_args, url_kwargs):
termination_a_type = url_kwargs.get('termination_a_type')
termination_a_ids = request.GET.get('termination_a_ids', [])
app_label, model = request.GET.get('termination_b_type').split('.')
self.termination_b_type = ContentType.objects.get(app_label=app_label, model=model)
# Initialize Cable termination attributes
obj.termination_a_type = ContentType.objects.get_for_model(termination_a_type)
obj.termination_a_ids = termination_a_type.objects.filter(pk__in=termination_a_ids)
obj.termination_b_type = self.termination_b_type
return obj
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
obj = self.get_object(**kwargs) obj = self.get_object(**kwargs)
obj = self.alter_object(obj, request, args, kwargs) obj = self.alter_object(obj, request, args, kwargs)
initial_data = request.GET initial_data = request.GET
app_label, model = request.GET.get('termination_b_type').split('.')
termination_b_type = ContentType.objects.get(app_label=app_label, model=model)
# TODO # TODO
# # Set initial site and rack based on side A termination (if not already set) # # 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) # termination_a_site = getattr(obj.termination_a.parent_object, 'site', None)
@ -2857,12 +2847,17 @@ class CableCreateView(generic.ObjectEditView):
form = self.form(instance=obj, initial=initial_data) form = self.form(instance=obj, initial=initial_data)
# Set the queryset of termination A # Set the queryset of termination A
form.fields['termination_a_ids'].queryset = kwargs['termination_a_type'].objects.all() form.fields['a_terminations'].queryset = kwargs['termination_a_type'].objects.all()
# TODO Find a better way to infer the near-end parent object
termination_a = kwargs['termination_a_type'].objects.filter(pk__in=initial_data['a_terminations']).first()
return render(request, self.template_name, { return render(request, self.template_name, {
'obj': obj, 'obj': obj,
'obj_type': Cable._meta.verbose_name, 'obj_type': Cable._meta.verbose_name,
'termination_b_type': self.termination_b_type.name, 'termination_a_type': kwargs['termination_a_type']._meta.model_name,
'termination_a': termination_a,
'termination_b_type': termination_b_type.name,
'form': form, 'form': form,
'return_url': self.get_return_url(request, obj), 'return_url': self.get_return_url(request, obj),
}) })

View File

@ -70,10 +70,10 @@
<span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> Connect <span class="mdi mdi-ethernet-cable" aria-hidden="true"></span> Connect
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?termination_a_id={{ termination.pk }}&termination_b_type=dcim.interface&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Interface</a></li> <li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?a_terminations={{ termination.pk }}&termination_b_type=dcim.interface&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Interface</a></li>
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?termination_a_id={{ termination.pk }}&termination_b_type=dcim.frontport&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Front Port</a></li> <li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?a_terminations={{ termination.pk }}&termination_b_type=dcim.frontport&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Front Port</a></li>
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?termination_a_id={{ termination.pk }}&termination_b_type=dcim.rearport&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Rear Port</a></li> <li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?a_terminations={{ termination.pk }}&termination_b_type=dcim.rearport&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Rear Port</a></li>
<li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?termination_a_id={{ termination.pk }}&termination_b_type=circuits.circuittermination&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Circuit Termination</a></li> <li><a class="dropdown-item" href="{% url 'circuits:circuittermination_connect' %}?a_terminations={{ termination.pk }}&termination_b_type=circuits.circuittermination&termination_b_site={{ termination.site.pk }}&return_url={{ object.get_absolute_url }}">Circuit Termination</a></li>
</ul> </ul>
</div> </div>
{% endif %} {% endif %}

View File

@ -63,13 +63,13 @@
<div class="card"> <div class="card">
<h5 class="card-header">Termination A</h5> <h5 class="card-header">Termination A</h5>
<div class="card-body"> <div class="card-body">
{% include 'dcim/inc/cable_termination.html' with termination=object.termination_a %} {% include 'dcim/inc/cable_termination.html' with terminations=object.get_a_terminations %}
</div> </div>
</div> </div>
<div class="card"> <div class="card">
<h5 class="card-header">Termination B</h5> <h5 class="card-header">Termination B</h5>
<div class="card-body"> <div class="card-body">
{% include 'dcim/inc/cable_termination.html' with termination=object.termination_b %} {% include 'dcim/inc/cable_termination.html' with terminations=object.get_b_terminations %}
</div> </div>
</div> </div>
{% plugin_right_page object %} {% plugin_right_page object %}

View File

@ -15,9 +15,8 @@
{% block content-wrapper %} {% block content-wrapper %}
<div class="tab-content"> <div class="tab-content">
{% with termination_a=form.instance.termination_a.0 %} {% render_errors form %}
{% render_errors form %} <form method="post">
<form method="post">
{% csrf_token %} {% csrf_token %}
{% for field in form.hidden_fields %} {% for field in form.hidden_fields %}
{{ field }} {{ field }}
@ -27,7 +26,27 @@
<div class="card h-100"> <div class="card h-100">
<h5 class="card-header offset-sm-3">A Side</h5> <h5 class="card-header offset-sm-3">A Side</h5>
<div class="card-body"> <div class="card-body">
{% if termination_a.device %} {% if termination_a_type == 'circuit' %}
{# Circuit termination #}
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Site</label>
<div class="col">
<input class="form-control" value="{{ termination_a.site }}" disabled />
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Provider</label>
<div class="col">
<input class="form-control" value="{{ termination_a.circuit.provider }}" disabled />
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Circuit</label>
<div class="col">
<input class="form-control" value="{{ termination_a.circuit.cid }}" disabled />
</div>
</div>
{% else %}
{# Device component #} {# Device component #}
<div class="row mb-3"> <div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Region</label> <label class="col-sm-3 col-form-label text-lg-end">Region</label>
@ -71,28 +90,8 @@
<input class="form-control" value="{{ termination_a|meta:"verbose_name"|capfirst }}" disabled /> <input class="form-control" value="{{ termination_a|meta:"verbose_name"|capfirst }}" disabled />
</div> </div>
</div> </div>
{% else %}
{# Circuit termination #}
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Site</label>
<div class="col">
<input class="form-control" value="{{ termination_a.site }}" disabled />
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Provider</label>
<div class="col">
<input class="form-control" value="{{ termination_a.circuit.provider }}" disabled />
</div>
</div>
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Circuit</label>
<div class="col">
<input class="form-control" value="{{ termination_a.circuit.cid }}" disabled />
</div>
</div>
{% endif %} {% endif %}
{% render_field form.termination_a_ids %} {% render_field form.a_terminations %}
</div> </div>
</div> </div>
</div> </div>
@ -148,7 +147,7 @@
<input class="form-control" value="{{ termination_b_type|capfirst }}" disabled /> <input class="form-control" value="{{ termination_b_type|capfirst }}" disabled />
</div> </div>
</div> </div>
{% render_field form.termination_b_ids %} {% render_field form.b_terminations %}
</div> </div>
</div> </div>
</div> </div>
@ -170,6 +169,5 @@
</div> </div>
</div> </div>
</form> </form>
{% endwith %}
</div> </div>
{% endblock %} {% endblock %}

View File

@ -113,7 +113,7 @@
<li> <li>
<a <a
class="dropdown-item" class="dropdown-item"
href="{% url 'dcim:consoleport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.consoleserverport&return_url={{ object.get_absolute_url }}" href="{% url 'dcim:consoleport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.consoleserverport&return_url={{ object.get_absolute_url }}"
> >
Console Server Port Console Server Port
</a> </a>
@ -121,7 +121,7 @@
<li> <li>
<a <a
class="dropdown-item" class="dropdown-item"
href="{% url 'dcim:consoleport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}" href="{% url 'dcim:consoleport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}"
> >
Front Port Front Port
</a> </a>
@ -129,7 +129,7 @@
<li> <li>
<a <a
class="dropdown-item" class="dropdown-item"
href="{% url 'dcim:consoleport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}" href="{% url 'dcim:consoleport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}"
> >
Rear Port Rear Port
</a> </a>

View File

@ -115,7 +115,7 @@
<li> <li>
<a <a
class="dropdown-item" class="dropdown-item"
href="{% url 'dcim:consoleserverport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.consoleport&return_url={{ object.get_absolute_url }}" href="{% url 'dcim:consoleserverport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.consoleport&return_url={{ object.get_absolute_url }}"
> >
Console Port Console Port
</a> </a>
@ -123,7 +123,7 @@
<li> <li>
<a <a
class="dropdown-item" class="dropdown-item"
href="{% url 'dcim:consoleserverport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}" href="{% url 'dcim:consoleserverport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}"
> >
Front Port Front Port
</a> </a>
@ -131,7 +131,7 @@
<li> <li>
<a <a
class="dropdown-item" class="dropdown-item"
href="{% url 'dcim:consoleserverport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}" href="{% url 'dcim:consoleserverport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}"
> >
Rear Port Rear Port
</a> </a>

View File

@ -105,22 +105,22 @@
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.interface&return_url={{ object.get_absolute_url }}">Interface</a> <a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.interface&return_url={{ object.get_absolute_url }}">Interface</a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.consoleserverport&return_url={{ object.get_absolute_url }}">Console Server Port</a> <a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.consoleserverport&return_url={{ object.get_absolute_url }}">Console Server Port</a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.consoleport&return_url={{ object.get_absolute_url }}">Console Port</a> <a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.consoleport&return_url={{ object.get_absolute_url }}">Console Port</a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}">Front Port</a> <a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}">Front Port</a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}">Rear Port</a> <a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}">Rear Port</a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}">Circuit Termination</a> <a class="dropdown-item" href="{% url 'dcim:frontport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}">Circuit Termination</a>
</li> </li>
</ul> </ul>
</div> </div>

View File

@ -1,29 +1,29 @@
{% load helpers %} {% load helpers %}
<table class="table table-hover panel-body attr-table"> <table class="table table-hover panel-body attr-table">
{% if termination.0.device %} {% if terminations.0.device %}
{# Device component #} {# Device component #}
<tr> <tr>
<td>Device</td> <td>Device</td>
<td>{{ termination.0.device|linkify }}</td> <td>{{ terminations.0.device|linkify }}</td>
</tr> </tr>
<tr> <tr>
<td>Site</td> <td>Site</td>
<td>{{ termination.0.device.site|linkify }}</td> <td>{{ terminations.0.device.site|linkify }}</td>
</tr> </tr>
{% if termination.0.device.rack %} {% if terminations.0.device.rack %}
<tr> <tr>
<td>Rack</td> <td>Rack</td>
<td>{{ termination.0.device.rack|linkify }}</td> <td>{{ terminations.0.device.rack|linkify }}</td>
</tr> </tr>
{% endif %} {% endif %}
<tr> <tr>
<td>Type</td> <td>Type</td>
<td>{{ termination.0|meta:"verbose_name"|capfirst }}</td> <td>{{ terminations.0|meta:"verbose_name"|capfirst }}</td>
</tr> </tr>
<tr> <tr>
<td>Component(s)</td> <td>Name(s)</td>
<td> <td>
{% for term in termination %} {% for term in terminations %}
{{ term|linkify }}{% if not forloop.last %},{% endif %} {{ term|linkify }}{% if not forloop.last %},{% endif %}
{% endfor %} {% endfor %}
</td> </td>
@ -32,12 +32,12 @@
{# Circuit termination #} {# Circuit termination #}
<tr> <tr>
<td>Provider</td> <td>Provider</td>
<td>{{ termination.0.circuit.provider|linkify }}</td> <td>{{ terminations.0.circuit.provider|linkify }}</td>
</tr> </tr>
<tr> <tr>
<td>Circuit</td> <td>Circuit</td>
<td> <td>
{% for term in termination %} {% for term in terminations %}
{{ term.circuit|linkify }} ({{ term }}){% if not forloop.last %},{% endif %} {{ term.circuit|linkify }} ({{ term }}){% if not forloop.last %},{% endif %}
{% endfor %} {% endfor %}
</td> </td>

View File

@ -251,22 +251,22 @@
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.interface&return_url={{ object.get_absolute_url }}"> <a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.interface&return_url={{ object.get_absolute_url }}">
Interface Interface
</a> </a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}"> <a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}">
Front Port Front Port
</a> </a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}"> <a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}">
Rear Port Rear Port
</a> </a>
</li> </li>
<li> <li>
<a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}"> <a class="dropdown-item" href="{% url 'dcim:interface_connect' %}?a_terminations={{ object.pk }}&termination_b_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}">
Circuit Termination Circuit Termination
</a> </a>
</li> </li>

View File

@ -158,7 +158,7 @@
{% if not object.mark_connected and not object.cable %} {% if not object.mark_connected and not object.cable %}
<div class="card-footer"> <div class="card-footer">
{% if perms.dcim.add_cable %} {% if perms.dcim.add_cable %}
<a href="{% url 'dcim:powerfeed_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.powerport&return_url={{ object.get_absolute_url }}" <a href="{% url 'dcim:powerfeed_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.powerport&return_url={{ object.get_absolute_url }}"
class="btn btn-primary btn-sm float-end"> class="btn btn-primary btn-sm float-end">
<i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> Connect <i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> Connect
</a> </a>

View File

@ -111,7 +111,7 @@
<div class="text-muted"> <div class="text-muted">
Not Connected Not Connected
{% if perms.dcim.add_cable %} {% if perms.dcim.add_cable %}
<a href="{% url 'dcim:poweroutlet_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.powerport&return_url={{ object.get_absolute_url }}" title="Connect" class="btn btn-primary btn-sm float-end"> <a href="{% url 'dcim:poweroutlet_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.powerport&return_url={{ object.get_absolute_url }}" title="Connect" class="btn btn-primary btn-sm float-end">
<i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> Connect <i class="mdi mdi-ethernet-cable" aria-hidden="true"></i> Connect
</a> </a>
{% endif %} {% endif %}

View File

@ -117,10 +117,10 @@
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li> <li>
<a class="dropdown-link" href="{% url 'dcim:powerport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.poweroutlet&return_url={{ object.get_absolute_url }}">Power Outlet</a> <a class="dropdown-link" href="{% url 'dcim:powerport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.poweroutlet&return_url={{ object.get_absolute_url }}">Power Outlet</a>
</li> </li>
<li> <li>
<a class="dropdown-link" href="{% url 'dcim:powerport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.powerfeed&return_url={{ object.get_absolute_url }}">Power Feed</a> <a class="dropdown-link" href="{% url 'dcim:powerport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.powerfeed&return_url={{ object.get_absolute_url }}">Power Feed</a>
</li> </li>
</ul> </ul>
</span> </span>

View File

@ -101,16 +101,16 @@
</button> </button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li> <li>
<a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.interface&return_url={{ object.get_absolute_url }}">Interface</a> <a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.interface&return_url={{ object.get_absolute_url }}">Interface</a>
</li> </li>
<li> <li>
<a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}">Front Port</a> <a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.frontport&return_url={{ object.get_absolute_url }}">Front Port</a>
</li> </li>
<li> <li>
<a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}">Rear Port</a> <a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=dcim.rearport&return_url={{ object.get_absolute_url }}">Rear Port</a>
</li> </li>
<li> <li>
<a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?termination_a_id={{ object.pk }}&termination_b_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}">Circuit Termination</a> <a class="dropdown-link" href="{% url 'dcim:rearport_connect' %}?a_terminations={{ object.pk }}&termination_b_type=circuits.circuittermination&return_url={{ object.get_absolute_url }}">Circuit Termination</a>
</li> </li>
</ul> </ul>
</span> </span>