Skip to content

Commit

Permalink
Allow adding/removing tagged VLANs in bulk editing of Interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
bctiemann committed Sep 17, 2024
1 parent 3000407 commit e66695b
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 16 deletions.
54 changes: 38 additions & 16 deletions netbox/dcim/forms/bulk_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1404,18 +1404,25 @@ class InterfaceBulkEditForm(
parent = DynamicModelChoiceField(
label=_('Parent'),
queryset=Interface.objects.all(),
required=False
required=False,
query_params={
'virtual_chassis_member_id': '$device',
}
)
bridge = DynamicModelChoiceField(
label=_('Bridge'),
queryset=Interface.objects.all(),
required=False
required=False,
query_params={
'virtual_chassis_member_id': '$device',
}
)
lag = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False,
query_params={
'type': 'lag',
'virtual_chassis_member_id': '$device',
},
label=_('LAG')
)
Expand Down Expand Up @@ -1472,6 +1479,7 @@ class InterfaceBulkEditForm(
required=False,
query_params={
'group_id': '$vlan_group',
'available_on_device': '$device',
},
label=_('Untagged VLAN')
)
Expand All @@ -1480,9 +1488,28 @@ class InterfaceBulkEditForm(
required=False,
query_params={
'group_id': '$vlan_group',
'available_on_device': '$device',
},
label=_('Tagged VLANs')
)
add_tagged_vlans = DynamicModelMultipleChoiceField(
label=_('Add tagged VLANs'),
queryset=VLAN.objects.all(),
required=False,
query_params={
'group_id': '$vlan_group',
'available_on_device': '$device',
},
)
remove_tagged_vlans = DynamicModelMultipleChoiceField(
label=_('Remove tagged VLANs'),
queryset=VLAN.objects.all(),
required=False,
query_params={
'group_id': '$vlan_group',
'available_on_device': '$device',
}
)
vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
Expand All @@ -1509,7 +1536,7 @@ class InterfaceBulkEditForm(
FieldSet('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected', name=_('Operation')),
FieldSet('poe_mode', 'poe_type', name=_('PoE')),
FieldSet('parent', 'bridge', 'lag', name=_('Related Interfaces')),
FieldSet('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans', name=_('802.1Q Switching')),
FieldSet('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans', 'add_tagged_vlans', 'remove_tagged_vlans', name=_('802.1Q Switching')),
FieldSet(
'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'wireless_lan_group', 'wireless_lans',
name=_('Wireless')
Expand All @@ -1523,19 +1550,7 @@ class InterfaceBulkEditForm(

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.device_id:
device = Device.objects.filter(pk=self.device_id).first()

# Restrict parent/bridge/LAG interface assignment by device
self.fields['parent'].widget.add_query_param('virtual_chassis_member_id', device.pk)
self.fields['bridge'].widget.add_query_param('virtual_chassis_member_id', device.pk)
self.fields['lag'].widget.add_query_param('virtual_chassis_member_id', device.pk)

# Limit VLAN choices by device
self.fields['untagged_vlan'].widget.add_query_param('available_on_device', device.pk)
self.fields['tagged_vlans'].widget.add_query_param('available_on_device', device.pk)

else:
if not self.device_id:
# See #4523
if 'pk' in self.initial:
site = None
Expand All @@ -1559,6 +1574,13 @@ def __init__(self, *args, **kwargs):
'site_id', [site.pk, settings.FILTERS_NULL_CHOICE_VALUE]
)

self.fields['add_tagged_vlans'].widget.add_query_param(
'site_id', [site.pk, settings.FILTERS_NULL_CHOICE_VALUE]
)
self.fields['remove_tagged_vlans'].widget.add_query_param(
'site_id', [site.pk, settings.FILTERS_NULL_CHOICE_VALUE]
)

self.fields['parent'].choices = ()
self.fields['parent'].widget.attrs['disabled'] = True
self.fields['bridge'].choices = ()
Expand Down
6 changes: 6 additions & 0 deletions netbox/netbox/views/generic/bulk_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,12 @@ def _update_objects(self, form, request):
if form.cleaned_data.get('remove_tags', None):
obj.tags.remove(*form.cleaned_data['remove_tags'])

# Add/remove tagged VLANs
if form.cleaned_data.get('add_tagged_vlans', None):
obj.tagged_vlans.add(*form.cleaned_data['add_tagged_vlans'])
if form.cleaned_data.get('remove_tagged_vlans', None):
obj.tagged_vlans.remove(*form.cleaned_data['remove_tagged_vlans'])

# Rebuild the tree for MPTT models
if issubclass(self.queryset.model, MPTTModel):
self.queryset.model.objects.rebuild()
Expand Down

0 comments on commit e66695b

Please sign in to comment.