From 37d136386be299c6433ff5040465e9a23e20c8a4 Mon Sep 17 00:00:00 2001 From: Arthur Date: Fri, 21 Mar 2025 09:37:19 -0700 Subject: [PATCH] 18245 add group to device role --- docs/models/dcim/devicerole.md | 4 ++ netbox/dcim/api/serializers_/roles.py | 3 +- netbox/dcim/filtersets.py | 13 ++++ netbox/dcim/forms/bulk_edit.py | 9 ++- netbox/dcim/forms/bulk_import.py | 9 ++- netbox/dcim/forms/filtersets.py | 6 ++ netbox/dcim/forms/model_forms.py | 9 ++- netbox/dcim/models/devices.py | 4 ++ netbox/dcim/tables/devices.py | 10 +++- netbox/templates/dcim/devicerole.html | 4 ++ netbox/templates/dcim/devicerolegroup.html | 70 ++++++++++++++++++++++ 11 files changed, 132 insertions(+), 9 deletions(-) create mode 100644 netbox/templates/dcim/devicerolegroup.html diff --git a/docs/models/dcim/devicerole.md b/docs/models/dcim/devicerole.md index 786170f2b..3b4c2c012 100644 --- a/docs/models/dcim/devicerole.md +++ b/docs/models/dcim/devicerole.md @@ -12,6 +12,10 @@ A unique human-friendly name. A unique URL-friendly identifier. (This value can be used for filtering.) +### Group + +The [device role group](./devicerolegroup.md) to which this device role belongs (if any). + ### Color The color used when displaying the role in the NetBox UI. diff --git a/netbox/dcim/api/serializers_/roles.py b/netbox/dcim/api/serializers_/roles.py index a066b69df..8167eb898 100644 --- a/netbox/dcim/api/serializers_/roles.py +++ b/netbox/dcim/api/serializers_/roles.py @@ -28,6 +28,7 @@ class DeviceRoleGroupSerializer(NestedGroupModelSerializer): class DeviceRoleSerializer(NetBoxModelSerializer): config_template = ConfigTemplateSerializer(nested=True, required=False, allow_null=True, default=None) + group = DeviceRoleGroupSerializer(nested=True, required=False, allow_null=True, default=None) # Related object counts device_count = RelatedObjectCountField('devices') @@ -36,7 +37,7 @@ class DeviceRoleSerializer(NetBoxModelSerializer): class Meta: model = DeviceRole fields = [ - 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', + 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'group', 'vm_role', 'config_template', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count', ] brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count') diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 0092d3655..9e590b2bd 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -953,6 +953,19 @@ class DeviceRoleFilterSet(OrganizationalModelFilterSet): queryset=ConfigTemplate.objects.all(), label=_('Config template (ID)'), ) + group_id = TreeNodeMultipleChoiceFilter( + queryset=DeviceRoleGroup.objects.all(), + field_name='group', + lookup_expr='in', + label=_('Device role group (ID)'), + ) + group = TreeNodeMultipleChoiceFilter( + queryset=DeviceRoleGroup.objects.all(), + field_name='group', + lookup_expr='in', + to_field_name='slug', + label=_('Device role group (slug)'), + ) class Meta: model = DeviceRole diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index a14074512..aec52d286 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -634,6 +634,11 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): label=_('Color'), required=False ) + group = DynamicModelChoiceField( + label=_('Group'), + queryset=DeviceRoleGroup.objects.all(), + required=False + ) vm_role = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect, @@ -652,9 +657,9 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): model = DeviceRole fieldsets = ( - FieldSet('color', 'vm_role', 'config_template', 'description'), + FieldSet('color', 'group', 'vm_role', 'config_template', 'description'), ) - nullable_fields = ('color', 'config_template', 'description') + nullable_fields = ('color', 'group', 'config_template', 'description') class PlatformBulkEditForm(NetBoxModelBulkEditForm): diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index 9f84ea22e..8fd8a5751 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -483,11 +483,18 @@ class DeviceRoleImportForm(NetBoxModelImportForm): required=False, help_text=_('Config template') ) + group = CSVModelChoiceField( + label=_('Group'), + queryset=DeviceRoleGroup.objects.all(), + required=False, + to_field_name='name', + help_text=_('Assigned group') + ) slug = SlugField() class Meta: model = DeviceRole - fields = ('name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags') + fields = ('name', 'slug', 'group', 'color', 'vm_role', 'config_template', 'description', 'tags') class PlatformImportForm(NetBoxModelImportForm): diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 07764f023..1d0e0480f 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -700,6 +700,12 @@ class DeviceRoleFilterForm(NetBoxModelFilterSetForm): required=False, label=_('Config template') ) + group_id = DynamicModelMultipleChoiceField( + queryset=DeviceRoleGroup.objects.all(), + required=False, + null_option='None', + label=_('Group') + ) tag = TagFilterField(model) diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index ae184389c..9984afc7b 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -450,18 +450,23 @@ class DeviceRoleForm(NetBoxModelForm): queryset=ConfigTemplate.objects.all(), required=False ) + group = DynamicModelChoiceField( + label=_('Group'), + queryset=DeviceRoleGroup.objects.all(), + required=False + ) slug = SlugField() fieldsets = ( FieldSet( - 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', name=_('Device Role') + 'name', 'slug', 'group', 'color', 'vm_role', 'config_template', 'description', 'tags', name=_('Device Role') ), ) class Meta: model = DeviceRole fields = [ - 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags', + 'name', 'slug', 'group', 'color', 'vm_role', 'config_template', 'description', 'tags', ] diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 4c37d2124..f9db72585 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -522,6 +522,10 @@ class DeviceRole(OrganizationalModel): null=True ) + clone_fields = ( + 'group', 'description', + ) + class Meta: ordering = ('name',) verbose_name = _('device role') diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index cc99188ca..7919ef449 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -90,6 +90,10 @@ class DeviceRoleTable(NetBoxTable): verbose_name=_('Name'), linkify=True ) + group = tables.Column( + verbose_name=_('Group'), + linkify=True + ) device_count = columns.LinkedCountColumn( viewname='dcim:device_list', url_params={'role_id': 'pk'}, @@ -115,10 +119,10 @@ class DeviceRoleTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = models.DeviceRole fields = ( - 'pk', 'id', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'config_template', 'description', - 'slug', 'tags', 'actions', 'created', 'last_updated', + 'pk', 'id', 'name', 'group', 'device_count', 'vm_count', 'color', 'vm_role', + 'config_template', 'description', 'slug', 'tags', 'actions', 'created', 'last_updated', ) - default_columns = ('pk', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description') + default_columns = ('pk', 'name', 'group', 'device_count', 'vm_count', 'color', 'vm_role', 'description') # diff --git a/netbox/templates/dcim/devicerole.html b/netbox/templates/dcim/devicerole.html index d9e170af3..59f5ff5a3 100644 --- a/netbox/templates/dcim/devicerole.html +++ b/netbox/templates/dcim/devicerole.html @@ -26,6 +26,10 @@ {% trans "Name" %} {{ object.name }} + + {% trans "Group" %} + {{ object.group|linkify|placeholder }} + {% trans "Description" %} {{ object.description|placeholder }} diff --git a/netbox/templates/dcim/devicerolegroup.html b/netbox/templates/dcim/devicerolegroup.html new file mode 100644 index 000000000..2218ccadc --- /dev/null +++ b/netbox/templates/dcim/devicerolegroup.html @@ -0,0 +1,70 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} +{% load render_table from django_tables2 %} +{% load i18n %} + +{% block breadcrumbs %} + {{ block.super }} + {% for devicerolegroup in object.get_ancestors %} + + {% endfor %} +{% endblock %} + +{% block extra_controls %} + {% if perms.tenancy.add_tenant %} + + {% trans "Add Device Role" %} + + {% endif %} +{% endblock extra_controls %} + +{% block content %} +
+
+
+

{% trans "Device Role Group" %}

+ + + + + + + + + + + + + +
{% trans "Name" %}{{ object.name }}
{% trans "Description" %}{{ object.description|placeholder }}
{% trans "Parent" %}{{ object.parent|linkify|placeholder }}
+
+ {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_left_page object %} +
+
+ {% include 'inc/panels/related_objects.html' %} + {% include 'inc/panels/custom_fields.html' %} + {% plugin_right_page object %} +
+
+
+
+
+

+ {% trans "Child Groups" %} + {% if perms.dcim.add_devicerolegroup %} + + {% endif %} +

+ {% htmx_table 'dcim:devicerolegroup_list' parent_id=object.pk %} +
+ {% plugin_full_width_page object %} +
+
+{% endblock %}