Jelajahi Sumber

Closes #8667: Support position patterning when creating module bays & templates

jeremystretch 4 tahun lalu
induk
melakukan
a2fe23549b

+ 32 - 9
netbox/dcim/forms/object_create.py

@@ -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(),

+ 2 - 2
netbox/dcim/tables/devices.py

@@ -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):

+ 5 - 3
netbox/dcim/views.py

@@ -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):

+ 6 - 8
netbox/netbox/views/generic/object_views.py

@@ -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')
-
-            for i, name in enumerate(names):
-                label = labels[i] if labels else None
-                # Initialize the individual component form
-                data['name'] = name
-                data['label'] = label
+            pattern_count = len(form.cleaned_data[f'{self.patterned_fields[0]}_pattern'])
+
+            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 - 0
netbox/templates/dcim/modulebaytemplate_create.html

@@ -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 %}