Просмотр исходного кода

Closes #3563: Enable editing of individual DeviceType components

Jeremy Stretch 6 лет назад
Родитель
Сommit
c668b990e1
5 измененных файлов с 138 добавлено и 8 удалено
  1. 1 0
      CHANGELOG.md
  2. 20 0
      netbox/dcim/forms.py
  3. 61 8
      netbox/dcim/tables.py
  4. 8 0
      netbox/dcim/urls.py
  5. 48 0
      netbox/dcim/views.py

+ 1 - 0
CHANGELOG.md

@@ -11,6 +11,7 @@ v2.6.6 (FUTURE)
 
 * [#1941](https://github.com/netbox-community/netbox/issues/1941) - Add InfiniBand interface types
 * [#3259](https://github.com/netbox-community/netbox/issues/3259) - Add `rack` and `site` filters for cables
+* [#3563](https://github.com/netbox-community/netbox/issues/3563) - Enable editing of individual DeviceType components
 
 ---
 

+ 20 - 0
netbox/dcim/forms.py

@@ -1023,6 +1023,16 @@ class PowerOutletTemplateForm(BootstrapMixin, forms.ModelForm):
             'device_type': forms.HiddenInput(),
         }
 
+    def __init__(self, *args, **kwargs):
+
+        super().__init__(*args, **kwargs)
+
+        # Limit power_port choices to current DeviceType
+        if hasattr(self.instance, 'device_type'):
+            self.fields['power_port'].queryset = PowerPortTemplate.objects.filter(
+                device_type=self.instance.device_type
+            )
+
 
 class PowerOutletTemplateCreateForm(ComponentForm):
     name_pattern = ExpandableNameField(
@@ -1107,6 +1117,16 @@ class FrontPortTemplateForm(BootstrapMixin, forms.ModelForm):
             'rear_port': StaticSelect2(),
         }
 
+    def __init__(self, *args, **kwargs):
+
+        super().__init__(*args, **kwargs)
+
+        # Limit rear_port choices to current DeviceType
+        if hasattr(self.instance, 'device_type'):
+            self.fields['rear_port'].queryset = RearPortTemplate.objects.filter(
+                device_type=self.instance.device_type
+            )
+
 
 class FrontPortTemplateCreateForm(ComponentForm):
     name_pattern = ExpandableNameField(

+ 61 - 8
netbox/dcim/tables.py

@@ -195,6 +195,16 @@ POWERPANEL_POWERFEED_COUNT = """
 """
 
 
+def get_component_template_actions(model_name):
+    return """
+        {{% if perms.dcim.change_{model_name} %}}
+            <a href="{{% url 'dcim:{model_name}_edit' pk=record.pk %}}?return_url={{{{ request.path }}}}" class="btn btn-xs btn-warning">
+                <i class="glyphicon glyphicon-pencil" aria-hidden="true"></i>
+            </a>
+        {{% endif %}}
+    """.format(model_name=model_name).strip()
+
+
 #
 # Regions
 #
@@ -404,74 +414,117 @@ class DeviceTypeTable(BaseTable):
 
 class ConsolePortTemplateTable(BaseTable):
     pk = ToggleColumn()
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('consoleporttemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = ConsolePortTemplate
-        fields = ('pk', 'name')
+        fields = ('pk', 'name', 'actions')
         empty_text = "None"
 
 
 class ConsoleServerPortTemplateTable(BaseTable):
     pk = ToggleColumn()
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('consoleserverporttemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = ConsoleServerPortTemplate
-        fields = ('pk', 'name')
+        fields = ('pk', 'name', 'actions')
         empty_text = "None"
 
 
 class PowerPortTemplateTable(BaseTable):
     pk = ToggleColumn()
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('powerporttemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = PowerPortTemplate
-        fields = ('pk', 'name', 'maximum_draw', 'allocated_draw')
+        fields = ('pk', 'name', 'maximum_draw', 'allocated_draw', 'actions')
         empty_text = "None"
 
 
 class PowerOutletTemplateTable(BaseTable):
     pk = ToggleColumn()
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('poweroutlettemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = PowerOutletTemplate
-        fields = ('pk', 'name', 'power_port', 'feed_leg')
+        fields = ('pk', 'name', 'power_port', 'feed_leg', 'actions')
         empty_text = "None"
 
 
 class InterfaceTemplateTable(BaseTable):
     pk = ToggleColumn()
     mgmt_only = tables.TemplateColumn("{% if value %}OOB Management{% endif %}")
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('interfacetemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = InterfaceTemplate
-        fields = ('pk', 'name', 'mgmt_only', 'type')
+        fields = ('pk', 'name', 'mgmt_only', 'type', 'actions')
         empty_text = "None"
 
 
 class FrontPortTemplateTable(BaseTable):
     pk = ToggleColumn()
+    rear_port_position = tables.Column(
+        verbose_name='Position'
+    )
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('frontporttemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = FrontPortTemplate
-        fields = ('pk', 'name', 'type', 'rear_port', 'rear_port_position')
+        fields = ('pk', 'name', 'type', 'rear_port', 'rear_port_position', 'actions')
         empty_text = "None"
 
 
 class RearPortTemplateTable(BaseTable):
     pk = ToggleColumn()
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('rearporttemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = RearPortTemplate
-        fields = ('pk', 'name', 'type', 'positions')
+        fields = ('pk', 'name', 'type', 'positions', 'actions')
         empty_text = "None"
 
 
 class DeviceBayTemplateTable(BaseTable):
     pk = ToggleColumn()
+    actions = tables.TemplateColumn(
+        template_code=get_component_template_actions('devicebaytemplate'),
+        attrs={'td': {'class': 'text-right noprint'}},
+        verbose_name=''
+    )
 
     class Meta(BaseTable.Meta):
         model = DeviceBayTemplate
-        fields = ('pk', 'name')
+        fields = ('pk', 'name', 'actions')
         empty_text = "None"
 
 

+ 8 - 0
netbox/dcim/urls.py

@@ -93,35 +93,43 @@ urlpatterns = [
     # Console port templates
     path(r'device-types/<int:pk>/console-ports/add/', views.ConsolePortTemplateCreateView.as_view(), name='devicetype_add_consoleport'),
     path(r'device-types/<int:pk>/console-ports/delete/', views.ConsolePortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleport'),
+    path(r'console-port-templates/<int:pk>/edit/', views.ConsolePortTemplateEditView.as_view(), name='consoleporttemplate_edit'),
 
     # Console server port templates
     path(r'device-types/<int:pk>/console-server-ports/add/', views.ConsoleServerPortTemplateCreateView.as_view(), name='devicetype_add_consoleserverport'),
     path(r'device-types/<int:pk>/console-server-ports/delete/', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_consoleserverport'),
+    path(r'console-server-port-templates/<int:pk>/edit/', views.ConsoleServerPortTemplateEditView.as_view(), name='consoleserverporttemplate_edit'),
 
     # Power port templates
     path(r'device-types/<int:pk>/power-ports/add/', views.PowerPortTemplateCreateView.as_view(), name='devicetype_add_powerport'),
     path(r'device-types/<int:pk>/power-ports/delete/', views.PowerPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_powerport'),
+    path(r'power-port-templates/<int:pk>/edit/', views.PowerPortTemplateEditView.as_view(), name='powerporttemplate_edit'),
 
     # Power outlet templates
     path(r'device-types/<int:pk>/power-outlets/add/', views.PowerOutletTemplateCreateView.as_view(), name='devicetype_add_poweroutlet'),
     path(r'device-types/<int:pk>/power-outlets/delete/', views.PowerOutletTemplateBulkDeleteView.as_view(), name='devicetype_delete_poweroutlet'),
+    path(r'power-outlet-templates/<int:pk>/edit/', views.PowerOutletTemplateEditView.as_view(), name='poweroutlettemplate_edit'),
 
     # Interface templates
     path(r'device-types/<int:pk>/interfaces/add/', views.InterfaceTemplateCreateView.as_view(), name='devicetype_add_interface'),
     path(r'device-types/<int:pk>/interfaces/edit/', views.InterfaceTemplateBulkEditView.as_view(), name='devicetype_bulkedit_interface'),
     path(r'device-types/<int:pk>/interfaces/delete/', views.InterfaceTemplateBulkDeleteView.as_view(), name='devicetype_delete_interface'),
+    path(r'interface-templates/<int:pk>/edit/', views.InterfaceTemplateEditView.as_view(), name='interfacetemplate_edit'),
 
     # Front port templates
     path(r'device-types/<int:pk>/front-ports/add/', views.FrontPortTemplateCreateView.as_view(), name='devicetype_add_frontport'),
     path(r'device-types/<int:pk>/front-ports/delete/', views.FrontPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_frontport'),
+    path(r'front-port-templates/<int:pk>/edit/', views.FrontPortTemplateEditView.as_view(), name='frontporttemplate_edit'),
 
     # Rear port templates
     path(r'device-types/<int:pk>/rear-ports/add/', views.RearPortTemplateCreateView.as_view(), name='devicetype_add_rearport'),
     path(r'device-types/<int:pk>/rear-ports/delete/', views.RearPortTemplateBulkDeleteView.as_view(), name='devicetype_delete_rearport'),
+    path(r'rear-port-templates/<int:pk>/edit/', views.RearPortTemplateEditView.as_view(), name='rearporttemplate_edit'),
 
     # Device bay templates
     path(r'device-types/<int:pk>/device-bays/add/', views.DeviceBayTemplateCreateView.as_view(), name='devicetype_add_devicebay'),
     path(r'device-types/<int:pk>/device-bays/delete/', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicetype_delete_devicebay'),
+    path(r'device-bay-templates/<int:pk>/edit/', views.DeviceBayTemplateEditView.as_view(), name='devicebaytemplate_edit'),
 
     # Device roles
     path(r'device-roles/', views.DeviceRoleListView.as_view(), name='devicerole_list'),

+ 48 - 0
netbox/dcim/views.py

@@ -693,6 +693,12 @@ class ConsolePortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView
     template_name = 'dcim/device_component_add.html'
 
 
+class ConsolePortTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_consoleporttemplate'
+    model = ConsolePortTemplate
+    model_form = forms.ConsolePortTemplateForm
+
+
 class ConsolePortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_consoleporttemplate'
     queryset = ConsolePortTemplate.objects.all()
@@ -710,6 +716,12 @@ class ConsoleServerPortTemplateCreateView(PermissionRequiredMixin, ComponentCrea
     template_name = 'dcim/device_component_add.html'
 
 
+class ConsoleServerPortTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_consoleserverporttemplate'
+    model = ConsoleServerPortTemplate
+    model_form = forms.ConsoleServerPortTemplateForm
+
+
 class ConsoleServerPortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_consoleserverporttemplate'
     queryset = ConsoleServerPortTemplate.objects.all()
@@ -727,6 +739,12 @@ class PowerPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
     template_name = 'dcim/device_component_add.html'
 
 
+class PowerPortTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_powerporttemplate'
+    model = PowerPortTemplate
+    model_form = forms.PowerPortTemplateForm
+
+
 class PowerPortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_powerporttemplate'
     queryset = PowerPortTemplate.objects.all()
@@ -744,6 +762,12 @@ class PowerOutletTemplateCreateView(PermissionRequiredMixin, ComponentCreateView
     template_name = 'dcim/device_component_add.html'
 
 
+class PowerOutletTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_poweroutlettemplate'
+    model = PowerOutletTemplate
+    model_form = forms.PowerOutletTemplateForm
+
+
 class PowerOutletTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_poweroutlettemplate'
     queryset = PowerOutletTemplate.objects.all()
@@ -761,6 +785,12 @@ class InterfaceTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
     template_name = 'dcim/device_component_add.html'
 
 
+class InterfaceTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_interfacetemplate'
+    model = InterfaceTemplate
+    model_form = forms.InterfaceTemplateForm
+
+
 class InterfaceTemplateBulkEditView(PermissionRequiredMixin, BulkEditView):
     permission_required = 'dcim.change_interfacetemplate'
     queryset = InterfaceTemplate.objects.all()
@@ -786,6 +816,12 @@ class FrontPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
     template_name = 'dcim/device_component_add.html'
 
 
+class FrontPortTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_frontporttemplate'
+    model = FrontPortTemplate
+    model_form = forms.FrontPortTemplateForm
+
+
 class FrontPortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_frontporttemplate'
     queryset = FrontPortTemplate.objects.all()
@@ -803,6 +839,12 @@ class RearPortTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
     template_name = 'dcim/device_component_add.html'
 
 
+class RearPortTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_rearporttemplate'
+    model = RearPortTemplate
+    model_form = forms.RearPortTemplateForm
+
+
 class RearPortTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_rearporttemplate'
     queryset = RearPortTemplate.objects.all()
@@ -820,6 +862,12 @@ class DeviceBayTemplateCreateView(PermissionRequiredMixin, ComponentCreateView):
     template_name = 'dcim/device_component_add.html'
 
 
+class DeviceBayTemplateEditView(PermissionRequiredMixin, ObjectEditView):
+    permission_required = 'dcim.change_devicebaytemplate'
+    model = DeviceBayTemplate
+    model_form = forms.DeviceBayTemplateForm
+
+
 class DeviceBayTemplateBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'dcim.delete_devicebaytemplate'
     queryset = DeviceBayTemplate.objects.all()