diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py
index f4abda645..5223de339 100644
--- a/netbox/circuits/api/serializers.py
+++ b/netbox/circuits/api/serializers.py
@@ -85,7 +85,7 @@ class CircuitTypeSerializer(NetBoxModelSerializer):
class Meta:
model = CircuitType
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',
]
diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py
index e28238fea..5c7168318 100644
--- a/netbox/circuits/filtersets.py
+++ b/netbox/circuits/filtersets.py
@@ -137,7 +137,7 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
class Meta:
model = CircuitType
- fields = ['id', 'name', 'slug', 'description']
+ fields = ['id', 'name', 'slug', 'color', 'description']
class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
diff --git a/netbox/circuits/forms/bulk_edit.py b/netbox/circuits/forms/bulk_edit.py
index 1a9366583..5c416bff9 100644
--- a/netbox/circuits/forms/bulk_edit.py
+++ b/netbox/circuits/forms/bulk_edit.py
@@ -7,7 +7,7 @@ from ipam.models import ASN
from netbox.forms import NetBoxModelBulkEditForm
from tenancy.models import Tenant
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
__all__ = (
@@ -91,6 +91,10 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
+ color = ColorField(
+ label=_('Color'),
+ required=False
+ )
description = forms.CharField(
label=_('Description'),
max_length=200,
@@ -99,9 +103,9 @@ class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
model = CircuitType
fieldsets = (
- (None, ('description',)),
+ (None, ('color', 'description')),
)
- nullable_fields = ('description',)
+ nullable_fields = ('color', 'description')
class CircuitBulkEditForm(NetBoxModelBulkEditForm):
diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py
index d2217b45b..0c30e3cda 100644
--- a/netbox/circuits/forms/bulk_import.py
+++ b/netbox/circuits/forms/bulk_import.py
@@ -3,6 +3,7 @@ from django import forms
from circuits.choices import CircuitStatusChoices
from circuits.models import *
from dcim.models import Site
+from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from netbox.forms import NetBoxModelImportForm
from tenancy.models import Tenant
@@ -64,7 +65,10 @@ class CircuitTypeImportForm(NetBoxModelImportForm):
class Meta:
model = CircuitType
- fields = ('name', 'slug', 'description', 'tags')
+ fields = ('name', 'slug', 'color', 'description', 'tags')
+ help_texts = {
+ 'color': mark_safe(_('RGB color in hexadecimal. Example:') + ' 00ff00
'),
+ }
class CircuitImportForm(NetBoxModelImportForm):
diff --git a/netbox/circuits/forms/filtersets.py b/netbox/circuits/forms/filtersets.py
index 1fb239023..830c10d8b 100644
--- a/netbox/circuits/forms/filtersets.py
+++ b/netbox/circuits/forms/filtersets.py
@@ -7,7 +7,7 @@ from dcim.models import Region, Site, SiteGroup
from ipam.models import ASN
from netbox.forms import NetBoxModelFilterSetForm
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
__all__ = (
@@ -97,8 +97,17 @@ class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
model = CircuitType
+ fieldsets = (
+ (None, ('q', 'filter_id', 'tag')),
+ (_('Attributes'), ('color',)),
+ )
tag = TagFilterField(model)
+ color = ColorField(
+ label=_('Color'),
+ required=False
+ )
+
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
model = Circuit
diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py
index 8a540032e..0809cb2f4 100644
--- a/netbox/circuits/forms/model_forms.py
+++ b/netbox/circuits/forms/model_forms.py
@@ -76,14 +76,14 @@ class CircuitTypeForm(NetBoxModelForm):
fieldsets = (
(_('Circuit Type'), (
- 'name', 'slug', 'description', 'tags',
+ 'name', 'slug', 'color', 'description', 'tags',
)),
)
class Meta:
model = CircuitType
fields = [
- 'name', 'slug', 'description', 'tags',
+ 'name', 'slug', 'color', 'description', 'tags',
]
diff --git a/netbox/circuits/migrations/0043_circuittype_color.py b/netbox/circuits/migrations/0043_circuittype_color.py
new file mode 100644
index 000000000..6c4dffeb6
--- /dev/null
+++ b/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),
+ ),
+ ]
diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py
index 0322b67c6..4dc775364 100644
--- a/netbox/circuits/models/circuits.py
+++ b/netbox/circuits/models/circuits.py
@@ -7,6 +7,7 @@ from circuits.choices import *
from dcim.models import CabledObjectModel
from netbox.models import ChangeLoggedModel, OrganizationalModel, PrimaryModel
from netbox.models.features import ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ImageAttachmentsMixin, TagsMixin
+from utilities.fields import ColorField
__all__ = (
'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
"Long Haul," "Metro," or "Out-of-Band".
"""
+ color = ColorField(
+ verbose_name=_('color'),
+ blank=True
+ )
+
def get_absolute_url(self):
return reverse('circuits:circuittype', args=[self.pk])
diff --git a/netbox/circuits/tables/circuits.py b/netbox/circuits/tables/circuits.py
index 6a05983e6..6ae727eca 100644
--- a/netbox/circuits/tables/circuits.py
+++ b/netbox/circuits/tables/circuits.py
@@ -28,6 +28,7 @@ class CircuitTypeTable(NetBoxTable):
linkify=True,
verbose_name=_('Name'),
)
+ color = columns.ColorColumn()
tags = columns.TagColumn(
url_name='circuits:circuittype_list'
)
@@ -40,7 +41,7 @@ class CircuitTypeTable(NetBoxTable):
class Meta(NetBoxTable.Meta):
model = CircuitType
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')
diff --git a/netbox/dcim/svg/cables.py b/netbox/dcim/svg/cables.py
index acc4fcad9..31e090078 100644
--- a/netbox/dcim/svg/cables.py
+++ b/netbox/dcim/svg/cables.py
@@ -159,6 +159,7 @@ class CableTraceSVG:
labels.append(location_label)
elif instance._meta.model_name == 'circuit':
labels[0] = f'Circuit {instance}'
+ labels.append(instance.type)
labels.append(instance.provider)
if instance.description:
labels.append(instance.description)
@@ -181,6 +182,8 @@ class CableTraceSVG:
if hasattr(instance, 'role'):
# Device
return instance.role.color
+ elif instance._meta.model_name == 'circuit' and instance.type.color:
+ return instance.type.color
else:
# Other parent object
return 'e0e0e0'
diff --git a/netbox/templates/circuits/circuittype.html b/netbox/templates/circuits/circuittype.html
index b8b08baf0..407ee4042 100644
--- a/netbox/templates/circuits/circuittype.html
+++ b/netbox/templates/circuits/circuittype.html
@@ -29,6 +29,16 @@