Sfoglia il codice sorgente

12216 Add color to circuit-type and add to SVG rendering (#14098)

* 12216 add color to model

* 12216 add forms, serializers for color

* 12216 color to detail view, add type to svg

* 12216 add color to svg

* 12216 review changes
Arthur Hanson 2 anni fa
parent
commit
ae447bd187

+ 1 - 1
netbox/circuits/api/serializers.py

@@ -85,7 +85,7 @@ class CircuitTypeSerializer(NetBoxModelSerializer):
     class Meta:
     class Meta:
         model = CircuitType
         model = CircuitType
         fields = [
         fields = [
-            'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
+            'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
             'circuit_count',
             'circuit_count',
         ]
         ]
 
 

+ 1 - 1
netbox/circuits/filtersets.py

@@ -137,7 +137,7 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
 
 
     class Meta:
     class Meta:
         model = CircuitType
         model = CircuitType
-        fields = ['id', 'name', 'slug', 'description']
+        fields = ['id', 'name', 'slug', 'color', 'description']
 
 
 
 
 class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
 class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):

+ 7 - 3
netbox/circuits/forms/bulk_edit.py

@@ -7,7 +7,7 @@ from ipam.models import ASN
 from netbox.forms import NetBoxModelBulkEditForm
 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 CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
+from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
 from utilities.forms.widgets import DatePicker, NumberWithOptions
 from utilities.forms.widgets import DatePicker, NumberWithOptions
 
 
 __all__ = (
 __all__ = (
@@ -91,6 +91,10 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
 
 
 
 
 class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
 class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
+    color = ColorField(
+        label=_('Color'),
+        required=False
+    )
     description = forms.CharField(
     description = forms.CharField(
         label=_('Description'),
         label=_('Description'),
         max_length=200,
         max_length=200,
@@ -99,9 +103,9 @@ class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
 
 
     model = CircuitType
     model = CircuitType
     fieldsets = (
     fieldsets = (
-        (None, ('description',)),
+        (None, ('color', 'description')),
     )
     )
-    nullable_fields = ('description',)
+    nullable_fields = ('color', 'description')
 
 
 
 
 class CircuitBulkEditForm(NetBoxModelBulkEditForm):
 class CircuitBulkEditForm(NetBoxModelBulkEditForm):

+ 5 - 1
netbox/circuits/forms/bulk_import.py

@@ -3,6 +3,7 @@ from django import forms
 from circuits.choices import CircuitStatusChoices
 from circuits.choices import CircuitStatusChoices
 from circuits.models import *
 from circuits.models import *
 from dcim.models import Site
 from dcim.models import Site
+from django.utils.safestring import mark_safe
 from django.utils.translation import gettext_lazy as _
 from django.utils.translation import gettext_lazy as _
 from netbox.forms import NetBoxModelImportForm
 from netbox.forms import NetBoxModelImportForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
@@ -64,7 +65,10 @@ class CircuitTypeImportForm(NetBoxModelImportForm):
 
 
     class Meta:
     class Meta:
         model = CircuitType
         model = CircuitType
-        fields = ('name', 'slug', 'description', 'tags')
+        fields = ('name', 'slug', 'color', 'description', 'tags')
+        help_texts = {
+            'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' <code>00ff00</code>'),
+        }
 
 
 
 
 class CircuitImportForm(NetBoxModelImportForm):
 class CircuitImportForm(NetBoxModelImportForm):

+ 10 - 1
netbox/circuits/forms/filtersets.py

@@ -7,7 +7,7 @@ from dcim.models import Region, Site, SiteGroup
 from ipam.models import ASN
 from ipam.models import ASN
 from netbox.forms import NetBoxModelFilterSetForm
 from netbox.forms import NetBoxModelFilterSetForm
 from tenancy.forms import TenancyFilterForm, ContactModelFilterForm
 from tenancy.forms import TenancyFilterForm, ContactModelFilterForm
-from utilities.forms.fields import DynamicModelMultipleChoiceField, TagFilterField
+from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField
 from utilities.forms.widgets import DatePicker, NumberWithOptions
 from utilities.forms.widgets import DatePicker, NumberWithOptions
 
 
 __all__ = (
 __all__ = (
@@ -97,8 +97,17 @@ class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
 
 
 class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
 class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
     model = CircuitType
     model = CircuitType
+    fieldsets = (
+        (None, ('q', 'filter_id', 'tag')),
+        (_('Attributes'), ('color',)),
+    )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
+    color = ColorField(
+        label=_('Color'),
+        required=False
+    )
+
 
 
 class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
 class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
     model = Circuit
     model = Circuit

+ 2 - 2
netbox/circuits/forms/model_forms.py

@@ -76,14 +76,14 @@ class CircuitTypeForm(NetBoxModelForm):
 
 
     fieldsets = (
     fieldsets = (
         (_('Circuit Type'), (
         (_('Circuit Type'), (
-            'name', 'slug', 'description', 'tags',
+            'name', 'slug', 'color', 'description', 'tags',
         )),
         )),
     )
     )
 
 
     class Meta:
     class Meta:
         model = CircuitType
         model = CircuitType
         fields = [
         fields = [
-            'name', 'slug', 'description', 'tags',
+            'name', 'slug', 'color', 'description', 'tags',
         ]
         ]
 
 
 
 

+ 18 - 0
netbox/circuits/migrations/0043_circuittype_color.py

@@ -0,0 +1,18 @@
+# Generated by Django 4.2.5 on 2023-10-20 21:25
+
+from django.db import migrations
+import utilities.fields
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ('circuits', '0042_provideraccount'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='circuittype',
+            name='color',
+            field=utilities.fields.ColorField(blank=True, max_length=6),
+        ),
+    ]

+ 6 - 0
netbox/circuits/models/circuits.py

@@ -7,6 +7,7 @@ from circuits.choices import *
 from dcim.models import CabledObjectModel
 from dcim.models import CabledObjectModel
 from netbox.models import ChangeLoggedModel, OrganizationalModel, PrimaryModel
 from netbox.models import ChangeLoggedModel, OrganizationalModel, PrimaryModel
 from netbox.models.features import ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ImageAttachmentsMixin, TagsMixin
 from netbox.models.features import ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ImageAttachmentsMixin, TagsMixin
+from utilities.fields import ColorField
 
 
 __all__ = (
 __all__ = (
     'Circuit',
     'Circuit',
@@ -20,6 +21,11 @@ class CircuitType(OrganizationalModel):
     Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
     Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
     "Long Haul," "Metro," or "Out-of-Band".
     "Long Haul," "Metro," or "Out-of-Band".
     """
     """
+    color = ColorField(
+        verbose_name=_('color'),
+        blank=True
+    )
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('circuits:circuittype', args=[self.pk])
         return reverse('circuits:circuittype', args=[self.pk])
 
 

+ 2 - 1
netbox/circuits/tables/circuits.py

@@ -28,6 +28,7 @@ class CircuitTypeTable(NetBoxTable):
         linkify=True,
         linkify=True,
         verbose_name=_('Name'),
         verbose_name=_('Name'),
     )
     )
+    color = columns.ColorColumn()
     tags = columns.TagColumn(
     tags = columns.TagColumn(
         url_name='circuits:circuittype_list'
         url_name='circuits:circuittype_list'
     )
     )
@@ -40,7 +41,7 @@ class CircuitTypeTable(NetBoxTable):
     class Meta(NetBoxTable.Meta):
     class Meta(NetBoxTable.Meta):
         model = CircuitType
         model = CircuitType
         fields = (
         fields = (
-            'pk', 'id', 'name', 'circuit_count', 'description', 'slug', 'tags', 'created', 'last_updated', 'actions',
+            'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated', 'actions',
         )
         )
         default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
         default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
 
 

+ 3 - 0
netbox/dcim/svg/cables.py

@@ -159,6 +159,7 @@ class CableTraceSVG:
             labels.append(location_label)
             labels.append(location_label)
         elif instance._meta.model_name == 'circuit':
         elif instance._meta.model_name == 'circuit':
             labels[0] = f'Circuit {instance}'
             labels[0] = f'Circuit {instance}'
+            labels.append(instance.type)
             labels.append(instance.provider)
             labels.append(instance.provider)
             if instance.description:
             if instance.description:
                 labels.append(instance.description)
                 labels.append(instance.description)
@@ -181,6 +182,8 @@ class CableTraceSVG:
         if hasattr(instance, 'role'):
         if hasattr(instance, 'role'):
             # Device
             # Device
             return instance.role.color
             return instance.role.color
+        elif instance._meta.model_name == 'circuit' and instance.type.color:
+            return instance.type.color
         else:
         else:
             # Other parent object
             # Other parent object
             return 'e0e0e0'
             return 'e0e0e0'

+ 10 - 0
netbox/templates/circuits/circuittype.html

@@ -29,6 +29,16 @@
             <th scope="row">{% trans "Description" %}</th>
             <th scope="row">{% trans "Description" %}</th>
             <td>{{ object.description|placeholder }}</td>
             <td>{{ object.description|placeholder }}</td>
           </tr>
           </tr>
+          <tr>
+            <th scope="row">{% trans "Color" %}</th>
+            <td>
+              {% if object.color %}
+                <span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span>
+              {% else %}
+                {{ ''|placeholder }}
+              {% endif %}
+            </td>
+          </tr>
         </table>
         </table>
       </div>
       </div>
     </div>
     </div>