diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 654459fce..dccca1bdf 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -7,6 +7,7 @@ from dcim.choices import * from dcim.constants import * from dcim.models import * from extras.models import ConfigTemplate +from ipam.choices import VLANQinQRoleChoices from ipam.models import ASN, VLAN, VLANGroup, VRF from netbox.choices import * from netbox.forms import NetBoxModelBulkEditForm @@ -1522,6 +1523,16 @@ class InterfaceBulkEditForm( 'available_on_device': '$device', } ) + qinq_svlan = DynamicModelChoiceField( + queryset=VLAN.objects.all(), + required=False, + label=_('Q-in-Q Service VLAN'), + query_params={ + 'group_id': '$vlan_group', + 'available_on_device': '$device', + 'qinq_role': VLANQinQRoleChoices.ROLE_SERVICE, + } + ) vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, @@ -1548,7 +1559,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', name=_('802.1Q Switching')), + FieldSet('mode', 'vlan_group', 'untagged_vlan', 'qinq_svlan', name=_('802.1Q Switching')), FieldSet( TabbedGroups( FieldSet('tagged_vlans', name=_('Assignment')), @@ -1563,7 +1574,7 @@ class InterfaceBulkEditForm( nullable_fields = ( 'module', 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'wwn', 'vdcs', 'mtu', 'description', 'poe_mode', 'poe_type', 'mode', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', - 'untagged_vlan', 'tagged_vlans', 'vrf', 'wireless_lans' + 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'vrf', 'wireless_lans' ) def __init__(self, *args, **kwargs): diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 3e6d87ff0..d6fdb21e2 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -1395,7 +1395,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): 'available_on_device': '$device', } ) - qinq_svlan = DynamicModelMultipleChoiceField( + qinq_svlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, label=_('Q-in-Q Service VLAN'), diff --git a/netbox/ipam/choices.py b/netbox/ipam/choices.py index 4d9c0bdd4..51b65a6da 100644 --- a/netbox/ipam/choices.py +++ b/netbox/ipam/choices.py @@ -159,8 +159,8 @@ class VLANStatusChoices(ChoiceSet): class VLANQinQRoleChoices(ChoiceSet): - ROLE_SERVICE = 's-vlan' - ROLE_CUSTOMER = 'c-vlan' + ROLE_SERVICE = 'svlan' + ROLE_CUSTOMER = 'cvlan' CHOICES = [ (ROLE_SERVICE, _('Service'), 'blue'), diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index e8d48de7c..0b37665d5 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -459,7 +459,7 @@ class VLANImportForm(NetBoxModelImportForm): ) qinq_role = CSVChoiceField( label=_('Q-in-Q role'), - choices=VLANStatusChoices, + choices=VLANQinQRoleChoices, required=False, help_text=_('Operational status') ) diff --git a/netbox/templates/dcim/interface.html b/netbox/templates/dcim/interface.html index 1658dd37e..510780dd9 100644 --- a/netbox/templates/dcim/interface.html +++ b/netbox/templates/dcim/interface.html @@ -81,6 +81,12 @@