From 6d242ec3483b7dc1fa7c70b88e1f58716a6b37ef Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 6 Feb 2020 20:46:19 -0500 Subject: [PATCH 1/4] Correct typo --- .../{device_component_list.html => consoleport_list.html} | 5 ++--- netbox/templates/inc/nav_menu.html | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) rename netbox/templates/dcim/{device_component_list.html => consoleport_list.html} (59%) diff --git a/netbox/templates/dcim/device_component_list.html b/netbox/templates/dcim/consoleport_list.html similarity index 59% rename from netbox/templates/dcim/device_component_list.html rename to netbox/templates/dcim/consoleport_list.html index 28322973e..728d1ce71 100644 --- a/netbox/templates/dcim/device_component_list.html +++ b/netbox/templates/dcim/consoleport_list.html @@ -6,11 +6,10 @@
{% export_button content_type %}
-

{% block title %}{{ table.Meta.model|model_name|capfirst }}s{% endblock %}

+

{% block title %}{{ table.Meta.model|model_name_plural|bettertitle }}{% endblock %}

- {% include 'responsive_table.html' %} - {% include 'inc/paginator.html' with paginator=table.paginator page=table.page %} + {% include 'utilities/obj_table.html' %}
{% include 'inc/search_panel.html' %} diff --git a/netbox/templates/inc/nav_menu.html b/netbox/templates/inc/nav_menu.html index a8522eef5..eeb520a57 100644 --- a/netbox/templates/inc/nav_menu.html +++ b/netbox/templates/inc/nav_menu.html @@ -239,7 +239,7 @@
{% endif %} - Power Outlet + Power Outlets {% if perms.dcim.add_devicebay %} From 4563749fd97ca4200715d04a74cb23337073df39 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 6 Feb 2020 20:58:14 -0500 Subject: [PATCH 2/4] Enable bulk edit/delete views for all device components --- netbox/dcim/forms.py | 52 +++++++++++++++++++ netbox/dcim/tests/test_views.py | 14 ++++- netbox/dcim/urls.py | 6 ++- netbox/dcim/views.py | 30 ++++++++--- netbox/templates/dcim/consoleport_list.html | 5 +- .../dcim/consoleserverport_list.html | 17 ++++++ netbox/templates/dcim/devicebay_list.html | 17 ++++++ netbox/templates/dcim/frontport_list.html | 17 ++++++ netbox/templates/dcim/interface_list.html | 17 ++++++ netbox/templates/dcim/poweroutlet_list.html | 17 ++++++ netbox/templates/dcim/powerport_list.html | 17 ++++++ netbox/templates/dcim/rearport_list.html | 17 ++++++ 12 files changed, 211 insertions(+), 15 deletions(-) create mode 100644 netbox/templates/dcim/consoleserverport_list.html create mode 100644 netbox/templates/dcim/devicebay_list.html create mode 100644 netbox/templates/dcim/frontport_list.html create mode 100644 netbox/templates/dcim/interface_list.html create mode 100644 netbox/templates/dcim/poweroutlet_list.html create mode 100644 netbox/templates/dcim/powerport_list.html create mode 100644 netbox/templates/dcim/rearport_list.html diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 9041468d8..b2255fab6 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2371,6 +2371,27 @@ class ConsolePortCreateForm(BootstrapMixin, forms.Form): ) +class ConsolePortBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): + pk = forms.ModelMultipleChoiceField( + queryset=ConsolePort.objects.all(), + widget=forms.MultipleHiddenInput() + ) + type = forms.ChoiceField( + choices=add_blank_choice(ConsolePortTypeChoices), + required=False, + widget=StaticSelect2() + ) + description = forms.CharField( + max_length=100, + required=False + ) + + class Meta: + nullable_fields = ( + 'description', + ) + + class ConsolePortCSVForm(forms.ModelForm): device = FlexibleModelChoiceField( queryset=Device.objects.all(), @@ -2544,6 +2565,37 @@ class PowerPortCreateForm(BootstrapMixin, forms.Form): ) +class PowerPortBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): + pk = forms.ModelMultipleChoiceField( + queryset=PowerPort.objects.all(), + widget=forms.MultipleHiddenInput() + ) + type = forms.ChoiceField( + choices=add_blank_choice(PowerPortTypeChoices), + required=False, + widget=StaticSelect2() + ) + maximum_draw = forms.IntegerField( + min_value=1, + required=False, + help_text="Maximum draw in watts" + ) + allocated_draw = forms.IntegerField( + min_value=1, + required=False, + help_text="Allocated draw in watts" + ) + description = forms.CharField( + max_length=100, + required=False + ) + + class Meta: + nullable_fields = ( + 'description', + ) + + class PowerPortCSVForm(forms.ModelForm): device = FlexibleModelChoiceField( queryset=Device.objects.all(), diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 2f157d96d..f8282833c 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1070,7 +1070,6 @@ class ConsolePortTestCase(StandardTestCases.Views): # Disable inapplicable views test_get_object = None test_create_object = None - test_bulk_edit_objects = None def test_bulk_create_objects(self): return self._test_bulk_create_objects(expected_count=3) @@ -1101,6 +1100,11 @@ class ConsolePortTestCase(StandardTestCases.Views): 'tags': 'Alpha,Bravo,Charlie', } + cls.bulk_edit_data = { + 'type': ConsolePortTypeChoices.TYPE_RJ45, + 'description': 'New description', + } + cls.csv_data = ( "device,name", "Device 1,Console Port 4", @@ -1164,7 +1168,6 @@ class PowerPortTestCase(StandardTestCases.Views): # Disable inapplicable views test_get_object = None - test_bulk_edit_objects = None test_create_object = None def test_bulk_create_objects(self): @@ -1200,6 +1203,13 @@ class PowerPortTestCase(StandardTestCases.Views): 'tags': 'Alpha,Bravo,Charlie', } + cls.bulk_edit_data = { + 'type': PowerPortTypeChoices.TYPE_IEC_C14, + 'maximum_draw': 100, + 'allocated_draw': 50, + 'description': 'New description', + } + cls.csv_data = ( "device,name", "Device 1,Power Port 4", diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 94d1d82ed..07d86cc36 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -178,7 +178,8 @@ urlpatterns = [ path('console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'), path('console-ports/add/', views.ConsolePortCreateView.as_view(), name='consoleport_add'), path('console-ports/import/', views.ConsolePortBulkImportView.as_view(), name='consoleport_import'), - # TODO: Bulk edit, rename, disconnect views for ConsolePorts + path('console-ports/edit/', views.ConsolePortBulkEditView.as_view(), name='consoleport_bulk_edit'), + # TODO: Bulk rename, disconnect views for ConsolePorts path('console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'), path('console-ports//connect//', views.CableCreateView.as_view(), name='consoleport_connect', kwargs={'termination_a_type': ConsolePort}), path('console-ports//edit/', views.ConsolePortEditView.as_view(), name='consoleport_edit'), @@ -204,7 +205,8 @@ urlpatterns = [ path('power-ports/', views.PowerPortListView.as_view(), name='powerport_list'), path('power-ports/add/', views.PowerPortCreateView.as_view(), name='powerport_add'), path('power-ports/import/', views.PowerPortBulkImportView.as_view(), name='powerport_import'), - # TODO: Bulk edit, rename, disconnect views for PowerPorts + path('power-ports/edit/', views.PowerPortBulkEditView.as_view(), name='powerport_bulk_edit'), + # TODO: Bulk rename, disconnect views for PowerPorts path('power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'), path('power-ports//connect//', views.CableCreateView.as_view(), name='powerport_connect', kwargs={'termination_a_type': PowerPort}), path('power-ports//edit/', views.PowerPortEditView.as_view(), name='powerport_edit'), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index f8d6e2211..824961b3e 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1224,7 +1224,7 @@ class ConsolePortListView(PermissionRequiredMixin, ObjectListView): filterset = filters.ConsolePortFilterSet filterset_form = forms.ConsolePortFilterForm table = tables.ConsolePortDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/consoleport_list.html' class ConsolePortCreateView(PermissionRequiredMixin, ComponentCreateView): @@ -1253,6 +1253,13 @@ class ConsolePortBulkImportView(PermissionRequiredMixin, BulkImportView): default_return_url = 'dcim:consoleport_list' +class ConsolePortBulkEditView(PermissionRequiredMixin, BulkEditView): + permission_required = 'dcim.change_consoleport' + queryset = ConsolePort.objects.all() + table = tables.ConsolePortTable + form = forms.ConsolePortBulkEditForm + + class ConsolePortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): permission_required = 'dcim.delete_consoleport' queryset = ConsolePort.objects.all() @@ -1270,7 +1277,7 @@ class ConsoleServerPortListView(PermissionRequiredMixin, ObjectListView): filterset = filters.ConsoleServerPortFilterSet filterset_form = forms.ConsoleServerPortFilterForm table = tables.ConsoleServerPortDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/consoleserverport_list.html' class ConsoleServerPortCreateView(PermissionRequiredMixin, ComponentCreateView): @@ -1335,7 +1342,7 @@ class PowerPortListView(PermissionRequiredMixin, ObjectListView): filterset = filters.PowerPortFilterSet filterset_form = forms.PowerPortFilterForm table = tables.PowerPortDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/powerport_list.html' class PowerPortCreateView(PermissionRequiredMixin, ComponentCreateView): @@ -1364,6 +1371,13 @@ class PowerPortBulkImportView(PermissionRequiredMixin, BulkImportView): default_return_url = 'dcim:powerport_list' +class PowerPortBulkEditView(PermissionRequiredMixin, BulkEditView): + permission_required = 'dcim.change_powerport' + queryset = PowerPort.objects.all() + table = tables.PowerPortTable + form = forms.PowerPortBulkEditForm + + class PowerPortBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): permission_required = 'dcim.delete_powerport' queryset = PowerPort.objects.all() @@ -1381,7 +1395,7 @@ class PowerOutletListView(PermissionRequiredMixin, ObjectListView): filterset = filters.PowerOutletFilterSet filterset_form = forms.PowerOutletFilterForm table = tables.PowerOutletDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/poweroutlet_list.html' class PowerOutletCreateView(PermissionRequiredMixin, ComponentCreateView): @@ -1446,7 +1460,7 @@ class InterfaceListView(PermissionRequiredMixin, ObjectListView): filterset = filters.InterfaceFilterSet filterset_form = forms.InterfaceFilterForm table = tables.InterfaceDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/interface_list.html' class InterfaceView(PermissionRequiredMixin, View): @@ -1548,7 +1562,7 @@ class FrontPortListView(PermissionRequiredMixin, ObjectListView): filterset = filters.FrontPortFilterSet filterset_form = forms.FrontPortFilterForm table = tables.FrontPortDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/frontport_list.html' class FrontPortCreateView(PermissionRequiredMixin, ComponentCreateView): @@ -1613,7 +1627,7 @@ class RearPortListView(PermissionRequiredMixin, ObjectListView): filterset = filters.RearPortFilterSet filterset_form = forms.RearPortFilterForm table = tables.RearPortDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/rearport_list.html' class RearPortCreateView(PermissionRequiredMixin, ComponentCreateView): @@ -1680,7 +1694,7 @@ class DeviceBayListView(PermissionRequiredMixin, ObjectListView): filterset = filters.DeviceBayFilterSet filterset_form = forms.DeviceBayFilterForm table = tables.DeviceBayDetailTable - template_name = 'dcim/device_component_list.html' + template_name = 'dcim/devicebay_list.html' class DeviceBayCreateView(PermissionRequiredMixin, ComponentCreateView): diff --git a/netbox/templates/dcim/consoleport_list.html b/netbox/templates/dcim/consoleport_list.html index 728d1ce71..0ed840820 100644 --- a/netbox/templates/dcim/consoleport_list.html +++ b/netbox/templates/dcim/consoleport_list.html @@ -1,15 +1,14 @@ {% extends '_base.html' %} {% load buttons %} -{% load helpers %} {% block content %}
{% export_button content_type %}
-

{% block title %}{{ table.Meta.model|model_name_plural|bettertitle }}{% endblock %}

+

{% block title %}Console Ports{% endblock %}

- {% include 'utilities/obj_table.html' %} + {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:consoleport_bulk_edit' bulk_delete_url='dcim:consoleport_bulk_delete' %}
{% include 'inc/search_panel.html' %} diff --git a/netbox/templates/dcim/consoleserverport_list.html b/netbox/templates/dcim/consoleserverport_list.html new file mode 100644 index 000000000..47a8676e3 --- /dev/null +++ b/netbox/templates/dcim/consoleserverport_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Console Server Ports{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:consoleserverport_bulk_edit' bulk_delete_url='dcim:consoleserverport_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/devicebay_list.html b/netbox/templates/dcim/devicebay_list.html new file mode 100644 index 000000000..74f64858a --- /dev/null +++ b/netbox/templates/dcim/devicebay_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Device Bays{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_delete_url='dcim:devicebay_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/frontport_list.html b/netbox/templates/dcim/frontport_list.html new file mode 100644 index 000000000..a3334b876 --- /dev/null +++ b/netbox/templates/dcim/frontport_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Front Ports{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:frontport_bulk_edit' bulk_delete_url='dcim:frontport_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/interface_list.html b/netbox/templates/dcim/interface_list.html new file mode 100644 index 000000000..9dd8f7858 --- /dev/null +++ b/netbox/templates/dcim/interface_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Interfaces{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:interface_bulk_edit' bulk_delete_url='dcim:interface_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/poweroutlet_list.html b/netbox/templates/dcim/poweroutlet_list.html new file mode 100644 index 000000000..2e842d699 --- /dev/null +++ b/netbox/templates/dcim/poweroutlet_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Power Outlets{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:poweroutlet_bulk_edit' bulk_delete_url='dcim:poweroutlet_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/powerport_list.html b/netbox/templates/dcim/powerport_list.html new file mode 100644 index 000000000..b5830edca --- /dev/null +++ b/netbox/templates/dcim/powerport_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Power Ports{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:powerport_bulk_edit' bulk_delete_url='dcim:powerport_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} diff --git a/netbox/templates/dcim/rearport_list.html b/netbox/templates/dcim/rearport_list.html new file mode 100644 index 000000000..cc603d620 --- /dev/null +++ b/netbox/templates/dcim/rearport_list.html @@ -0,0 +1,17 @@ +{% extends '_base.html' %} +{% load buttons %} + +{% block content %} +
+ {% export_button content_type %} +
+

{% block title %}Rear Ports{% endblock %}

+
+
+ {% include 'utilities/obj_table.html' with bulk_edit_url='dcim:rearport_bulk_edit' bulk_delete_url='dcim:rearport_bulk_delete' %} +
+
+ {% include 'inc/search_panel.html' %} +
+
+{% endblock %} From 52257467c377da31fdf6886af7a115a9a0529cc3 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 6 Feb 2020 21:44:28 -0500 Subject: [PATCH 3/4] Tweak bulk edit views to dynamically remove device-dependent fields --- netbox/dcim/forms.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index b2255fab6..0877dfbf7 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2747,6 +2747,7 @@ class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): ) device = forms.ModelChoiceField( queryset=Device.objects.all(), + required=False, widget=forms.HiddenInput() ) type = forms.ChoiceField( @@ -2778,6 +2779,9 @@ class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): if 'device' in self.initial: device = Device.objects.filter(pk=self.initial['device']).first() self.fields['power_port'].queryset = PowerPort.objects.filter(device=device) + else: + self.fields['power_port'].choices = () + self.fields['power_port'].widget.attrs['disabled'] = True class PowerOutletBulkRenameForm(BulkRenameForm): @@ -3021,6 +3025,7 @@ class InterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): ) device = forms.ModelChoiceField( queryset=Device.objects.all(), + required=False, widget=forms.HiddenInput() ) type = forms.ChoiceField( @@ -3096,6 +3101,9 @@ class InterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): device__in=[device, device.get_vc_master()], type=InterfaceTypeChoices.TYPE_LAG ) + else: + self.fields['lag'].choices = () + self.fields['lag'].widget.attrs['disabled'] = True def clean(self): From 4cc9f2f67de7602ae79f4faedac6766715a88c77 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 6 Feb 2020 21:52:10 -0500 Subject: [PATCH 4/4] Changelog for #4116 --- docs/release-notes/version-2.7.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/release-notes/version-2.7.md b/docs/release-notes/version-2.7.md index cce66932d..35580a1d0 100644 --- a/docs/release-notes/version-2.7.md +++ b/docs/release-notes/version-2.7.md @@ -3,6 +3,7 @@ ## Enhancements * [#4113](https://github.com/netbox-community/netbox/issues/4113) - Add bulk edit functionality for device type components +* [#4116](https://github.com/netbox-community/netbox/issues/4116) - Enable bulk edit and delete functions for device component list views ## Bug Fixes