mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
Closes #8667: Support position patterning when creating module bays & templates
This commit is contained in:
parent
6604ebfd01
commit
a2fe23549b
@ -8,11 +8,13 @@ from utilities.forms import (
|
||||
)
|
||||
|
||||
__all__ = (
|
||||
'ModularComponentTemplateCreateForm',
|
||||
'DeviceComponentCreateForm',
|
||||
'ComponentTemplateCreateForm',
|
||||
'DeviceComponentCreateForm',
|
||||
'FrontPortCreateForm',
|
||||
'FrontPortTemplateCreateForm',
|
||||
'ModularComponentTemplateCreateForm',
|
||||
'ModuleBayCreateForm',
|
||||
'ModuleBayTemplateCreateForm',
|
||||
'VirtualChassisCreateForm',
|
||||
)
|
||||
|
||||
@ -34,14 +36,17 @@ class ComponentCreateForm(BootstrapMixin, forms.Form):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
# Validate that the number of components being created from both the name_pattern and label_pattern are equal
|
||||
if self.cleaned_data['label_pattern']:
|
||||
name_pattern_count = len(self.cleaned_data['name_pattern'])
|
||||
label_pattern_count = len(self.cleaned_data['label_pattern'])
|
||||
if name_pattern_count != label_pattern_count:
|
||||
# Validate that all patterned fields generate an equal number of values
|
||||
patterned_fields = [
|
||||
field_name for field_name in self.fields if field_name.endswith('_pattern')
|
||||
]
|
||||
pattern_count = len(self.cleaned_data['name_pattern'])
|
||||
for field_name in patterned_fields:
|
||||
value_count = len(self.cleaned_data[field_name])
|
||||
if self.cleaned_data[field_name] and value_count != pattern_count:
|
||||
raise forms.ValidationError({
|
||||
'label_pattern': f'The provided name pattern will create {name_pattern_count} components, however '
|
||||
f'{label_pattern_count} labels will be generated. These counts must match.'
|
||||
field_name: f'The provided pattern specifies {value_count} values, but {pattern_count} are '
|
||||
f'expected.'
|
||||
}, code='label_pattern_mismatch')
|
||||
|
||||
|
||||
@ -176,6 +181,24 @@ class FrontPortCreateForm(DeviceComponentCreateForm):
|
||||
}
|
||||
|
||||
|
||||
class ModuleBayTemplateCreateForm(ComponentTemplateCreateForm):
|
||||
position_pattern = ExpandableNameField(
|
||||
label='Position',
|
||||
required=False,
|
||||
help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)'
|
||||
)
|
||||
field_order = ('device_type', 'name_pattern', 'label_pattern', 'position_pattern')
|
||||
|
||||
|
||||
class ModuleBayCreateForm(DeviceComponentCreateForm):
|
||||
position_pattern = ExpandableNameField(
|
||||
label='Position',
|
||||
required=False,
|
||||
help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)'
|
||||
)
|
||||
field_order = ('device', 'name_pattern', 'label_pattern', 'position_pattern')
|
||||
|
||||
|
||||
class VirtualChassisCreateForm(NetBoxModelForm):
|
||||
region = DynamicModelChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
|
@ -744,8 +744,8 @@ class DeviceModuleBayTable(ModuleBayTable):
|
||||
|
||||
class Meta(DeviceComponentTable.Meta):
|
||||
model = ModuleBay
|
||||
fields = ('pk', 'id', 'name', 'label', 'description', 'installed_module', 'tags', 'actions')
|
||||
default_columns = ('pk', 'name', 'label', 'description', 'installed_module')
|
||||
fields = ('pk', 'id', 'name', 'label', 'position', 'installed_module', 'description', 'tags', 'actions')
|
||||
default_columns = ('pk', 'name', 'label', 'installed_module', 'description')
|
||||
|
||||
|
||||
class InventoryItemTable(DeviceComponentTable):
|
||||
|
@ -1324,9 +1324,10 @@ class RearPortTemplateBulkDeleteView(generic.BulkDeleteView):
|
||||
|
||||
class ModuleBayTemplateCreateView(generic.ComponentCreateView):
|
||||
queryset = ModuleBayTemplate.objects.all()
|
||||
form = forms.ComponentTemplateCreateForm
|
||||
form = forms.ModuleBayTemplateCreateForm
|
||||
model_form = forms.ModuleBayTemplateForm
|
||||
template_name = 'dcim/component_template_create.html'
|
||||
template_name = 'dcim/modulebaytemplate_create.html'
|
||||
patterned_fields = ('name', 'label', 'position')
|
||||
|
||||
|
||||
class ModuleBayTemplateEditView(generic.ObjectEditView):
|
||||
@ -2304,8 +2305,9 @@ class ModuleBayView(generic.ObjectView):
|
||||
|
||||
class ModuleBayCreateView(generic.ComponentCreateView):
|
||||
queryset = ModuleBay.objects.all()
|
||||
form = forms.DeviceComponentCreateForm
|
||||
form = forms.ModuleBayCreateForm
|
||||
model_form = forms.ModuleBayForm
|
||||
patterned_fields = ('name', 'label', 'position')
|
||||
|
||||
|
||||
class ModuleBayEditView(generic.ObjectEditView):
|
||||
|
@ -587,14 +587,12 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
|
||||
if form.is_valid():
|
||||
new_components = []
|
||||
data = deepcopy(request.POST)
|
||||
names = form.cleaned_data['name_pattern']
|
||||
labels = form.cleaned_data.get('label_pattern')
|
||||
pattern_count = len(form.cleaned_data[f'{self.patterned_fields[0]}_pattern'])
|
||||
|
||||
for i, name in enumerate(names):
|
||||
label = labels[i] if labels else None
|
||||
# Initialize the individual component form
|
||||
data['name'] = name
|
||||
data['label'] = label
|
||||
for i in range(pattern_count):
|
||||
for field_name in self.patterned_fields:
|
||||
if form.cleaned_data.get(f'{field_name}_pattern'):
|
||||
data[field_name] = form.cleaned_data[f'{field_name}_pattern'][i]
|
||||
|
||||
if hasattr(form, 'get_iterative_data'):
|
||||
data.update(form.get_iterative_data(i))
|
||||
|
7
netbox/templates/dcim/modulebaytemplate_create.html
Normal file
7
netbox/templates/dcim/modulebaytemplate_create.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% extends 'dcim/component_template_create.html' %}
|
||||
{% load form_helpers %}
|
||||
|
||||
{% block replication_fields %}
|
||||
{{ block.super }}
|
||||
{% render_field replication_form.position_pattern %}
|
||||
{% endblock replication_fields %}
|
Loading…
Reference in New Issue
Block a user