Просмотр исходного кода

Merge pull request #2918 from digitalocean/2643-description-fields

Closes #2643: Add description field to console/power components and device bays
Jeremy Stretch 7 лет назад
Родитель
Сommit
00c4d3dd92

+ 1 - 0
CHANGELOG.md

@@ -17,6 +17,7 @@ NetBox now makes use of its own `Tag` model instead of the vanilla model which s
 ## Enhancements
 
 * [#2324](https://github.com/digitalocean/netbox/issues/2324) - Add color option for tags
+* [#2643](https://github.com/digitalocean/netbox/issues/2643) - Add `description` field to console/power components and device bays
 * [#2791](https://github.com/digitalocean/netbox/issues/2791) - Add a comment field for tags
 * [#2926](https://github.com/digitalocean/netbox/issues/2926) - Add changelog to the Tag model
 

+ 9 - 9
netbox/dcim/api/serializers.py

@@ -346,8 +346,8 @@ class ConsoleServerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer)
     class Meta:
         model = ConsoleServerPort
         fields = [
-            'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
-            'tags',
+            'id', 'device', 'name', 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status',
+            'cable', 'tags',
         ]
 
 
@@ -359,8 +359,8 @@ class ConsolePortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
     class Meta:
         model = ConsolePort
         fields = [
-            'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
-            'tags',
+            'id', 'device', 'name', 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status',
+            'cable', 'tags',
         ]
 
 
@@ -372,8 +372,8 @@ class PowerOutletSerializer(TaggitSerializer, ConnectedEndpointSerializer):
     class Meta:
         model = PowerOutlet
         fields = [
-            'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
-            'tags',
+            'id', 'device', 'name', 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status',
+            'cable', 'tags',
         ]
 
 
@@ -385,8 +385,8 @@ class PowerPortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
     class Meta:
         model = PowerPort
         fields = [
-            'id', 'device', 'name', 'connected_endpoint_type', 'connected_endpoint', 'connection_status', 'cable',
-            'tags',
+            'id', 'device', 'name', 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status',
+            'cable', 'tags',
         ]
 
 
@@ -475,7 +475,7 @@ class DeviceBaySerializer(TaggitSerializer, ValidatedModelSerializer):
 
     class Meta:
         model = DeviceBay
-        fields = ['id', 'device', 'name', 'installed_device', 'tags']
+        fields = ['id', 'device', 'name', 'description', 'installed_device', 'tags']
 
 
 #

+ 12 - 10
netbox/dcim/filters.py

@@ -689,7 +689,8 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
         if not value.strip():
             return queryset
         return queryset.filter(
-            Q(name__icontains=value)
+            Q(name__icontains=value) |
+            Q(description__icontains=value)
         )
 
 
@@ -702,7 +703,7 @@ class ConsolePortFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = ConsolePort
-        fields = ['name', 'connection_status']
+        fields = ['name', 'description', 'connection_status']
 
 
 class ConsoleServerPortFilter(DeviceComponentFilterSet):
@@ -714,7 +715,7 @@ class ConsoleServerPortFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = ConsoleServerPort
-        fields = ['name', 'connection_status']
+        fields = ['name', 'description', 'connection_status']
 
 
 class PowerPortFilter(DeviceComponentFilterSet):
@@ -726,7 +727,7 @@ class PowerPortFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = PowerPort
-        fields = ['name', 'connection_status']
+        fields = ['name', 'description', 'connection_status']
 
 
 class PowerOutletFilter(DeviceComponentFilterSet):
@@ -738,7 +739,7 @@ class PowerOutletFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = PowerOutlet
-        fields = ['name', 'connection_status']
+        fields = ['name', 'description', 'connection_status']
 
 
 class InterfaceFilter(django_filters.FilterSet):
@@ -793,13 +794,14 @@ class InterfaceFilter(django_filters.FilterSet):
 
     class Meta:
         model = Interface
-        fields = ['name', 'connection_status', 'form_factor', 'enabled', 'mtu', 'mgmt_only']
+        fields = ['name', 'connection_status', 'form_factor', 'enabled', 'mtu', 'mgmt_only', 'description']
 
     def search(self, queryset, name, value):
         if not value.strip():
             return queryset
         return queryset.filter(
-            Q(name__icontains=value)
+            Q(name__icontains=value) |
+            Q(description__icontains=value)
         ).distinct()
 
     def filter_device(self, queryset, name, value):
@@ -857,7 +859,7 @@ class FrontPortFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = FrontPort
-        fields = ['name', 'type']
+        fields = ['name', 'type', 'description']
 
 
 class RearPortFilter(DeviceComponentFilterSet):
@@ -869,14 +871,14 @@ class RearPortFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = RearPort
-        fields = ['name', 'type']
+        fields = ['name', 'type', 'description']
 
 
 class DeviceBayFilter(DeviceComponentFilterSet):
 
     class Meta:
         model = DeviceBay
-        fields = ['name']
+        fields = ['name', 'description']
 
 
 class InventoryItemFilter(DeviceComponentFilterSet):

+ 53 - 5
netbox/dcim/forms.py

@@ -1854,7 +1854,7 @@ class ConsolePortForm(BootstrapMixin, forms.ModelForm):
     class Meta:
         model = ConsolePort
         fields = [
-            'device', 'name', 'tags',
+            'device', 'name', 'description', 'tags',
         ]
         widgets = {
             'device': forms.HiddenInput(),
@@ -1865,6 +1865,10 @@ class ConsolePortCreateForm(ComponentForm):
     name_pattern = ExpandableNameField(
         label='Name'
     )
+    description = forms.CharField(
+        max_length=100,
+        required=False
+    )
     tags = TagField(
         required=False
     )
@@ -1882,7 +1886,7 @@ class ConsoleServerPortForm(BootstrapMixin, forms.ModelForm):
     class Meta:
         model = ConsoleServerPort
         fields = [
-            'device', 'name', 'tags',
+            'device', 'name', 'description', 'tags',
         ]
         widgets = {
             'device': forms.HiddenInput(),
@@ -1893,11 +1897,31 @@ class ConsoleServerPortCreateForm(ComponentForm):
     name_pattern = ExpandableNameField(
         label='Name'
     )
+    description = forms.CharField(
+        max_length=100,
+        required=False
+    )
     tags = TagField(
         required=False
     )
 
 
+class ConsoleServerPortBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
+    pk = forms.ModelMultipleChoiceField(
+        queryset=ConsoleServerPort.objects.all(),
+        widget=forms.MultipleHiddenInput()
+    )
+    description = forms.CharField(
+        max_length=100,
+        required=False
+    )
+
+    class Meta:
+        nullable_fields = [
+            'description',
+        ]
+
+
 class ConsoleServerPortBulkRenameForm(BulkRenameForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=ConsoleServerPort.objects.all(),
@@ -1924,7 +1948,7 @@ class PowerPortForm(BootstrapMixin, forms.ModelForm):
     class Meta:
         model = PowerPort
         fields = [
-            'device', 'name', 'tags',
+            'device', 'name', 'description', 'tags',
         ]
         widgets = {
             'device': forms.HiddenInput(),
@@ -1935,6 +1959,10 @@ class PowerPortCreateForm(ComponentForm):
     name_pattern = ExpandableNameField(
         label='Name'
     )
+    description = forms.CharField(
+        max_length=100,
+        required=False
+    )
     tags = TagField(
         required=False
     )
@@ -1952,7 +1980,7 @@ class PowerOutletForm(BootstrapMixin, forms.ModelForm):
     class Meta:
         model = PowerOutlet
         fields = [
-            'device', 'name', 'tags',
+            'device', 'name', 'description', 'tags',
         ]
         widgets = {
             'device': forms.HiddenInput(),
@@ -1963,11 +1991,31 @@ class PowerOutletCreateForm(ComponentForm):
     name_pattern = ExpandableNameField(
         label='Name'
     )
+    description = forms.CharField(
+        max_length=100,
+        required=False
+    )
     tags = TagField(
         required=False
     )
 
 
+class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
+    pk = forms.ModelMultipleChoiceField(
+        queryset=PowerOutlet.objects.all(),
+        widget=forms.MultipleHiddenInput()
+    )
+    description = forms.CharField(
+        max_length=100,
+        required=False
+    )
+
+    class Meta:
+        nullable_fields = [
+            'description',
+        ]
+
+
 class PowerOutletBulkRenameForm(BulkRenameForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=PowerOutlet.objects.all(),
@@ -2776,7 +2824,7 @@ class DeviceBayForm(BootstrapMixin, forms.ModelForm):
     class Meta:
         model = DeviceBay
         fields = [
-            'device', 'name', 'tags',
+            'device', 'name', 'description', 'tags',
         ]
         widgets = {
             'device': forms.HiddenInput(),

+ 38 - 0
netbox/dcim/migrations/0071_device_components_add_description.py

@@ -0,0 +1,38 @@
+# Generated by Django 2.1.7 on 2019-02-20 18:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('dcim', '0070_custom_tag_models'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='consoleport',
+            name='description',
+            field=models.CharField(blank=True, max_length=100),
+        ),
+        migrations.AddField(
+            model_name='consoleserverport',
+            name='description',
+            field=models.CharField(blank=True, max_length=100),
+        ),
+        migrations.AddField(
+            model_name='devicebay',
+            name='description',
+            field=models.CharField(blank=True, max_length=100),
+        ),
+        migrations.AddField(
+            model_name='poweroutlet',
+            name='description',
+            field=models.CharField(blank=True, max_length=100),
+        ),
+        migrations.AddField(
+            model_name='powerport',
+            name='description',
+            field=models.CharField(blank=True, max_length=100),
+        ),
+    ]

+ 14 - 21
netbox/dcim/models.py

@@ -46,6 +46,10 @@ class ComponentTemplateModel(models.Model):
 
 
 class ComponentModel(models.Model):
+    description = models.CharField(
+        max_length=100,
+        blank=True
+    )
 
     class Meta:
         abstract = True
@@ -1745,7 +1749,7 @@ class ConsolePort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager(through=TaggedItem)
 
-    csv_headers = ['device', 'name']
+    csv_headers = ['device', 'name', 'description']
 
     class Meta:
         ordering = ['device', 'name']
@@ -1761,6 +1765,7 @@ class ConsolePort(CableTermination, ComponentModel):
         return (
             self.device.identifier,
             self.name,
+            self.description,
         )
 
 
@@ -1788,7 +1793,7 @@ class ConsoleServerPort(CableTermination, ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager(through=TaggedItem)
 
-    csv_headers = ['device', 'name']
+    csv_headers = ['device', 'name', 'description']
 
     class Meta:
         unique_together = ['device', 'name']
@@ -1803,6 +1808,7 @@ class ConsoleServerPort(CableTermination, ComponentModel):
         return (
             self.device.identifier,
             self.name,
+            self.description,
         )
 
 
@@ -1841,7 +1847,7 @@ class PowerPort(CableTermination, ComponentModel):
 
     class Meta:
         ordering = ['device', 'name']
-        unique_together = ['device', 'name']
+        unique_together = ['device', 'name', 'description']
 
     def __str__(self):
         return self.name
@@ -1853,6 +1859,7 @@ class PowerPort(CableTermination, ComponentModel):
         return (
             self.device.identifier,
             self.name,
+            self.description,
         )
 
 
@@ -1883,7 +1890,7 @@ class PowerOutlet(CableTermination, ComponentModel):
     csv_headers = ['device', 'name']
 
     class Meta:
-        unique_together = ['device', 'name']
+        unique_together = ['device', 'name', 'description']
 
     def __str__(self):
         return self.name
@@ -1895,6 +1902,7 @@ class PowerOutlet(CableTermination, ComponentModel):
         return (
             self.device.identifier,
             self.name,
+            self.description,
         )
 
 
@@ -1973,10 +1981,6 @@ class Interface(CableTermination, ComponentModel):
         verbose_name='OOB Management',
         help_text='This interface is used only for out-of-band management'
     )
-    description = models.CharField(
-        max_length=100,
-        blank=True
-    )
     mode = models.PositiveSmallIntegerField(
         choices=IFACE_MODE_CHOICES,
         blank=True,
@@ -2193,10 +2197,6 @@ class FrontPort(CableTermination, ComponentModel):
         default=1,
         validators=[MinValueValidator(1), MaxValueValidator(64)]
     )
-    description = models.CharField(
-        max_length=100,
-        blank=True
-    )
 
     objects = DeviceComponentManager()
     tags = TaggableManager(through=TaggedItem)
@@ -2259,10 +2259,6 @@ class RearPort(CableTermination, ComponentModel):
         default=1,
         validators=[MinValueValidator(1), MaxValueValidator(64)]
     )
-    description = models.CharField(
-        max_length=100,
-        blank=True
-    )
 
     objects = DeviceComponentManager()
     tags = TaggableManager(through=TaggedItem)
@@ -2314,7 +2310,7 @@ class DeviceBay(ComponentModel):
     objects = DeviceComponentManager()
     tags = TaggableManager(through=TaggedItem)
 
-    csv_headers = ['device', 'name', 'installed_device']
+    csv_headers = ['device', 'name', 'installed_device', 'description']
 
     class Meta:
         ordering = ['device', 'name']
@@ -2331,6 +2327,7 @@ class DeviceBay(ComponentModel):
             self.device.identifier,
             self.name,
             self.installed_device.identifier if self.installed_device else None,
+            self.description,
         )
 
     def clean(self):
@@ -2400,10 +2397,6 @@ class InventoryItem(ComponentModel):
         default=False,
         verbose_name='Discovered'
     )
-    description = models.CharField(
-        max_length=100,
-        blank=True
-    )
 
     tags = TaggableManager(through=TaggedItem)
 

+ 3 - 0
netbox/templates/dcim/device.html

@@ -445,6 +445,7 @@
                                 {% endif %}
                                 <th>Name</th>
                                 <th>Status</th>
+                                <th>Description</th>
                                 <th colspan="2">Installed Device</th>
                                 <th></th>
                             </tr>
@@ -570,6 +571,7 @@
                                     <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
                                 {% endif %}
                                 <th>Name</th>
+                                <th>Description</th>
                                 <th>Cable</th>
                                 <th colspan="2">Connection</th>
                                 <th></th>
@@ -625,6 +627,7 @@
                                     <th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
                                 {% endif %}
                                 <th>Name</th>
+                                <th>Description</th>
                                 <th>Cable</th>
                                 <th colspan="2">Connection</th>
                                 <th></th>

+ 5 - 0
netbox/templates/dcim/inc/consoleport.html

@@ -5,6 +5,11 @@
         <i class="fa fa-fw fa-keyboard-o"></i> {{ cp }}
     </td>
 
+    {# Description #}
+    <td>
+        {{ cp.description }}
+    </td>
+
     {# Cable #}
     <td>
         {% if cp.cable %}

+ 8 - 1
netbox/templates/dcim/inc/consoleserverport.html

@@ -1,3 +1,5 @@
+{% load helpers %}
+
 <tr class="consoleserverport{% if csp.cable.status %} success{% elif csp.cable %} info{% endif %}">
 
     {# Checkbox #}
@@ -12,12 +14,17 @@
         <i class="fa fa-fw fa-keyboard-o"></i> {{ csp }}
     </td>
 
+    {# Description #}
+    <td>
+        {{ csp.description|placeholder }}
+    </td>
+
     {# Cable #}
     <td>
         {% if csp.cable %}
             <a href="{{ csp.cable.get_absolute_url }}">{{ csp.cable }}</a>
         {% else %}
-            &mdash;
+            <span class="text-muted">&mdash;</span>
         {% endif %}
     </td>
 

+ 25 - 7
netbox/templates/dcim/inc/devicebay.html

@@ -1,16 +1,35 @@
+{% load helpers %}
+
 <tr class="devicebay">
     {% if perms.dcim.change_devicebay or perms.dcim.delete_devicebay %}
         <td class="pk">
             <input name="pk" type="checkbox" value="{{ devicebay.pk }}" />
         </td>
     {% endif %}
+
+    {# Name #}
     <td>
         <i class="fa fa-fw fa-{% if devicebay.installed_device %}dot-circle-o{% else %}circle-o{% endif %}"></i> {{ devicebay.name }}
     </td>
+
+    {# Status #}
+    <td>
+        {% if devicebay.installed_device %}
+            <span class="label label-{{ devicebay.installed_device.get_status_class }}">
+                {{ devicebay.installed_device.get_status_display }}
+            </span>
+        {% else %}
+            <span class="label label-default">Vacant</span>
+        {% endif %}
+    </td>
+
+    {# Description #}
+    <td>
+        {{ devicebay.description|placeholder }}
+    </td>
+
+    {# Installed device #}
     {% if devicebay.installed_device %}
-        <td>
-            <span class="label label-{{ devicebay.installed_device.get_status_class }}">{{ devicebay.installed_device.get_status_display }}</span>
-        </td>
         <td>
             <a href="{% url 'dcim:device' pk=devicebay.installed_device.pk %}">{{ devicebay.installed_device }}</a>
         </td>
@@ -18,11 +37,10 @@
             <span>{{ devicebay.installed_device.device_type.display_name }}</span>
         </td>
     {% else %}
-        <td></td>
-        <td colspan="2">
-            <span class="text-muted">Vacant</span>
-        </td>
+        <td colspan="2"></td>
     {% endif %}
+
+    {# Actions #}
     <td class="text-right">
         {% if perms.dcim.change_devicebay %}
             {% if devicebay.installed_device %}

+ 8 - 1
netbox/templates/dcim/inc/poweroutlet.html

@@ -1,3 +1,5 @@
+{% load helpers %}
+
 <tr class="poweroutlet{% if po.cable.status %} success{% elif po.cable %} info{% endif %}">
 
     {# Checkbox #}
@@ -12,12 +14,17 @@
         <i class="fa fa-fw fa-bolt"></i> {{ po }}
     </td>
 
+    {# Description #}
+    <td>
+        {{ po.description|placeholder }}
+    </td>
+
     {# Cable #}
     <td>
         {% if po.cable %}
             <a href="{{ po.cable.get_absolute_url }}">{{ po.cable }}</a>
         {% else %}
-            &mdash;
+            <span class="text-muted">&mdash;</span>
         {% endif %}
     </td>
 

+ 5 - 0
netbox/templates/dcim/inc/powerport.html

@@ -5,6 +5,11 @@
         <i class="fa fa-fw fa-bolt"></i> {{ pp }}
     </td>
 
+    {# Description #}
+    <td>
+        {{ pp.description }}
+    </td>
+
     {# Cable #}
     <td>
         {% if pp.cable %}