diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index e74551c2e..883d72498 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2131,7 +2131,7 @@ class RearPortBulkRenameForm(BulkRenameForm): # Cables # -class CableForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): +class CableCreateForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): termination_b_site = forms.ModelChoiceField( queryset=Site.objects.all(), label='Site', @@ -2198,7 +2198,7 @@ class CableForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): ] def __init__(self, *args, **kwargs): - super(CableForm, self).__init__(*args, **kwargs) + super(CableCreateForm, self).__init__(*args, **kwargs) # Define available types for endpoint B based on the type of endpoint A termination_a_type = self.instance.termination_a._meta.model_name @@ -2207,6 +2207,13 @@ class CableForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelForm): ) +class CableForm(BootstrapMixin, forms.ModelForm): + + class Meta: + model = Cable + fields = ('type', 'status', 'label', 'color') + + class CableFilterForm(BootstrapMixin, forms.Form): model = Cable q = forms.CharField(required=False, label='Search') diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 26bfc5a32..881a3b2d7 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -2380,6 +2380,9 @@ class Cable(ChangeLoggedModel): return '{} (#{})'.format(self.label, self.pk) return '#{}'.format(self.pk) + def get_absolute_url(self): + return reverse('dcim:cable', args=[self.pk]) + def get_path_endpoints(self): """ Traverse both ends of a cable path and return its connected endpoints. Note that one or both endpoints may be diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index 0a79560f8..7a27ecc64 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -621,9 +621,10 @@ class DeviceBayTable(BaseTable): class CableTable(BaseTable): # django-tables2 adds CSS `class="label"` which causes rendering issues - _label = tables.Column( - accessor=Accessor('label'), - verbose_name='Label' + pk = tables.LinkColumn( + viewname='dcim:cable', + args=[Accessor('pk')], + verbose_name='PK' ) device_a = tables.LinkColumn( viewname='dcim:device', @@ -652,7 +653,7 @@ class CableTable(BaseTable): class Meta(BaseTable.Meta): model = Cable - fields = ('_label', 'device_a', 'termination_a', 'device_b', 'termination_b', 'status', 'type', 'color') + fields = ('pk', 'device_a', 'termination_a', 'device_b', 'termination_b', 'status', 'type', 'color') # diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index e7b69593a..9a669d4f1 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -252,6 +252,8 @@ urlpatterns = [ # Cables url(r'^cables/$', views.CableListView.as_view(), name='cable_list'), + url(r'^cables/(?P\d+)/$', views.CableView.as_view(), name='cable'), + url(r'^cables/(?P\d+)/edit/$', views.CableEditView.as_view(), name='cable_edit'), url(r'^cables/(?P\d+)/delete/$', views.CableDeleteView.as_view(), name='cable_delete'), # Console/power/interface connections diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 25f62f612..e4454ee75 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2023,10 +2023,21 @@ class CableListView(ObjectListView): template_name = 'dcim/cable_list.html' +class CableView(View): + + def get(self, request, pk): + + cable = get_object_or_404(Cable, pk=pk) + + return render(request, 'dcim/cable.html', { + 'cable': cable, + }) + + class CableCreateView(PermissionRequiredMixin, ObjectEditView): permission_required = 'dcim.add_cable' model = Cable - model_form = forms.CableForm + model_form = forms.CableCreateForm template_name = 'dcim/cable_connect.html' def alter_obj(self, obj, request, url_args, url_kwargs): @@ -2039,6 +2050,13 @@ class CableCreateView(PermissionRequiredMixin, ObjectEditView): return obj +class CableEditView(PermissionRequiredMixin, ObjectEditView): + permission_required = 'dcim.change_cable' + model = Cable + model_form = forms.CableForm + default_return_url = 'dcim:cable_list' + + class CableDeleteView(PermissionRequiredMixin, ObjectDeleteView): permission_required = 'dcim.delete_cable' model = Cable diff --git a/netbox/templates/dcim/cable.html b/netbox/templates/dcim/cable.html new file mode 100644 index 000000000..72bea3ebc --- /dev/null +++ b/netbox/templates/dcim/cable.html @@ -0,0 +1,72 @@ +{% extends '_base.html' %} +{% load helpers %} + +{% block header %} +
+
+ +
+
+
+ {% if perms.dcim.change_cable %} + + Edit this cable + + {% endif %} + {% if perms.dcim.delete_cable %} + + Delete this cable + + {% endif %} +
+

{% block title %}Cable {{ cable }}{% endblock %}

+{% endblock %} + +{% block content %} +
+
+
+
+ Cable +
+ + + + + + + + + + + + + + + + + +
Type{{ cable.get_type_display }}
Status{{ cable.get_status_display }}
Label{% if cable.label %}{{ cable.label }}{% else %}N/A{% endif %}
Color + +
+
+
+
+
+
+ Termination A +
+ {% include 'dcim/inc/cable_termination.html' with termination=cable.termination_a %} +
+
+
+ Termination B +
+ {% include 'dcim/inc/cable_termination.html' with termination=cable.termination_b %} +
+
+
+{% endblock %} diff --git a/netbox/templates/dcim/inc/cable_termination.html b/netbox/templates/dcim/inc/cable_termination.html new file mode 100644 index 000000000..8089c6636 --- /dev/null +++ b/netbox/templates/dcim/inc/cable_termination.html @@ -0,0 +1,12 @@ + + + + + + + + + +
Device + {{ termination.device }} +
Component{{ termination_a }}