diff --git a/docs/release-notes/version-2.7.md b/docs/release-notes/version-2.7.md index b1b2c0807..440ddfbee 100644 --- a/docs/release-notes/version-2.7.md +++ b/docs/release-notes/version-2.7.md @@ -12,6 +12,7 @@ * [#4381](https://github.com/netbox-community/netbox/issues/4381) - Enable export templates for rack reservations * [#4382](https://github.com/netbox-community/netbox/issues/4382) - Enable custom links for rack reservations * [#4386](https://github.com/netbox-community/netbox/issues/4386) - Update admin links for Django RQ to reflect multiple queues +* [#4389](https://github.com/netbox-community/netbox/issues/4389) - Add a bulk edit view for device bays ### Bug Fixes diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index f08ad4363..311a8e69e 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -3982,6 +3982,22 @@ class PopulateDeviceBayForm(BootstrapMixin, forms.Form): ).exclude(pk=device_bay.device.pk) +class DeviceBayBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm): + pk = forms.ModelMultipleChoiceField( + queryset=DeviceBay.objects.all(), + widget=forms.MultipleHiddenInput() + ) + description = forms.CharField( + max_length=100, + required=False + ) + + class Meta: + nullable_fields = ( + 'description', + ) + + class DeviceBayCSVForm(forms.ModelForm): device = FlexibleModelChoiceField( queryset=Device.objects.all(), diff --git a/netbox/dcim/tables.py b/netbox/dcim/tables.py index 816318126..e3675ae97 100644 --- a/netbox/dcim/tables.py +++ b/netbox/dcim/tables.py @@ -857,7 +857,7 @@ class DeviceBayTable(BaseTable): class Meta(BaseTable.Meta): model = DeviceBay - fields = ('name',) + fields = ('name', 'description') class DeviceBayDetailTable(DeviceComponentDetailTable): @@ -865,8 +865,8 @@ class DeviceBayDetailTable(DeviceComponentDetailTable): installed_device = tables.LinkColumn() class Meta(DeviceBayTable.Meta): - fields = ('pk', 'name', 'device', 'installed_device') - sequence = ('pk', 'name', 'device', 'installed_device') + fields = ('pk', 'name', 'device', 'installed_device', 'description') + sequence = ('pk', 'name', 'device', 'installed_device', 'description') exclude = ('cable',) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 68ecda6e8..dbdb1526e 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -1329,37 +1329,37 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase): class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase): model = DeviceBay - # Disable inapplicable views - test_bulk_edit_objects = None - @classmethod def setUpTestData(cls): - device1 = create_test_device('Device 1') - device2 = create_test_device('Device 2') + device = create_test_device('Device 1') # Update the DeviceType subdevice role to allow adding DeviceBays DeviceType.objects.update(subdevice_role=SubdeviceRoleChoices.ROLE_PARENT) DeviceBay.objects.bulk_create([ - DeviceBay(device=device1, name='Device Bay 1'), - DeviceBay(device=device1, name='Device Bay 2'), - DeviceBay(device=device1, name='Device Bay 3'), + DeviceBay(device=device, name='Device Bay 1'), + DeviceBay(device=device, name='Device Bay 2'), + DeviceBay(device=device, name='Device Bay 3'), ]) cls.form_data = { - 'device': device2.pk, + 'device': device.pk, 'name': 'Device Bay X', 'description': 'A device bay', 'tags': 'Alpha,Bravo,Charlie', } cls.bulk_create_data = { - 'device': device2.pk, + 'device': device.pk, 'name_pattern': 'Device Bay [4-6]', 'description': 'A device bay', 'tags': 'Alpha,Bravo,Charlie', } + cls.bulk_edit_data = { + 'description': 'New description', + } + cls.csv_data = ( "device,name", "Device 1,Device Bay 4", diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index 05f0aa9c2..c62800386 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -284,7 +284,7 @@ urlpatterns = [ path('device-bays/', views.DeviceBayListView.as_view(), name='devicebay_list'), path('device-bays/add/', views.DeviceBayCreateView.as_view(), name='devicebay_add'), path('device-bays/import/', views.DeviceBayBulkImportView.as_view(), name='devicebay_import'), - # TODO: Bulk edit view for DeviceBays + path('device-bays/edit/', views.DeviceBayBulkEditView.as_view(), name='devicebay_bulk_edit'), path('device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'), path('device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'), path('device-bays//edit/', views.DeviceBayEditView.as_view(), name='devicebay_edit'), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index dc4fda7c3..2bfd6df98 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -1893,6 +1893,14 @@ class DeviceBayBulkImportView(PermissionRequiredMixin, BulkImportView): default_return_url = 'dcim:devicebay_list' +class DeviceBayBulkEditView(PermissionRequiredMixin, BulkEditView): + permission_required = 'dcim.change_devicebay' + queryset = DeviceBay.objects.all() + filterset = filters.DeviceBayFilterSet + table = tables.DeviceBayTable + form = forms.DeviceBayBulkEditForm + + class DeviceBayBulkRenameView(PermissionRequiredMixin, BulkRenameView): permission_required = 'dcim.change_devicebay' queryset = DeviceBay.objects.all()