Fixes #13843: Fix assignment of VLAN group scope during bulk edit (#13887)

* Update VLANGroup bulk edit form to support all scope types

* Fixes #13843: Fix scope assignment for VLAN groups during bulk edit

* Add missed static file

* Restore graphiql static assets
This commit is contained in:
Jeremy Stretch 2023-09-26 13:09:20 -04:00 committed by GitHub
parent b759d694ee
commit 1ad6d94dc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 9 deletions

View File

@ -1,7 +1,8 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from dcim.models import Region, Site, SiteGroup from dcim.models import Location, Rack, Region, Site, SiteGroup
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.models import * from ipam.models import *
@ -10,9 +11,10 @@ from netbox.forms import NetBoxModelBulkEditForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import add_blank_choice from utilities.forms import add_blank_choice
from utilities.forms.fields import ( from utilities.forms.fields import (
CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField, CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
) )
from utilities.forms.widgets import BulkEditNullBooleanSelect from utilities.forms.widgets import BulkEditNullBooleanSelect
from virtualization.models import Cluster, ClusterGroup
__all__ = ( __all__ = (
'AggregateBulkEditForm', 'AggregateBulkEditForm',
@ -407,11 +409,6 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm):
class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
site = DynamicModelChoiceField(
label=_('Site'),
queryset=Site.objects.all(),
required=False
)
min_vid = forms.IntegerField( min_vid = forms.IntegerField(
min_value=VLAN_VID_MIN, min_value=VLAN_VID_MIN,
max_value=VLAN_VID_MAX, max_value=VLAN_VID_MAX,
@ -429,12 +426,84 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=200, max_length=200,
required=False required=False
) )
scope_type = ContentTypeChoiceField(
label=_('Scope type'),
queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
required=False
)
scope_id = forms.IntegerField(
required=False,
widget=forms.HiddenInput()
)
region = DynamicModelChoiceField(
label=_('Region'),
queryset=Region.objects.all(),
required=False
)
sitegroup = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label=_('Site group')
)
site = DynamicModelChoiceField(
label=_('Site'),
queryset=Site.objects.all(),
required=False,
query_params={
'region_id': '$region',
'group_id': '$sitegroup',
}
)
location = DynamicModelChoiceField(
label=_('Location'),
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site',
}
)
rack = DynamicModelChoiceField(
label=_('Rack'),
queryset=Rack.objects.all(),
required=False,
query_params={
'site_id': '$site',
'location_id': '$location',
}
)
clustergroup = DynamicModelChoiceField(
queryset=ClusterGroup.objects.all(),
required=False,
label=_('Cluster group')
)
cluster = DynamicModelChoiceField(
label=_('Cluster'),
queryset=Cluster.objects.all(),
required=False,
query_params={
'group_id': '$clustergroup',
}
)
model = VLANGroup model = VLANGroup
fieldsets = ( fieldsets = (
(None, ('site', 'min_vid', 'max_vid', 'description')), (None, ('site', 'min_vid', 'max_vid', 'description')),
(_('Scope'), ('scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster')),
) )
nullable_fields = ('site', 'description') nullable_fields = ('description',)
def clean(self):
super().clean()
# Assign scope based on scope_type
if self.cleaned_data.get('scope_type'):
scope_field = self.cleaned_data['scope_type'].model
if scope_obj := self.cleaned_data.get(scope_field):
self.cleaned_data['scope_id'] = scope_obj.pk
self.changed_data.append('scope_id')
else:
self.cleaned_data.pop('scope_type')
self.changed_data.remove('scope_type')
class VLANBulkEditForm(NetBoxModelBulkEditForm): class VLANBulkEditForm(NetBoxModelBulkEditForm):

View File

@ -3,6 +3,7 @@ import re
from copy import deepcopy from copy import deepcopy
from django.contrib import messages from django.contrib import messages
from django.contrib.contenttypes.fields import GenericRel
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
from django.db import transaction, IntegrityError from django.db import transaction, IntegrityError
@ -519,9 +520,11 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView):
model_field = self.queryset.model._meta.get_field(name) model_field = self.queryset.model._meta.get_field(name)
if isinstance(model_field, (ManyToManyField, ManyToManyRel)): if isinstance(model_field, (ManyToManyField, ManyToManyRel)):
m2m_fields[name] = model_field m2m_fields[name] = model_field
elif isinstance(model_field, GenericRel):
# Ignore generic relations (these may be used for other purposes in the form)
continue
else: else:
model_fields[name] = model_field model_fields[name] = model_field
except FieldDoesNotExist: except FieldDoesNotExist:
# This form field is used to modify a field rather than set its value directly # This form field is used to modify a field rather than set its value directly
model_fields[name] = None model_fields[name] = None

Binary file not shown.

Binary file not shown.

View File

@ -88,6 +88,7 @@ const showHideLayout: ShowHideLayout = {
const showHideMap: ShowHideMap = { const showHideMap: ShowHideMap = {
vlangroup_add: 'vlangroup', vlangroup_add: 'vlangroup',
vlangroup_edit: 'vlangroup', vlangroup_edit: 'vlangroup',
vlangroup_bulk_edit: 'vlangroup',
}; };
/** /**