1313from users .models import User
1414from utilities .forms import BulkEditForm , add_blank_choice , form_from_model
1515from utilities .forms .fields import ColorField , CommentField , DynamicModelChoiceField , DynamicModelMultipleChoiceField
16- from utilities .forms .rendering import FieldSet , InlineFields
16+ from utilities .forms .rendering import FieldSet , InlineFields , TabbedGroups
1717from utilities .forms .widgets import BulkEditNullBooleanSelect , NumberWithOptions
1818from wireless .models import WirelessLAN , WirelessLANGroup
1919from wireless .choices import WirelessRoleChoices
@@ -1404,18 +1404,25 @@ class InterfaceBulkEditForm(
14041404 parent = DynamicModelChoiceField (
14051405 label = _ ('Parent' ),
14061406 queryset = Interface .objects .all (),
1407- required = False
1407+ required = False ,
1408+ query_params = {
1409+ 'virtual_chassis_member_id' : '$device' ,
1410+ }
14081411 )
14091412 bridge = DynamicModelChoiceField (
14101413 label = _ ('Bridge' ),
14111414 queryset = Interface .objects .all (),
1412- required = False
1415+ required = False ,
1416+ query_params = {
1417+ 'virtual_chassis_member_id' : '$device' ,
1418+ }
14131419 )
14141420 lag = DynamicModelChoiceField (
14151421 queryset = Interface .objects .all (),
14161422 required = False ,
14171423 query_params = {
14181424 'type' : 'lag' ,
1425+ 'virtual_chassis_member_id' : '$device' ,
14191426 },
14201427 label = _ ('LAG' )
14211428 )
@@ -1472,6 +1479,7 @@ class InterfaceBulkEditForm(
14721479 required = False ,
14731480 query_params = {
14741481 'group_id' : '$vlan_group' ,
1482+ 'available_on_device' : '$device' ,
14751483 },
14761484 label = _ ('Untagged VLAN' )
14771485 )
@@ -1480,9 +1488,28 @@ class InterfaceBulkEditForm(
14801488 required = False ,
14811489 query_params = {
14821490 'group_id' : '$vlan_group' ,
1491+ 'available_on_device' : '$device' ,
14831492 },
14841493 label = _ ('Tagged VLANs' )
14851494 )
1495+ add_tagged_vlans = DynamicModelMultipleChoiceField (
1496+ label = _ ('Add tagged VLANs' ),
1497+ queryset = VLAN .objects .all (),
1498+ required = False ,
1499+ query_params = {
1500+ 'group_id' : '$vlan_group' ,
1501+ 'available_on_device' : '$device' ,
1502+ },
1503+ )
1504+ remove_tagged_vlans = DynamicModelMultipleChoiceField (
1505+ label = _ ('Remove tagged VLANs' ),
1506+ queryset = VLAN .objects .all (),
1507+ required = False ,
1508+ query_params = {
1509+ 'group_id' : '$vlan_group' ,
1510+ 'available_on_device' : '$device' ,
1511+ }
1512+ )
14861513 vrf = DynamicModelChoiceField (
14871514 queryset = VRF .objects .all (),
14881515 required = False ,
@@ -1509,7 +1536,13 @@ class InterfaceBulkEditForm(
15091536 FieldSet ('vdcs' , 'mtu' , 'tx_power' , 'enabled' , 'mgmt_only' , 'mark_connected' , name = _ ('Operation' )),
15101537 FieldSet ('poe_mode' , 'poe_type' , name = _ ('PoE' )),
15111538 FieldSet ('parent' , 'bridge' , 'lag' , name = _ ('Related Interfaces' )),
1512- FieldSet ('mode' , 'vlan_group' , 'untagged_vlan' , 'tagged_vlans' , name = _ ('802.1Q Switching' )),
1539+ FieldSet ('mode' , 'vlan_group' , 'untagged_vlan' , name = _ ('802.1Q Switching' )),
1540+ FieldSet (
1541+ TabbedGroups (
1542+ FieldSet ('tagged_vlans' , name = _ ('Assignment' )),
1543+ FieldSet ('add_tagged_vlans' , 'remove_tagged_vlans' , name = _ ('Add/Remove' )),
1544+ ),
1545+ ),
15131546 FieldSet (
15141547 'rf_role' , 'rf_channel' , 'rf_channel_frequency' , 'rf_channel_width' , 'wireless_lan_group' , 'wireless_lans' ,
15151548 name = _ ('Wireless' )
@@ -1523,19 +1556,7 @@ class InterfaceBulkEditForm(
15231556
15241557 def __init__ (self , * args , ** kwargs ):
15251558 super ().__init__ (* args , ** kwargs )
1526- if self .device_id :
1527- device = Device .objects .filter (pk = self .device_id ).first ()
1528-
1529- # Restrict parent/bridge/LAG interface assignment by device
1530- self .fields ['parent' ].widget .add_query_param ('virtual_chassis_member_id' , device .pk )
1531- self .fields ['bridge' ].widget .add_query_param ('virtual_chassis_member_id' , device .pk )
1532- self .fields ['lag' ].widget .add_query_param ('virtual_chassis_member_id' , device .pk )
1533-
1534- # Limit VLAN choices by device
1535- self .fields ['untagged_vlan' ].widget .add_query_param ('available_on_device' , device .pk )
1536- self .fields ['tagged_vlans' ].widget .add_query_param ('available_on_device' , device .pk )
1537-
1538- else :
1559+ if not self .device_id :
15391560 # See #4523
15401561 if 'pk' in self .initial :
15411562 site = None
@@ -1559,6 +1580,13 @@ def __init__(self, *args, **kwargs):
15591580 'site_id' , [site .pk , settings .FILTERS_NULL_CHOICE_VALUE ]
15601581 )
15611582
1583+ self .fields ['add_tagged_vlans' ].widget .add_query_param (
1584+ 'site_id' , [site .pk , settings .FILTERS_NULL_CHOICE_VALUE ]
1585+ )
1586+ self .fields ['remove_tagged_vlans' ].widget .add_query_param (
1587+ 'site_id' , [site .pk , settings .FILTERS_NULL_CHOICE_VALUE ]
1588+ )
1589+
15621590 self .fields ['parent' ].choices = ()
15631591 self .fields ['parent' ].widget .attrs ['disabled' ] = True
15641592 self .fields ['bridge' ].choices = ()
0 commit comments