mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Add position field for module bays
This commit is contained in:
@ -432,7 +432,10 @@ class ModuleBayTemplateSerializer(ValidatedModelSerializer):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBayTemplate
|
model = ModuleBayTemplate
|
||||||
fields = ['id', 'url', 'display', 'device_type', 'name', 'label', 'description', 'created', 'last_updated']
|
fields = [
|
||||||
|
'id', 'url', 'display', 'device_type', 'name', 'label', 'position', 'description', 'created',
|
||||||
|
'last_updated',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayTemplateSerializer(ValidatedModelSerializer):
|
class DeviceBayTemplateSerializer(ValidatedModelSerializer):
|
||||||
@ -785,8 +788,8 @@ class ModuleBaySerializer(PrimaryModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'device', 'name', 'label', 'description', 'tags', 'custom_fields', 'created',
|
'id', 'url', 'display', 'device', 'name', 'label', 'position', 'description', 'tags', 'custom_fields',
|
||||||
'last_updated',
|
'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -886,7 +886,7 @@ class ModuleBayTemplateBulkEditForm(BulkEditForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
nullable_fields = ('label', 'description')
|
nullable_fields = ('label', 'position', 'description')
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayTemplateBulkEditForm(BulkEditForm):
|
class DeviceBayTemplateBulkEditForm(BulkEditForm):
|
||||||
@ -1153,7 +1153,7 @@ class ModuleBayBulkEditForm(
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
nullable_fields = ['label', 'description']
|
nullable_fields = ['label', 'position', 'description']
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayBulkEditForm(
|
class DeviceBayBulkEditForm(
|
||||||
|
@ -717,7 +717,7 @@ class ModuleBayCSVForm(CustomFieldModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fields = ('device', 'name', 'label', 'description')
|
fields = ('device', 'name', 'label', 'position', 'description')
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayCSVForm(CustomFieldModelCSVForm):
|
class DeviceBayCSVForm(CustomFieldModelCSVForm):
|
||||||
|
@ -1073,10 +1073,13 @@ class ModuleBayFilterForm(DeviceComponentFilterForm):
|
|||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
field_groups = [
|
field_groups = [
|
||||||
['q', 'tag'],
|
['q', 'tag'],
|
||||||
['name', 'label'],
|
['name', 'label', 'position'],
|
||||||
['region_id', 'site_group_id', 'site_id', 'location_id', 'virtual_chassis_id', 'device_id'],
|
['region_id', 'site_group_id', 'site_id', 'location_id', 'virtual_chassis_id', 'device_id'],
|
||||||
]
|
]
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
position = forms.CharField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayFilterForm(DeviceComponentFilterForm):
|
class DeviceBayFilterForm(DeviceComponentFilterForm):
|
||||||
|
@ -1059,7 +1059,7 @@ class ModuleBayTemplateForm(BootstrapMixin, forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBayTemplate
|
model = ModuleBayTemplate
|
||||||
fields = [
|
fields = [
|
||||||
'device_type', 'name', 'label', 'description',
|
'device_type', 'name', 'label', 'position', 'description',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'device_type': forms.HiddenInput(),
|
'device_type': forms.HiddenInput(),
|
||||||
@ -1313,7 +1313,7 @@ class ModuleBayForm(CustomFieldModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fields = [
|
fields = [
|
||||||
'device', 'name', 'label', 'description', 'tags',
|
'device', 'name', 'label', 'position', 'description', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'device': forms.HiddenInput(),
|
'device': forms.HiddenInput(),
|
||||||
|
@ -163,6 +163,12 @@ class ComponentTemplateCreateForm(ComponentForm):
|
|||||||
'manufacturer_id': '$manufacturer'
|
'manufacturer_id': '$manufacturer'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ModularComponentTemplateCreateForm(ComponentTemplateCreateForm):
|
||||||
module_type = DynamicModelChoiceField(
|
module_type = DynamicModelChoiceField(
|
||||||
queryset=ModuleType.objects.all(),
|
queryset=ModuleType.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
@ -170,12 +176,9 @@ class ComponentTemplateCreateForm(ComponentForm):
|
|||||||
'manufacturer_id': '$manufacturer'
|
'manufacturer_id': '$manufacturer'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
description = forms.CharField(
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsolePortTemplateCreateForm(ComponentTemplateCreateForm):
|
class ConsolePortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(ConsolePortTypeChoices),
|
choices=add_blank_choice(ConsolePortTypeChoices),
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
@ -185,7 +188,7 @@ class ConsolePortTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortTemplateCreateForm(ComponentTemplateCreateForm):
|
class ConsoleServerPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(ConsolePortTypeChoices),
|
choices=add_blank_choice(ConsolePortTypeChoices),
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
@ -195,7 +198,7 @@ class ConsoleServerPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerPortTemplateCreateForm(ComponentTemplateCreateForm):
|
class PowerPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(PowerPortTypeChoices),
|
choices=add_blank_choice(PowerPortTypeChoices),
|
||||||
required=False
|
required=False
|
||||||
@ -216,7 +219,7 @@ class PowerPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletTemplateCreateForm(ComponentTemplateCreateForm):
|
class PowerOutletTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(PowerOutletTypeChoices),
|
choices=add_blank_choice(PowerOutletTypeChoices),
|
||||||
required=False
|
required=False
|
||||||
@ -240,7 +243,7 @@ class PowerOutletTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTemplateCreateForm(ComponentTemplateCreateForm):
|
class InterfaceTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=InterfaceTypeChoices,
|
choices=InterfaceTypeChoices,
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
@ -255,7 +258,7 @@ class InterfaceTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FrontPortTemplateCreateForm(ComponentTemplateCreateForm):
|
class FrontPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=PortTypeChoices,
|
choices=PortTypeChoices,
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
@ -320,7 +323,7 @@ class FrontPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class RearPortTemplateCreateForm(ComponentTemplateCreateForm):
|
class RearPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=PortTypeChoices,
|
choices=PortTypeChoices,
|
||||||
widget=StaticSelect(),
|
widget=StaticSelect(),
|
||||||
@ -341,6 +344,7 @@ class RearPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|||||||
|
|
||||||
|
|
||||||
class ModuleBayTemplateCreateForm(ComponentTemplateCreateForm):
|
class ModuleBayTemplateCreateForm(ComponentTemplateCreateForm):
|
||||||
|
# TODO: Support patterned position assignment
|
||||||
field_order = ('manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'description')
|
field_order = ('manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ class ModuleBayTemplateImportForm(ComponentTemplateImportForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBayTemplate
|
model = ModuleBayTemplate
|
||||||
fields = [
|
fields = [
|
||||||
'device_type', 'name', 'label', 'description',
|
'device_type', 'name', 'label', 'position', 'description',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -105,6 +105,7 @@ class Migration(migrations.Migration):
|
|||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
('label', models.CharField(blank=True, max_length=64)),
|
('label', models.CharField(blank=True, max_length=64)),
|
||||||
|
('position', models.CharField(blank=True, max_length=30)),
|
||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modulebays', to='dcim.device')),
|
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modulebays', to='dcim.device')),
|
||||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
@ -241,6 +242,7 @@ class Migration(migrations.Migration):
|
|||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
('label', models.CharField(blank=True, max_length=64)),
|
('label', models.CharField(blank=True, max_length=64)),
|
||||||
|
('position', models.CharField(blank=True, max_length=30)),
|
||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modulebaytemplates', to='dcim.devicetype')),
|
('device_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='modulebaytemplates', to='dcim.devicetype')),
|
||||||
],
|
],
|
||||||
|
@ -123,6 +123,11 @@ class ModularComponentTemplateModel(ComponentTemplateModel):
|
|||||||
"A component template must be associated with either a device type or a module type."
|
"A component template must be associated with either a device type or a module type."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def resolve_name(self, module):
|
||||||
|
if module:
|
||||||
|
return self.name.replace('{module}', module.module_bay.position)
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
@extras_features('webhooks')
|
@extras_features('webhooks')
|
||||||
class ConsolePortTemplate(ModularComponentTemplateModel):
|
class ConsolePortTemplate(ModularComponentTemplateModel):
|
||||||
@ -144,7 +149,7 @@ class ConsolePortTemplate(ModularComponentTemplateModel):
|
|||||||
|
|
||||||
def instantiate(self, **kwargs):
|
def instantiate(self, **kwargs):
|
||||||
return ConsolePort(
|
return ConsolePort(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
**kwargs
|
**kwargs
|
||||||
@ -171,7 +176,7 @@ class ConsoleServerPortTemplate(ModularComponentTemplateModel):
|
|||||||
|
|
||||||
def instantiate(self, **kwargs):
|
def instantiate(self, **kwargs):
|
||||||
return ConsoleServerPort(
|
return ConsoleServerPort(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
**kwargs
|
**kwargs
|
||||||
@ -210,7 +215,7 @@ class PowerPortTemplate(ModularComponentTemplateModel):
|
|||||||
|
|
||||||
def instantiate(self, **kwargs):
|
def instantiate(self, **kwargs):
|
||||||
return PowerPort(
|
return PowerPort(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
maximum_draw=self.maximum_draw,
|
maximum_draw=self.maximum_draw,
|
||||||
@ -279,7 +284,7 @@ class PowerOutletTemplate(ModularComponentTemplateModel):
|
|||||||
else:
|
else:
|
||||||
power_port = None
|
power_port = None
|
||||||
return PowerOutlet(
|
return PowerOutlet(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
power_port=power_port,
|
power_port=power_port,
|
||||||
@ -318,7 +323,7 @@ class InterfaceTemplate(ModularComponentTemplateModel):
|
|||||||
|
|
||||||
def instantiate(self, **kwargs):
|
def instantiate(self, **kwargs):
|
||||||
return Interface(
|
return Interface(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
mgmt_only=self.mgmt_only,
|
mgmt_only=self.mgmt_only,
|
||||||
@ -387,7 +392,7 @@ class FrontPortTemplate(ModularComponentTemplateModel):
|
|||||||
else:
|
else:
|
||||||
rear_port = None
|
rear_port = None
|
||||||
return FrontPort(
|
return FrontPort(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
color=self.color,
|
color=self.color,
|
||||||
@ -426,7 +431,7 @@ class RearPortTemplate(ModularComponentTemplateModel):
|
|||||||
|
|
||||||
def instantiate(self, **kwargs):
|
def instantiate(self, **kwargs):
|
||||||
return RearPort(
|
return RearPort(
|
||||||
name=self.name,
|
name=self.resolve_name(kwargs.get('module')),
|
||||||
label=self.label,
|
label=self.label,
|
||||||
type=self.type,
|
type=self.type,
|
||||||
color=self.color,
|
color=self.color,
|
||||||
@ -440,6 +445,12 @@ class ModuleBayTemplate(ComponentTemplateModel):
|
|||||||
"""
|
"""
|
||||||
A template for a ModuleBay to be created for a new parent Device.
|
A template for a ModuleBay to be created for a new parent Device.
|
||||||
"""
|
"""
|
||||||
|
position = models.CharField(
|
||||||
|
max_length=30,
|
||||||
|
blank=True,
|
||||||
|
help_text='Identifier to reference when renaming installed components'
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('device_type', '_name')
|
ordering = ('device_type', '_name')
|
||||||
unique_together = ('device_type', 'name')
|
unique_together = ('device_type', 'name')
|
||||||
@ -448,7 +459,8 @@ class ModuleBayTemplate(ComponentTemplateModel):
|
|||||||
return ModuleBay(
|
return ModuleBay(
|
||||||
device=device,
|
device=device,
|
||||||
name=self.name,
|
name=self.name,
|
||||||
label=self.label
|
label=self.label,
|
||||||
|
position=self.position
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -880,6 +880,12 @@ class ModuleBay(ComponentModel):
|
|||||||
"""
|
"""
|
||||||
An empty space within a Device which can house a child device
|
An empty space within a Device which can house a child device
|
||||||
"""
|
"""
|
||||||
|
position = models.CharField(
|
||||||
|
max_length=30,
|
||||||
|
blank=True,
|
||||||
|
help_text='Identifier to reference when renaming installed components'
|
||||||
|
)
|
||||||
|
|
||||||
clone_fields = ['device']
|
clone_fields = ['device']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -749,7 +749,7 @@ class ModuleBayTable(DeviceComponentTable):
|
|||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fields = ('pk', 'id', 'name', 'device', 'label', 'installed_module', 'description', 'tags')
|
fields = ('pk', 'id', 'name', 'device', 'label', 'position', 'installed_module', 'description', 'tags')
|
||||||
default_columns = ('pk', 'name', 'device', 'label', 'installed_module', 'description')
|
default_columns = ('pk', 'name', 'device', 'label', 'installed_module', 'description')
|
||||||
|
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ class ModuleBayTemplateTable(ComponentTemplateTable):
|
|||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = ModuleBayTemplate
|
model = ModuleBayTemplate
|
||||||
fields = ('pk', 'name', 'label', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'position', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
<th scope="row">Label</th>
|
<th scope="row">Label</th>
|
||||||
<td>{{ object.label|placeholder }}</td>
|
<td>{{ object.label|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Position</th>
|
||||||
|
<td>{{ object.position|placeholder }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Description</th>
|
<th scope="row">Description</th>
|
||||||
<td>{{ object.description|placeholder }}</td>
|
<td>{{ object.description|placeholder }}</td>
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
{% block tab_items %}
|
{% block tab_items %}
|
||||||
<li role="presentation" class="nav-item">
|
<li role="presentation" class="nav-item">
|
||||||
<a href="{% url 'dcim:devicetype' pk=object.pk %}" class="nav-link{% if active_tab == 'moduletype' %} active{% endif %}">
|
<a href="{% url 'dcim:moduletype' pk=object.pk %}" class="nav-link{% if active_tab == 'moduletype' %} active{% endif %}">
|
||||||
Module Type
|
Module Type
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
Reference in New Issue
Block a user