From a5124ab9c835896ff434812bf870d1add82a3afe Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Fri, 1 Jul 2022 15:10:31 -0400 Subject: [PATCH] Closes #8511: Enable custom fields and tags for circuit terminations --- docs/release-notes/version-3.3.md | 3 + netbox/circuits/api/serializers.py | 4 +- netbox/circuits/filtersets.py | 2 +- netbox/circuits/forms/models.py | 4 +- netbox/circuits/graphql/types.py | 3 +- ...7_circuittermination_tags_custom_fields.py | 24 +++ netbox/circuits/models/circuits.py | 13 +- netbox/templates/circuits/circuit.html | 140 +++++++++--------- .../circuits/circuittermination_edit.html | 8 + .../circuits/inc/circuit_termination.html | 33 ++++- 10 files changed, 155 insertions(+), 79 deletions(-) create mode 100644 netbox/circuits/migrations/0037_circuittermination_tags_custom_fields.py diff --git a/docs/release-notes/version-3.3.md b/docs/release-notes/version-3.3.md index f5cb8eee1..d158e6cf9 100644 --- a/docs/release-notes/version-3.3.md +++ b/docs/release-notes/version-3.3.md @@ -28,6 +28,7 @@ * [#8222](https://github.com/netbox-community/netbox/issues/8222) - Enable the assignment of a VM to a specific host device within a cluster * [#8471](https://github.com/netbox-community/netbox/issues/8471) - Add `status` field to Cluster * [#8495](https://github.com/netbox-community/netbox/issues/8495) - Enable custom field grouping +* [#8511](https://github.com/netbox-community/netbox/issues/8511) - Enable custom fields and tags for circuit terminations * [#8995](https://github.com/netbox-community/netbox/issues/8995) - Enable arbitrary ordering of REST API results * [#9070](https://github.com/netbox-community/netbox/issues/9070) - Hide navigation menu items based on user permissions * [#9166](https://github.com/netbox-community/netbox/issues/9166) - Add UI visibility toggle for custom fields @@ -51,6 +52,8 @@ * circuits.Circuit * Added optional `termination_date` field +* circuits.CircuitTermination + * Added 'custom_fields' and 'tags' fields * dcim.Device * The `position` field has been changed from an integer to a decimal * dcim.DeviceType diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py index 2bb3cd266..844cfce89 100644 --- a/netbox/circuits/api/serializers.py +++ b/netbox/circuits/api/serializers.py @@ -98,7 +98,7 @@ class CircuitSerializer(NetBoxModelSerializer): ] -class CircuitTerminationSerializer(ValidatedModelSerializer, LinkTerminationSerializer): +class CircuitTerminationSerializer(NetBoxModelSerializer, LinkTerminationSerializer): url = serializers.HyperlinkedIdentityField(view_name='circuits-api:circuittermination-detail') circuit = NestedCircuitSerializer() site = NestedSiteSerializer(required=False, allow_null=True) @@ -110,5 +110,5 @@ class CircuitTerminationSerializer(ValidatedModelSerializer, LinkTerminationSeri fields = [ 'id', 'url', 'display', 'circuit', 'term_side', 'site', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'mark_connected', 'cable', 'link_peer', 'link_peer_type', - '_occupied', 'created', 'last_updated', + '_occupied', 'tags', 'custom_fields', 'created', 'last_updated', ] diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py index 67a0d1b02..a74ff5c5a 100644 --- a/netbox/circuits/filtersets.py +++ b/netbox/circuits/filtersets.py @@ -198,7 +198,7 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte ).distinct() -class CircuitTerminationFilterSet(ChangeLoggedModelFilterSet, CableTerminationFilterSet): +class CircuitTerminationFilterSet(NetBoxModelFilterSet, CableTerminationFilterSet): q = django_filters.CharFilter( method='search', label='Search', diff --git a/netbox/circuits/forms/models.py b/netbox/circuits/forms/models.py index 907c39586..7bd7abbbf 100644 --- a/netbox/circuits/forms/models.py +++ b/netbox/circuits/forms/models.py @@ -116,7 +116,7 @@ class CircuitForm(TenancyForm, NetBoxModelForm): } -class CircuitTerminationForm(BootstrapMixin, forms.ModelForm): +class CircuitTerminationForm(NetBoxModelForm): provider = DynamicModelChoiceField( queryset=Provider.objects.all(), required=False, @@ -161,7 +161,7 @@ class CircuitTerminationForm(BootstrapMixin, forms.ModelForm): model = CircuitTermination fields = [ 'provider', 'circuit', 'term_side', 'region', 'site_group', 'site', 'provider_network', 'mark_connected', - 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', + 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags', ] help_texts = { 'port_speed': "Physical circuit speed", diff --git a/netbox/circuits/graphql/types.py b/netbox/circuits/graphql/types.py index 027b53203..094b78d07 100644 --- a/netbox/circuits/graphql/types.py +++ b/netbox/circuits/graphql/types.py @@ -1,4 +1,5 @@ from circuits import filtersets, models +from extras.graphql.mixins import CustomFieldsMixin, TagsMixin from netbox.graphql.types import ObjectType, OrganizationalObjectType, NetBoxObjectType __all__ = ( @@ -10,7 +11,7 @@ __all__ = ( ) -class CircuitTerminationType(ObjectType): +class CircuitTerminationType(CustomFieldsMixin, TagsMixin, ObjectType): class Meta: model = models.CircuitTermination diff --git a/netbox/circuits/migrations/0037_circuittermination_tags_custom_fields.py b/netbox/circuits/migrations/0037_circuittermination_tags_custom_fields.py new file mode 100644 index 000000000..c87bc4219 --- /dev/null +++ b/netbox/circuits/migrations/0037_circuittermination_tags_custom_fields.py @@ -0,0 +1,24 @@ +import django.core.serializers.json +from django.db import migrations, models +import taggit.managers + + +class Migration(migrations.Migration): + + dependencies = [ + ('extras', '0076_configcontext_locations'), + ('circuits', '0036_circuit_termination_date'), + ] + + operations = [ + migrations.AddField( + model_name='circuittermination', + name='custom_field_data', + field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder), + ), + migrations.AddField( + model_name='circuittermination', + name='tags', + field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'), + ), + ] diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index 5df6f1b85..cf6ffc503 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -5,7 +5,9 @@ from django.urls import reverse from circuits.choices import * from dcim.models import LinkTermination -from netbox.models import ChangeLoggedModel, OrganizationalModel, NetBoxModel +from netbox.models import ( + ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, NetBoxModel, TagsMixin, +) from netbox.models.features import WebhooksMixin __all__ = ( @@ -141,7 +143,14 @@ class Circuit(NetBoxModel): return CircuitStatusChoices.colors.get(self.status) -class CircuitTermination(WebhooksMixin, ChangeLoggedModel, LinkTermination): +class CircuitTermination( + CustomFieldsMixin, + CustomLinksMixin, + TagsMixin, + WebhooksMixin, + ChangeLoggedModel, + LinkTermination +): circuit = models.ForeignKey( to='circuits.Circuit', on_delete=models.CASCADE, diff --git a/netbox/templates/circuits/circuit.html b/netbox/templates/circuits/circuit.html index a4c41f871..a11139032 100644 --- a/netbox/templates/circuits/circuit.html +++ b/netbox/templates/circuits/circuit.html @@ -8,74 +8,78 @@ {% endblock %} {% block content %} -
-
-
-
- Circuit -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Provider{{ object.provider|linkify }}
Circuit ID{{ object.cid }}
Type{{ object.type|linkify }}
Status{% badge object.get_status_display bg_color=object.get_status_color %}
Tenant - {% if object.tenant.group %} - {{ object.tenant.group|linkify }} / - {% endif %} - {{ object.tenant|linkify|placeholder }} -
Install Date{{ object.install_date|annotated_date|placeholder }}
Termination Date{{ object.termination_date|annotated_date|placeholder }}
Commit Rate{{ object.commit_rate|humanize_speed|placeholder }}
Description{{ object.description|placeholder }}
-
+
+
+
+
Circuit
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Provider{{ object.provider|linkify }}
Circuit ID{{ object.cid }}
Type{{ object.type|linkify }}
Status{% badge object.get_status_display bg_color=object.get_status_color %}
Tenant + {% if object.tenant.group %} + {{ object.tenant.group|linkify }} / + {% endif %} + {{ object.tenant|linkify|placeholder }} +
Install Date{{ object.install_date|annotated_date|placeholder }}
Termination Date{{ object.termination_date|annotated_date|placeholder }}
Commit Rate{{ object.commit_rate|humanize_speed|placeholder }}
Description{{ object.description|placeholder }}
- {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/tags.html' %} - {% include 'inc/panels/comments.html' %} - {% plugin_left_page object %} -
-
- {% include 'circuits/inc/circuit_termination.html' with termination=object.termination_a side='A' %} - {% include 'circuits/inc/circuit_termination.html' with termination=object.termination_z side='Z' %} - {% include 'inc/panels/contacts.html' %} - {% include 'inc/panels/image_attachments.html' %} - {% plugin_right_page object %} -
-
-
-
- {% plugin_full_width_page object %} +
+ {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/tags.html' %} + {% plugin_left_page object %}
-
+
+ {% include 'inc/panels/comments.html' %} + {% include 'inc/panels/contacts.html' %} + {% include 'inc/panels/image_attachments.html' %} + {% plugin_right_page object %} +
+
+
+
+ {% include 'circuits/inc/circuit_termination.html' with termination=object.termination_a side='A' %} +
+
+ {% include 'circuits/inc/circuit_termination.html' with termination=object.termination_z side='Z' %} +
+
+
+
+ {% plugin_full_width_page object %} +
+
{% endblock %} diff --git a/netbox/templates/circuits/circuittermination_edit.html b/netbox/templates/circuits/circuittermination_edit.html index f8393f945..606e12b5e 100644 --- a/netbox/templates/circuits/circuittermination_edit.html +++ b/netbox/templates/circuits/circuittermination_edit.html @@ -10,6 +10,7 @@ {% render_field form.provider %} {% render_field form.circuit %} {% render_field form.term_side %} + {% render_field form.tags %} {% render_field form.mark_connected %} {% with providernetwork_tab_active=form.initial.provider_network %}
@@ -47,6 +48,13 @@ {% render_field form.pp_info %} {% render_field form.description %}
+ +
+
+
Custom Fields
+
+ {% render_custom_fields form %} +
{% endblock %} {# Override buttons block, 'Create & Add Another'/'_addanother' is not needed on a circuit. #} diff --git a/netbox/templates/circuits/inc/circuit_termination.html b/netbox/templates/circuits/inc/circuit_termination.html index b673cd4a3..f6bb377ec 100644 --- a/netbox/templates/circuits/inc/circuit_termination.html +++ b/netbox/templates/circuits/inc/circuit_termination.html @@ -2,7 +2,6 @@
- Termination - {{ side }} Side
{% if not termination and perms.circuits.add_circuittermination %} @@ -10,10 +9,10 @@ {% endif %} {% if termination and perms.circuits.change_circuittermination %} - + Edit - + Swap {% endif %} @@ -23,6 +22,7 @@ {% endif %}
+
Termination {{ side }}
{% if termination %} @@ -110,6 +110,33 @@ Description {{ termination.description|placeholder }} + + Tags + + {% for tag in termination.tags.all %} + {% tag tag %} + {% empty %} + {{ ''|placeholder }} + {% endfor %} + + + {% for group_name, fields in termination.get_custom_fields_by_group.items %} + + + {{ group_name|default:"Custom Fields" }} + + + {% for field, value in fields.items %} + + + {{ field }} + + + {% customfield_value field value %} + + + {% endfor %} + {% endfor %} {% else %} None