From 21b3fbd50f414ef8d3726dd68dabd5cec35f2430 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 12 May 2016 14:38:34 -0400 Subject: [PATCH] Added views for DeviceRoles --- netbox/dcim/forms.py | 15 +++++ netbox/dcim/models.py | 3 + netbox/dcim/tables.py | 34 +++++++++- netbox/dcim/urls.py | 6 ++ netbox/dcim/views.py | 65 ++++++++++++++----- netbox/templates/dcim/devicerole_edit.html | 11 ++++ netbox/templates/dcim/devicerole_list.html | 21 ++++++ .../templates/dcim/inc/devicerole_table.html | 14 ++++ netbox/templates/utilities/obj_edit.html | 3 +- netbox/utilities/views.py | 5 +- 10 files changed, 157 insertions(+), 20 deletions(-) create mode 100644 netbox/templates/dcim/devicerole_edit.html create mode 100644 netbox/templates/dcim/devicerole_list.html create mode 100644 netbox/templates/dcim/inc/devicerole_table.html diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 7c3607774..7bf717de0 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -261,6 +261,21 @@ class InterfaceTemplateForm(forms.ModelForm, BootstrapMixin): fields = ['name_pattern', 'form_factor', 'mgmt_only'] +# +# Device roles +# + +class DeviceRoleForm(forms.ModelForm, BootstrapMixin): + + class Meta: + model = DeviceRole + fields = ['name', 'slug', 'color'] + + +class DeviceRoleBulkDeleteForm(ConfirmationForm): + pk = forms.ModelMultipleChoiceField(queryset=DeviceRole.objects.all(), widget=forms.MultipleHiddenInput) + + # # Devices # diff --git a/netbox/dcim/models.py b/netbox/dcim/models.py index 824800b8b..9b7dc0b9e 100644 --- a/netbox/dcim/models.py +++ b/netbox/dcim/models.py @@ -392,6 +392,9 @@ class DeviceRole(models.Model): def __unicode__(self): return self.name + def get_absolute_url(self): + return "{}?role={}".format(reverse('dcim:device_list'), self.slug) + class Platform(models.Model): """ diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index 867a006a6..ebcd0fd55 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -2,7 +2,7 @@ import django_tables2 as tables from django_tables2.utils import Accessor from .models import Site, RackGroup, Rack, DeviceType, ConsolePortTemplate, ConsoleServerPortTemplate, \ - PowerPortTemplate, PowerOutletTemplate, InterfaceTemplate, Device, ConsolePort, PowerPort + PowerPortTemplate, PowerOutletTemplate, InterfaceTemplate, DeviceRole, Device, ConsolePort, PowerPort DEVICE_LINK = """ {{ record.name|default:'Unnamed device' }} @@ -12,6 +12,10 @@ RACKGROUP_EDIT_LINK = """ Edit """ +DEVICEROLE_EDIT_LINK = """ +Edit +""" + STATUS_ICON = """ """ @@ -224,6 +228,34 @@ class InterfaceTemplateBulkDeleteTable(InterfaceTemplateTable): fields = ('pk', 'name') +# +# Device roles +# + +class DeviceRoleTable(tables.Table): + name = tables.LinkColumn(verbose_name='Name') + device_count = tables.Column(accessor=Accessor('device_count'), verbose_name='Devices') + slug = tables.Column(verbose_name='Slug') + color = tables.Column(verbose_name='Color') + + class Meta: + model = DeviceRole + fields = ('name', 'device_count', 'slug', 'color') + empty_text = "No device roles were found." + attrs = { + 'class': 'table table-hover', + } + + +class DeviceRoleBulkEditTable(DeviceRoleTable): + pk = tables.CheckBoxColumn() + edit = tables.TemplateColumn(template_code=DEVICEROLE_EDIT_LINK, verbose_name='') + + class Meta(DeviceRoleTable.Meta): + model = None # django_tables2 bugfix + fields = ('pk', 'name', 'device_count', 'slug', 'color') + + # # Devices # diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 7c024a170..fb657e169 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -64,6 +64,12 @@ urlpatterns = [ url(r'^device-types/(?P\d+)/interfaces/delete/$', views.component_template_delete, {'model': InterfaceTemplate}, name='devicetype_delete_interface'), + # Device roles + url(r'^device-roles/$', views.DeviceRoleListView.as_view(), name='devicerole_list'), + url(r'^device-roles/add/$', views.DeviceRoleAddView.as_view(), name='devicerole_add'), + url(r'^device-roles/delete/$', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'), + url(r'^device-roles/(?P[\w-]+)/edit/$', views.DeviceRoleEditView.as_view(), name='devicerole_edit'), + # Devices url(r'^devices/$', views.DeviceListView.as_view(), name='device_list'), url(r'^devices/add/$', views.DeviceAddView.as_view(), name='device_add'), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index fca0b7451..b6bbc31a7 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -24,24 +24,24 @@ from .filters import RackGroupFilter, RackFilter, DeviceTypeFilter, DeviceFilter PowerConnectionFilter, InterfaceConnectionFilter from .forms import SiteForm, SiteImportForm, RackGroupForm, RackGroupFilterForm, RackGroupBulkDeleteForm, RackForm, \ RackImportForm, RackBulkEditForm, RackBulkDeleteForm, RackFilterForm, DeviceTypeForm, DeviceTypeBulkEditForm, \ - DeviceTypeBulkDeleteForm, DeviceTypeFilterForm, DeviceForm, DeviceImportForm, DeviceBulkEditForm, \ - DeviceBulkDeleteForm, DeviceFilterForm, ConsolePortForm, ConsolePortCreateForm, ConsolePortConnectionForm, \ - ConsoleConnectionImportForm, ConsoleServerPortForm, ConsoleServerPortCreateForm, ConsoleServerPortConnectionForm, \ - PowerPortForm, PowerPortCreateForm, PowerPortConnectionForm, PowerConnectionImportForm, PowerOutletForm, \ - PowerOutletCreateForm, PowerOutletConnectionForm, InterfaceForm, InterfaceCreateForm, InterfaceBulkCreateForm, \ - InterfaceConnectionForm, InterfaceConnectionDeletionForm, InterfaceConnectionImportForm, \ - ConsoleConnectionFilterForm, PowerConnectionFilterForm, InterfaceConnectionFilterForm, IPAddressForm, \ - ConsolePortTemplateForm, ConsoleServerPortTemplateForm, PowerPortTemplateForm, PowerOutletTemplateForm, \ - InterfaceTemplateForm -from .models import Site, RackGroup, Rack, DeviceType, ConsolePortTemplate, ConsoleServerPortTemplate, \ + DeviceTypeBulkDeleteForm, DeviceTypeFilterForm, DeviceRoleForm, DeviceRoleBulkDeleteForm, DeviceForm, \ + DeviceImportForm, DeviceBulkEditForm, DeviceBulkDeleteForm, DeviceFilterForm, ConsolePortForm, \ + ConsolePortCreateForm, ConsolePortConnectionForm, ConsoleConnectionImportForm, ConsoleServerPortForm, \ + ConsoleServerPortCreateForm, ConsoleServerPortConnectionForm, PowerPortForm, PowerPortCreateForm, \ + PowerPortConnectionForm, PowerConnectionImportForm, PowerOutletForm, PowerOutletCreateForm, \ + PowerOutletConnectionForm, InterfaceForm, InterfaceCreateForm, InterfaceBulkCreateForm, InterfaceConnectionForm, \ + InterfaceConnectionDeletionForm, InterfaceConnectionImportForm, ConsoleConnectionFilterForm, \ + PowerConnectionFilterForm, InterfaceConnectionFilterForm, IPAddressForm, ConsolePortTemplateForm, \ + ConsoleServerPortTemplateForm, PowerPortTemplateForm, PowerOutletTemplateForm, InterfaceTemplateForm +from .models import Site, RackGroup, Rack, DeviceType, DeviceRole, ConsolePortTemplate, ConsoleServerPortTemplate, \ PowerPortTemplate, PowerOutletTemplate, InterfaceTemplate, Device, ConsolePort, ConsoleServerPort, PowerPort, \ PowerOutlet, Interface, InterfaceConnection, Module, CONNECTION_STATUS_CONNECTED from .tables import SiteTable, RackGroupTable, RackGroupBulkEditTable, RackTable, RackBulkEditTable, DeviceTypeTable, \ - DeviceTypeBulkEditTable, DeviceTable, DeviceBulkEditTable, DeviceImportTable, ConsoleConnectionTable, \ - PowerConnectionTable, InterfaceConnectionTable, ConsolePortTemplateTable, ConsoleServerPortTemplateTable, \ - PowerPortTemplateTable, PowerOutletTemplateTable, InterfaceTemplateTable, ConsolePortTemplateBulkDeleteTable, \ - ConsoleServerPortTemplateBulkDeleteTable, PowerPortTemplateBulkDeleteTable, PowerOutletTemplateBulkDeleteTable, \ - InterfaceTemplateBulkDeleteTable + DeviceTypeBulkEditTable, DeviceRoleTable, DeviceRoleBulkEditTable, DeviceTable, DeviceBulkEditTable, \ + DeviceImportTable, ConsoleConnectionTable, PowerConnectionTable, InterfaceConnectionTable, \ + ConsolePortTemplateTable, ConsoleServerPortTemplateTable, PowerPortTemplateTable, PowerOutletTemplateTable, \ + InterfaceTemplateTable, ConsolePortTemplateBulkDeleteTable, ConsoleServerPortTemplateBulkDeleteTable, \ + PowerPortTemplateBulkDeleteTable, PowerOutletTemplateBulkDeleteTable, InterfaceTemplateBulkDeleteTable EXPANSION_PATTERN = '\[(\d+-\d+)\]' @@ -458,6 +458,41 @@ def component_template_delete(request, pk, model): }) +# +# Device roles +# + +class DeviceRoleListView(ObjectListView): + queryset = DeviceRole.objects.annotate(device_count=Count('devices')) + table = DeviceRoleTable + edit_table = DeviceRoleBulkEditTable + edit_table_permissions = ['dcim.change_devicerole', 'dcim.delete_devicerole'] + template_name = 'dcim/devicerole_list.html' + + +class DeviceRoleAddView(PermissionRequiredMixin, ObjectAddView): + permission_required = 'dcim.add_devicerole' + model = DeviceRole + form_class = DeviceRoleForm + template_name = 'dcim/devicerole_edit.html' + cancel_url = 'dcim:devicerole_list' + + +class DeviceRoleEditView(PermissionRequiredMixin, ObjectEditView): + permission_required = 'dcim.change_devicerole' + model = DeviceRole + form_class = DeviceRoleForm + return_url = 'dcim:devicerole_list' + template_name = 'dcim/devicerole_edit.html' + + +class DeviceRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): + permission_required = 'dcim.delete_devicerole' + cls = DeviceRole + form = DeviceRoleBulkDeleteForm + default_redirect_url = 'dcim:devicerole_list' + + # # Devices # diff --git a/netbox/templates/dcim/devicerole_edit.html b/netbox/templates/dcim/devicerole_edit.html new file mode 100644 index 000000000..4271af50a --- /dev/null +++ b/netbox/templates/dcim/devicerole_edit.html @@ -0,0 +1,11 @@ +{% extends 'utilities/obj_edit.html' %} +{% load form_helpers %} + +{% block form %} +
+
Device Role
+
+ {% render_form form %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/devicerole_list.html b/netbox/templates/dcim/devicerole_list.html new file mode 100644 index 000000000..350ef258d --- /dev/null +++ b/netbox/templates/dcim/devicerole_list.html @@ -0,0 +1,21 @@ +{% extends '_base.html' %} +{% load helpers %} + +{% block title %}Device Roles{% endblock %} + +{% block content %} +
+ {% if perms.dcim.add_devicerole %} + + + Add a device role + + {% endif %} +
+

Device Roles

+
+
+ {% include 'dcim/inc/devicerole_table.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/inc/devicerole_table.html b/netbox/templates/dcim/inc/devicerole_table.html new file mode 100644 index 000000000..54f8c3547 --- /dev/null +++ b/netbox/templates/dcim/inc/devicerole_table.html @@ -0,0 +1,14 @@ +{% load render_table from django_tables2 %} +{% if perms.dcim.delete_devicerole %} +
+ {% csrf_token %} + + {% render_table table table_template|default:'table.html' %} + +
+{% else %} + {% render_table table table_template|default:'table.html' %} +{% endif %} diff --git a/netbox/templates/utilities/obj_edit.html b/netbox/templates/utilities/obj_edit.html index 8d31e1933..8a34ba1a3 100644 --- a/netbox/templates/utilities/obj_edit.html +++ b/netbox/templates/utilities/obj_edit.html @@ -26,12 +26,11 @@
{% if obj %} - Cancel {% else %} - Cancel {% endif %} + Cancel
diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 93731f882..3267a708a 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -118,6 +118,7 @@ class ObjectEditView(View): model = None form_class = None template_name = None + return_url = None def get_object(self, kwargs): # Look up object by slug if one has been provided. Otherwise, use PK. @@ -135,7 +136,7 @@ class ObjectEditView(View): 'obj': obj, 'form': form, 'obj_type': self.model._meta.verbose_name, - 'cancel_url': obj.get_absolute_url(), + 'cancel_url': reverse(self.return_url) if self.return_url else obj.get_absolute_url(), }) def post(self, request, *args, **kwargs): @@ -155,7 +156,7 @@ class ObjectEditView(View): 'obj': obj, 'form': form, 'obj_type': self.model._meta.verbose_name, - 'cancel_url': obj.get_absolute_url(), + 'cancel_url': reverse(self.return_url) if self.return_url else obj.get_absolute_url(), })