diff --git a/netbox/circuits/urls.py b/netbox/circuits/urls.py index 894be27f3..323f588eb 100644 --- a/netbox/circuits/urls.py +++ b/netbox/circuits/urls.py @@ -1,6 +1,6 @@ from django.urls import path -from dcim.views import CableCreateView, PathTraceView +from dcim.views import CableEditView, PathTraceView from netbox.views.generic import ObjectChangeLogView, ObjectJournalView from . import views from .models import * @@ -61,6 +61,6 @@ urlpatterns = [ path('circuit-terminations//edit/', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'), path('circuit-terminations//delete/', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'), path('circuit-terminations//trace/', PathTraceView.as_view(), name='circuittermination_trace', kwargs={'model': CircuitTermination}), - path('circuit-terminations/connect/', CableCreateView.as_view(), name='circuittermination_connect', kwargs={'termination_a_type': CircuitTermination}), + path('circuit-terminations/connect/', CableEditView.as_view(), name='circuittermination_connect', kwargs={'termination_a_type': CircuitTermination}), ] diff --git a/netbox/dcim/forms/connections.py b/netbox/dcim/forms/connections.py index 66a9e9c6e..10ccbb7d9 100644 --- a/netbox/dcim/forms/connections.py +++ b/netbox/dcim/forms/connections.py @@ -1,305 +1,142 @@ +from django import forms + from circuits.models import Circuit, CircuitTermination, Provider from dcim.models import * -from netbox.forms import NetBoxModelForm -from tenancy.forms import TenancyForm -from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, StaticSelect - -__all__ = ( - 'ConnectCableToCircuitTerminationForm', - 'ConnectCableToConsolePortForm', - 'ConnectCableToConsoleServerPortForm', - 'ConnectCableToFrontPortForm', - 'ConnectCableToInterfaceForm', - 'ConnectCableToPowerFeedForm', - 'ConnectCableToPowerPortForm', - 'ConnectCableToPowerOutletForm', - 'ConnectCableToRearPortForm', -) +from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField +from .models import CableForm -class BaseCableConnectionForm(TenancyForm, NetBoxModelForm): - a_terminations = DynamicModelMultipleChoiceField( - queryset=Interface.objects.all(), - label='Name', - disabled_indicator='_occupied' - ) - b_terminations = DynamicModelMultipleChoiceField( - queryset=Interface.objects.all(), - label='Name', - disabled_indicator='_occupied' - ) +def get_cable_form(a_type, b_type): - def save(self, *args, **kwargs): + class FormMetaclass(forms.models.ModelFormMetaclass): - # Set the A/B terminations on the Cable instance - self.instance.a_terminations = self.cleaned_data['a_terminations'] - self.instance.b_terminations = self.cleaned_data['b_terminations'] + def __new__(mcs, name, bases, attrs): - return super().save(*args, **kwargs) + for cable_end, term_cls in (('a', a_type), ('b', b_type)): + attrs[f'termination_{cable_end}_region'] = DynamicModelChoiceField( + queryset=Region.objects.all(), + label='Region', + required=False, + initial_params={ + 'sites': '$termination_{cable_end}_site' + } + ) + attrs[f'termination_{cable_end}_sitegroup'] = DynamicModelChoiceField( + queryset=SiteGroup.objects.all(), + label='Site group', + required=False, + initial_params={ + 'sites': '$termination_{cable_end}_site' + } + ) + attrs[f'termination_{cable_end}_site'] = DynamicModelChoiceField( + queryset=Site.objects.all(), + label='Site', + required=False, + query_params={ + 'region_id': '$termination_{cable_end}_region', + 'group_id': '$termination_{cable_end}_sitegroup', + } + ) + attrs[f'termination_{cable_end}_location'] = DynamicModelChoiceField( + queryset=Location.objects.all(), + label='Location', + required=False, + null_option='None', + query_params={ + 'site_id': '$termination_{cable_end}_site' + } + ) -class ConnectCableToDeviceForm(BaseCableConnectionForm): - """ - Base form for connecting a Cable to a Device component - """ - termination_b_region = DynamicModelChoiceField( - queryset=Region.objects.all(), - label='Region', - required=False, - initial_params={ - 'sites': '$termination_b_site' - } - ) - termination_b_sitegroup = DynamicModelChoiceField( - queryset=SiteGroup.objects.all(), - label='Site group', - required=False, - initial_params={ - 'sites': '$termination_b_site' - } - ) - termination_b_site = DynamicModelChoiceField( - queryset=Site.objects.all(), - label='Site', - required=False, - query_params={ - 'region_id': '$termination_b_region', - 'group_id': '$termination_b_sitegroup', - } - ) - termination_b_location = DynamicModelChoiceField( - queryset=Location.objects.all(), - label='Location', - required=False, - null_option='None', - query_params={ - 'site_id': '$termination_b_site' - } - ) - termination_b_rack = DynamicModelChoiceField( - queryset=Rack.objects.all(), - label='Rack', - required=False, - null_option='None', - query_params={ - 'site_id': '$termination_b_site', - 'location_id': '$termination_b_location', - } - ) - termination_b_device = DynamicModelChoiceField( - queryset=Device.objects.all(), - label='Device', - required=False, - query_params={ - 'site_id': '$termination_b_site', - 'location_id': '$termination_b_location', - 'rack_id': '$termination_b_rack', - } - ) + # Device component + if hasattr(term_cls, 'device'): - class Meta: - model = Cable - fields = [ - 'a_terminations', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', - 'termination_b_rack', 'termination_b_device', 'b_terminations', 'type', 'status', 'tenant_group', - 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', - ] - widgets = { - 'status': StaticSelect, - 'type': StaticSelect, - 'length_unit': StaticSelect, - } + attrs[f'termination_{cable_end}_rack'] = DynamicModelChoiceField( + queryset=Rack.objects.all(), + label='Rack', + required=False, + null_option='None', + query_params={ + 'site_id': '$termination_{cable_end}_site', + 'location_id': '$termination_{cable_end}_location', + } + ) + attrs[f'termination_{cable_end}_device'] = DynamicModelChoiceField( + queryset=Device.objects.all(), + label='Device', + required=False, + query_params={ + 'site_id': f'$termination_{cable_end}_site', + 'location_id': f'$termination_{cable_end}_location', + 'rack_id': f'$termination_{cable_end}_rack', + } + ) + attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( + queryset=term_cls.objects.all(), + label=term_cls._meta.verbose_name.title(), + disabled_indicator='_occupied', + query_params={ + 'device_id': f'termination_{cable_end}_device', + } + ) + # PowerFeed + elif term_cls == PowerFeed: -class ConnectCableToConsolePortForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=ConsolePort.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device' - } - ) + attrs[f'termination_{cable_end}_powerpanel'] = DynamicModelChoiceField( + queryset=PowerPanel.objects.all(), + label='Power Panel', + required=False, + query_params={ + 'site_id': f'$termination_{cable_end}_site', + 'location_id': f'$termination_{cable_end}_location', + } + ) + attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( + queryset=term_cls.objects.all(), + label='Power Feed', + disabled_indicator='_occupied', + query_params={ + 'powerpanel_id': f'termination_{cable_end}_powerpanel', + } + ) + # CircuitTermination + elif term_cls == CircuitTermination: -class ConnectCableToConsoleServerPortForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=ConsoleServerPort.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device' - } - ) + attrs[f'termination_{cable_end}_provider'] = DynamicModelChoiceField( + queryset=Provider.objects.all(), + label='Provider', + required=False + ) + attrs[f'termination_{cable_end}_circuit'] = DynamicModelChoiceField( + queryset=Circuit.objects.all(), + label='Circuit', + query_params={ + 'provider_id': f'$termination_{cable_end}_provider', + 'site_id': f'$termination_{cable_end}_site', + } + ) + attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( + queryset=term_cls.objects.all(), + label='Side', + disabled_indicator='_occupied', + query_params={ + 'circuit_id': f'termination_{cable_end}_circuit', + } + ) + return super().__new__(mcs, name, bases, attrs) -class ConnectCableToPowerPortForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=PowerPort.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device' - } - ) + class _CableForm(CableForm, metaclass=FormMetaclass): + def save(self, *args, **kwargs): -class ConnectCableToPowerOutletForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=PowerOutlet.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device' - } - ) + # Set the A/B terminations on the Cable instance + self.instance.a_terminations = self.cleaned_data['a_terminations'] + self.instance.b_terminations = self.cleaned_data['b_terminations'] + return super().save(*args, **kwargs) -class ConnectCableToInterfaceForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=Interface.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device', - 'kind': 'physical', - } - ) - - -class ConnectCableToFrontPortForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=FrontPort.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device' - } - ) - - -class ConnectCableToRearPortForm(ConnectCableToDeviceForm): - b_terminations = DynamicModelMultipleChoiceField( - queryset=RearPort.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'device_id': '$termination_b_device' - } - ) - - -class ConnectCableToCircuitTerminationForm(BaseCableConnectionForm): - termination_b_provider = DynamicModelChoiceField( - queryset=Provider.objects.all(), - label='Provider', - required=False - ) - termination_b_region = DynamicModelChoiceField( - queryset=Region.objects.all(), - label='Region', - required=False, - initial_params={ - 'sites': '$termination_b_site' - } - ) - termination_b_sitegroup = DynamicModelChoiceField( - queryset=SiteGroup.objects.all(), - label='Site group', - required=False, - initial_params={ - 'sites': '$termination_b_site' - } - ) - termination_b_site = DynamicModelChoiceField( - queryset=Site.objects.all(), - label='Site', - required=False, - query_params={ - 'region_id': '$termination_b_region', - 'group_id': '$termination_b_sitegroup', - } - ) - termination_b_circuit = DynamicModelChoiceField( - queryset=Circuit.objects.all(), - label='Circuit', - query_params={ - 'provider_id': '$termination_b_provider', - 'site_id': '$termination_b_site', - } - ) - b_terminations = DynamicModelMultipleChoiceField( - queryset=CircuitTermination.objects.all(), - label='Side', - disabled_indicator='_occupied', - query_params={ - 'circuit_id': '$termination_b_circuit' - } - ) - - class Meta(ConnectCableToDeviceForm.Meta): - fields = [ - 'a_terminations', 'termination_b_provider', 'termination_b_region', 'termination_b_sitegroup', - 'termination_b_site', 'termination_b_circuit', 'b_terminations', 'type', 'status', 'tenant_group', - 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', - ] - - -class ConnectCableToPowerFeedForm(BaseCableConnectionForm): - termination_b_region = DynamicModelChoiceField( - queryset=Region.objects.all(), - label='Region', - required=False, - initial_params={ - 'sites': '$termination_b_site' - } - ) - termination_b_sitegroup = DynamicModelChoiceField( - queryset=SiteGroup.objects.all(), - label='Site group', - required=False, - initial_params={ - 'sites': '$termination_b_site' - } - ) - termination_b_site = DynamicModelChoiceField( - queryset=Site.objects.all(), - label='Site', - required=False, - query_params={ - 'region_id': '$termination_b_region', - 'group_id': '$termination_b_sitegroup', - } - ) - termination_b_location = DynamicModelChoiceField( - queryset=Location.objects.all(), - label='Location', - required=False, - query_params={ - 'site_id': '$termination_b_site' - } - ) - termination_b_powerpanel = DynamicModelChoiceField( - queryset=PowerPanel.objects.all(), - label='Power Panel', - required=False, - query_params={ - 'site_id': '$termination_b_site', - 'location_id': '$termination_b_location', - } - ) - b_terminations = DynamicModelMultipleChoiceField( - queryset=PowerFeed.objects.all(), - label='Name', - disabled_indicator='_occupied', - query_params={ - 'power_panel_id': '$termination_b_powerpanel' - } - ) - - class Meta(ConnectCableToDeviceForm.Meta): - fields = [ - 'a_terminations', 'termination_b_region', 'termination_b_sitegroup', 'termination_b_site', - 'termination_b_location', 'termination_b_powerpanel', 'b_terminations', 'type', 'status', 'tenant_group', - 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', - ] + return _CableForm diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 0c04c734e..8aa5f694a 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -294,7 +294,7 @@ urlpatterns = [ path('console-ports//delete/', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'), path('console-ports//changelog/', ObjectChangeLogView.as_view(), name='consoleport_changelog', kwargs={'model': ConsolePort}), path('console-ports//trace/', views.PathTraceView.as_view(), name='consoleport_trace', kwargs={'model': ConsolePort}), - path('console-ports/connect/', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}), + path('console-ports/connect/', views.CableEditView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}), path('devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'), # Console server ports @@ -310,7 +310,7 @@ urlpatterns = [ path('console-server-ports//delete/', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'), path('console-server-ports//changelog/', ObjectChangeLogView.as_view(), name='consoleserverport_changelog', kwargs={'model': ConsoleServerPort}), path('console-server-ports//trace/', views.PathTraceView.as_view(), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}), - path('console-server-ports/connect/', views.CableCreateView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}), + path('console-server-ports/connect/', views.CableEditView.as_view(), name='consoleserverport_connect', kwargs={'termination_a_type': ConsoleServerPort}), path('devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'), # Power ports @@ -326,7 +326,7 @@ urlpatterns = [ path('power-ports//delete/', views.PowerPortDeleteView.as_view(), name='powerport_delete'), path('power-ports//changelog/', ObjectChangeLogView.as_view(), name='powerport_changelog', kwargs={'model': PowerPort}), path('power-ports//trace/', views.PathTraceView.as_view(), name='powerport_trace', kwargs={'model': PowerPort}), - path('power-ports/connect/', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}), + path('power-ports/connect/', views.CableEditView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}), path('devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'), # Power outlets @@ -342,7 +342,7 @@ urlpatterns = [ path('power-outlets//delete/', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'), path('power-outlets//changelog/', ObjectChangeLogView.as_view(), name='poweroutlet_changelog', kwargs={'model': PowerOutlet}), path('power-outlets//trace/', views.PathTraceView.as_view(), name='poweroutlet_trace', kwargs={'model': PowerOutlet}), - path('power-outlets/connect/', views.CableCreateView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}), + path('power-outlets/connect/', views.CableEditView.as_view(), name='poweroutlet_connect', kwargs={'termination_a_type': PowerOutlet}), path('devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'), # Interfaces @@ -358,7 +358,7 @@ urlpatterns = [ path('interfaces//delete/', views.InterfaceDeleteView.as_view(), name='interface_delete'), path('interfaces//changelog/', ObjectChangeLogView.as_view(), name='interface_changelog', kwargs={'model': Interface}), path('interfaces//trace/', views.PathTraceView.as_view(), name='interface_trace', kwargs={'model': Interface}), - path('interfaces/connect/', views.CableCreateView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}), + path('interfaces/connect/', views.CableEditView.as_view(), name='interface_connect', kwargs={'termination_a_type': Interface}), path('devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'), # Front ports @@ -374,7 +374,7 @@ urlpatterns = [ path('front-ports//delete/', views.FrontPortDeleteView.as_view(), name='frontport_delete'), path('front-ports//changelog/', ObjectChangeLogView.as_view(), name='frontport_changelog', kwargs={'model': FrontPort}), path('front-ports//trace/', views.PathTraceView.as_view(), name='frontport_trace', kwargs={'model': FrontPort}), - path('front-ports/connect/', views.CableCreateView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}), + path('front-ports/connect/', views.CableEditView.as_view(), name='frontport_connect', kwargs={'termination_a_type': FrontPort}), # path('devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'), # Rear ports @@ -390,7 +390,7 @@ urlpatterns = [ path('rear-ports//delete/', views.RearPortDeleteView.as_view(), name='rearport_delete'), path('rear-ports//changelog/', ObjectChangeLogView.as_view(), name='rearport_changelog', kwargs={'model': RearPort}), path('rear-ports//trace/', views.PathTraceView.as_view(), name='rearport_trace', kwargs={'model': RearPort}), - path('rear-ports/connect/', views.CableCreateView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}), + path('rear-ports/connect/', views.CableEditView.as_view(), name='rearport_connect', kwargs={'termination_a_type': RearPort}), path('devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'), # Module bays @@ -500,6 +500,6 @@ urlpatterns = [ path('power-feeds//trace/', views.PathTraceView.as_view(), name='powerfeed_trace', kwargs={'model': PowerFeed}), path('power-feeds//changelog/', ObjectChangeLogView.as_view(), name='powerfeed_changelog', kwargs={'model': PowerFeed}), path('power-feeds//journal/', ObjectJournalView.as_view(), name='powerfeed_journal', kwargs={'model': PowerFeed}), - path('power-feeds/connect/', views.CableCreateView.as_view(), name='powerfeed_connect', kwargs={'termination_a_type': PowerFeed}), + path('power-feeds/connect/', views.CableEditView.as_view(), name='powerfeed_connect', kwargs={'termination_a_type': PowerFeed}), ] diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 5c27f734e..1f13e2dc8 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -12,12 +12,12 @@ 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 from netbox.views import generic -from utilities.forms import ConfirmationForm +from utilities.forms import ConfirmationForm, restrict_form_fields from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.permissions import get_permission_for_model from utilities.utils import count_related @@ -2804,72 +2804,49 @@ class PathTraceView(generic.ObjectView): } -class CableCreateView(generic.ObjectEditView): +class CableEditView(generic.ObjectEditView): queryset = Cable.objects.all() - template_name = 'dcim/cable_connect.html' + template_name = 'dcim/cable_edit.html' def dispatch(self, request, *args, **kwargs): - # Set the form class based on the type of component being connected - self.form = { - 'dcim.consoleport': forms.ConnectCableToConsolePortForm, - 'dcim.consoleserverport': forms.ConnectCableToConsoleServerPortForm, - 'dcim.powerport': forms.ConnectCableToPowerPortForm, - 'dcim.poweroutlet': forms.ConnectCableToPowerOutletForm, - 'dcim.interface': forms.ConnectCableToInterfaceForm, - 'dcim.frontport': forms.ConnectCableToFrontPortForm, - 'dcim.rearport': forms.ConnectCableToRearPortForm, - 'dcim.powerfeed': forms.ConnectCableToPowerFeedForm, - 'circuits.circuittermination': forms.ConnectCableToCircuitTerminationForm, - }[request.GET.get('termination_b_type')] + # If creating a new Cable, initialize the form class using URL query params + if 'pk' not in kwargs: + termination_types = { + 'dcim.consoleport': ConsolePort, + 'dcim.consoleserverport': ConsoleServerPort, + 'dcim.powerport': PowerPort, + 'dcim.poweroutlet': PowerOutlet, + 'dcim.interface': Interface, + 'dcim.frontport': FrontPort, + 'dcim.rearport': RearPort, + 'dcim.powerfeed': PowerFeed, + 'circuits.circuittermination': CircuitTermination, + } + + a_type = kwargs.pop('termination_a_type') + b_type = termination_types[request.GET.get('termination_b_type')] + + self.form = forms.get_cable_form(a_type, b_type) return super().dispatch(request, *args, **kwargs) def get_object(self, **kwargs): - # Always return a new instance - return self.queryset.model() + """ + Hack into get_object() to set the form class when editing an existing Cable, since ObjectEditView + doesn't currently provide a hook for dynamic class resolution. + """ + obj = super().get_object(**kwargs) - def get(self, request, *args, **kwargs): - obj = self.get_object(**kwargs) - obj = self.alter_object(obj, request, args, kwargs) - initial_data = request.GET + if obj.pk: + # TODO: Optimize this logic + termination_a = obj.terminations.filter(cable_end='A').first() + a_type = termination_a.termination._meta.model if termination_a else None + termination_b = obj.terminations.filter(cable_end='B').first() + b_type = termination_b.termination._meta.model if termination_a else None + self.form = forms.get_cable_form(a_type, b_type) - app_label, model = request.GET.get('termination_b_type').split('.') - termination_b_type = ContentType.objects.get(app_label=app_label, model=model) - - # TODO - # # 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_b_site' not in initial_data: - # initial_data['termination_b_site'] = termination_a_site - # if 'termination_b_rack' not in initial_data: - # initial_data['termination_b_rack'] = getattr(obj.termination_a.parent_object, 'rack', None) - form = self.form(instance=obj, initial=initial_data) - - # TODO Find a better way to infer the near-end parent object - termination_a = kwargs['termination_a_type'].objects.filter(pk=int(initial_data['a_terminations'])).first() - - # Set the queryset of termination A - form.fields['a_terminations'].queryset = kwargs['termination_a_type'].objects.all() - form.fields['a_terminations'].widget.add_query_params({ - 'device_id': termination_a.device_id, - }) - - return render(request, self.template_name, { - 'obj': obj, - 'obj_type': Cable._meta.verbose_name, - 'termination_a_type': kwargs['termination_a_type']._meta.model_name, - 'termination_a_parent': termination_a.parent_object, - 'termination_b_type': termination_b_type.name, - 'form': form, - 'return_url': self.get_return_url(request, obj), - }) - - -class CableEditView(generic.ObjectEditView): - queryset = Cable.objects.all() - form = forms.CableForm - template_name = 'dcim/cable_edit.html' + return obj class CableDeleteView(generic.ObjectDeleteView): diff --git a/netbox/templates/dcim/cable_connect.html b/netbox/templates/dcim/cable_connect.html deleted file mode 100644 index fdbc4cf97..000000000 --- a/netbox/templates/dcim/cable_connect.html +++ /dev/null @@ -1,167 +0,0 @@ -{% extends 'base/layout.html' %} -{% load static %} -{% load helpers %} -{% load form_helpers %} - -{% block title %}Connect Cable to {{ termination_b_type|bettertitle }}{% endblock %} - -{% block tabs %} - -{% endblock %} - -{% block content-wrapper %} -
- {% render_errors form %} -
- {% csrf_token %} - {% for field in form.hidden_fields %} - {{ field }} - {% endfor %} -
-
-
-
A Side
-
- {% if termination_a_type == 'circuit' %} - {# Circuit termination #} -
- -
- -
-
-
- -
- -
-
- {% else %} - {# Device component #} -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- {% endif %} - {% render_field form.a_terminations %} -
-
-
-
- -
-
-
-
B Side
-
- {% if tabs %} - - {% endif %} - {% if 'termination_b_provider' in form.fields %} - {% render_field form.termination_b_provider %} - {% endif %} - {% if 'termination_b_region' in form.fields %} - {% render_field form.termination_b_region %} - {% endif %} - {% if 'termination_b_sitegroup' in form.fields %} - {% render_field form.termination_b_sitegroup %} - {% endif %} - {% if 'termination_b_site' in form.fields %} - {% render_field form.termination_b_site %} - {% endif %} - {% if 'termination_b_location' in form.fields %} - {% render_field form.termination_b_location %} - {% endif %} - {% if 'termination_b_rack' in form.fields %} - {% render_field form.termination_b_rack %} - {% endif %} - {% if 'termination_b_device' in form.fields %} - {% render_field form.termination_b_device %} - {% endif %} - {% if 'termination_b_type' in form.fields %} - {% render_field form.termination_b_type %} - {% endif %} - {% if 'termination_b_powerpanel' in form.fields %} - {% render_field form.termination_b_powerpanel %} - {% endif %} - {% if 'termination_b_circuit' in form.fields %} - {% render_field form.termination_b_circuit %} - {% endif %} -
- -
- -
-
- {% render_field form.b_terminations %} -
-
-
-
-
-
-
-
Cable
-
- {% include 'dcim/inc/cable_form.html' %} -
-
-
-
-
-
- Cancel - -
-
-
-
-{% endblock %} diff --git a/netbox/templates/dcim/cable_edit.html b/netbox/templates/dcim/cable_edit.html index 45f05faad..e2cef7601 100644 --- a/netbox/templates/dcim/cable_edit.html +++ b/netbox/templates/dcim/cable_edit.html @@ -1,5 +1,125 @@ -{% extends 'generic/object_edit.html' %} +{% extends 'base/layout.html' %} +{% load static %} +{% load helpers %} +{% load form_helpers %} -{% block form %} - {% include 'dcim/inc/cable_form.html' %} +{% block title %}Connect Cable{% endblock %} + +{% block tabs %} + +{% endblock %} + +{% block content-wrapper %} +
+ {% render_errors form %} +
+ {% csrf_token %} + {% for field in form.hidden_fields %} + {{ field }} + {% endfor %} +
+
+
+
A Side
+
+ {% render_field form.termination_a_region %} + {% render_field form.termination_a_sitegroup %} + {% render_field form.termination_a_site %} + {% render_field form.termination_a_location %} + {% if 'termination_a_rack' in form.fields %} + {% render_field form.termination_a_rack %} + {% endif %} + {% if 'termination_a_device' in form.fields %} + {% render_field form.termination_a_device %} + {% endif %} + {% if 'termination_a_powerpanel' in form.fields %} + {% render_field form.termination_a_powerpanel %} + {% endif %} + {% if 'termination_a_provider' in form.fields %} + {% render_field form.termination_a_provider %} + {% endif %} + {% if 'termination_a_circuit' in form.fields %} + {% render_field form.termination_a_circuit %} + {% endif %} + {% render_field form.a_terminations %} +
+
+
+
+ +
+
+
+
B Side
+
+ {% render_field form.termination_b_region %} + {% render_field form.termination_b_sitegroup %} + {% render_field form.termination_b_site %} + {% render_field form.termination_b_location %} + {% if 'termination_b_rack' in form.fields %} + {% render_field form.termination_b_rack %} + {% endif %} + {% if 'termination_b_device' in form.fields %} + {% render_field form.termination_b_device %} + {% endif %} + {% if 'termination_b_powerpanel' in form.fields %} + {% render_field form.termination_b_powerpanel %} + {% endif %} + {% if 'termination_b_provider' in form.fields %} + {% render_field form.termination_b_provider %} + {% endif %} + {% if 'termination_b_circuit' in form.fields %} + {% render_field form.termination_b_circuit %} + {% endif %} + {% render_field form.b_terminations %} +
+
+
+
+
+
+
+
Cable
+
+ {% render_field form.status %} + {% render_field form.type %} + {% render_field form.tenant_group %} + {% render_field form.tenant %} + {% render_field form.label %} + {% render_field form.color %} +
+ +
+ {{ form.length }} +
+
+ {{ form.length_unit }} +
+
+
+ {% render_field form.tags %} + {% if form.custom_fields %} +
+
+
Custom Fields
+
+ {% render_custom_fields form %} +
+ {% endif %} +
+
+
+
+
+
+ Cancel + +
+
+
+
{% endblock %} diff --git a/netbox/templates/dcim/inc/cable_form.html b/netbox/templates/dcim/inc/cable_form.html deleted file mode 100644 index 0f11ac3cb..000000000 --- a/netbox/templates/dcim/inc/cable_form.html +++ /dev/null @@ -1,27 +0,0 @@ -{% load form_helpers %} - -{% render_field form.status %} -{% render_field form.type %} -{% render_field form.tenant_group %} -{% render_field form.tenant %} -{% render_field form.label %} -{% render_field form.color %} -
- -
- {{ form.length }} -
-
- {{ form.length_unit }} -
-
-
-{% render_field form.tags %} -{% if form.custom_fields %} -
-
-
Custom Fields
-
- {% render_custom_fields form %} -
-{% endif %} diff --git a/netbox/templates/dcim/inc/cable_termination.html b/netbox/templates/dcim/inc/cable_termination.html index a72878b48..9d1c43bdd 100644 --- a/netbox/templates/dcim/inc/cable_termination.html +++ b/netbox/templates/dcim/inc/cable_termination.html @@ -6,13 +6,31 @@ Site {{ terminations.0.device.site|linkify }} + + Rack + {{ terminations.0.device.rack|linkify|placeholder }} + Device {{ terminations.0.device|linkify }} - Rack - {{ terminations.0.device.rack|linkify|placeholder }} + {{ terminations.0|meta:"verbose_name"|capfirst }} + + {% for term in terminations %} + {{ term|linkify }}{% if not forloop.last %},{% endif %} + {% endfor %} + + + {% elif terminations.0.power_panel %} + {# Power feed #} + + Site + {{ terminations.0.power_panel.site|linkify }} + + + Power Panel + {{ terminations.0.power_panel|linkify }} {{ terminations.0|meta:"verbose_name"|capfirst }}