#9166 - Add UI Visibility setting for custom fields

This commit is contained in:
kkthxbye 2022-05-24 10:12:32 +02:00
parent 64146b8cb1
commit 20eaa7d069
14 changed files with 84 additions and 13 deletions

View File

@ -84,13 +84,14 @@ class CustomFieldSerializer(ValidatedModelSerializer):
)
filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
data_type = serializers.SerializerMethodField()
ui_visibility = ChoiceField(choices=CustomFieldVisibilityChoices, required=False)
class Meta:
model = CustomField
fields = [
'id', 'url', 'display', 'content_types', 'type', 'object_type', 'data_type', 'name', 'label', 'group_name',
'description', 'required', 'filter_logic', 'default', 'weight', 'validation_minimum', 'validation_maximum',
'validation_regex', 'choices', 'created', 'last_updated',
'validation_regex', 'choices', 'created', 'last_updated', 'ui_visibility',
]
def get_data_type(self, obj):

View File

@ -47,6 +47,19 @@ class CustomFieldFilterLogicChoices(ChoiceSet):
)
class CustomFieldVisibilityChoices(ChoiceSet):
VISIBILITY_READ_WRITE = 'read-write'
VISIBILITY_READ_ONLY = 'read-only'
VISIBILITY_HIDDEN = 'hidden'
CHOICES = (
(VISIBILITY_READ_WRITE, 'Read/Write'),
(VISIBILITY_READ_ONLY, 'Read-only'),
(VISIBILITY_HIDDEN, 'Hidden'),
)
#
# CustomLinks
#

View File

@ -62,7 +62,9 @@ class CustomFieldFilterSet(BaseFilterSet):
class Meta:
model = CustomField
fields = ['id', 'content_types', 'name', 'group_name', 'required', 'filter_logic', 'weight', 'description']
fields = [
'id', 'content_types', 'name', 'group_name', 'required', 'filter_logic', 'weight', 'description', 'ui_visibility'
]
def search(self, queryset, name, value):
if not value.strip():

View File

@ -37,6 +37,13 @@ class CustomFieldBulkEditForm(BulkEditForm):
weight = forms.IntegerField(
required=False
)
ui_visibility = forms.ChoiceField(
label="UI visibility",
choices=add_blank_choice(CustomFieldVisibilityChoices),
required=False,
initial='',
widget=StaticSelect()
)
nullable_fields = ('group_name', 'description',)

View File

@ -37,7 +37,7 @@ class CustomFieldCSVForm(CSVModelForm):
model = CustomField
fields = (
'name', 'label', 'group_name', 'type', 'content_types', 'required', 'description', 'weight', 'filter_logic',
'default', 'choices', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex',
'default', 'choices', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex', 'ui_visibility',
)

View File

@ -1,6 +1,7 @@
from django.contrib.contenttypes.models import ContentType
from extras.models import *
from extras.choices import CustomFieldVisibilityChoices
__all__ = (
'CustomFieldsMixin',
@ -42,8 +43,14 @@ class CustomFieldsMixin:
Append form fields for all CustomFields assigned to this object type.
"""
for customfield in self._get_custom_fields(self._get_content_type()):
if customfield.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_HIDDEN:
continue
field_name = f'cf_{customfield.name}'
self.fields[field_name] = self._get_form_field(customfield)
if customfield.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_READ_ONLY:
self.fields[field_name].disabled = True
# Annotate the field in the list of CustomField form fields
self.custom_fields[field_name] = customfield

View File

@ -32,7 +32,7 @@ __all__ = (
class CustomFieldFilterForm(FilterForm):
fieldsets = (
(None, ('q',)),
('Attributes', ('content_types', 'type', 'group_name', 'weight', 'required')),
('Attributes', ('content_types', 'type', 'group_name', 'weight', 'required', 'ui_visibility')),
)
content_types = ContentTypeMultipleChoiceField(
queryset=ContentType.objects.all(),
@ -56,6 +56,12 @@ class CustomFieldFilterForm(FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
ui_visibility = forms.ChoiceField(
choices=add_blank_choice(CustomFieldVisibilityChoices),
required=False,
label=_('UI Visibility'),
widget=StaticSelect()
)
class CustomLinkFilterForm(FilterForm):

View File

@ -41,7 +41,7 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
fieldsets = (
('Custom Field', (
'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'weight', 'required', 'description',
'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'weight', 'required', 'description', 'ui_visibility',
)),
('Behavior', ('filter_logic',)),
('Values', ('default', 'choices')),
@ -58,6 +58,7 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
widgets = {
'type': StaticSelect(),
'filter_logic': StaticSelect(),
'ui_visibility': StaticSelect(),
}

View File

@ -0,0 +1,18 @@
# Generated by Django 4.0.4 on 2022-05-23 20:23
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('extras', '0074_customfield_group_name'),
]
operations = [
migrations.AddField(
model_name='customfield',
name='ui_visibility',
field=models.CharField(default='read-write', max_length=50),
),
]

View File

@ -136,6 +136,12 @@ class CustomField(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
null=True,
help_text='Comma-separated list of available choices (for selection fields)'
)
ui_visibility = models.CharField(
max_length=50,
choices=CustomFieldVisibilityChoices,
default=CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE,
help_text='Specifies the visibility of custom field in the UI.'
)
objects = CustomFieldManager()
class Meta:

View File

@ -28,12 +28,13 @@ class CustomFieldTable(NetBoxTable):
)
content_types = columns.ContentTypesColumn()
required = columns.BooleanColumn()
ui_visibility = columns.ChoiceFieldColumn(verbose_name="UI visibility")
class Meta(NetBoxTable.Meta):
model = CustomField
fields = (
'pk', 'id', 'name', 'content_types', 'label', 'type', 'group_name', 'required', 'weight', 'default',
'description', 'filter_logic', 'choices', 'created', 'last_updated',
'description', 'filter_logic', 'choices', 'created', 'last_updated', 'ui_visibility',
)
default_columns = ('pk', 'name', 'content_types', 'label', 'group_name', 'type', 'required', 'description')

View File

@ -36,13 +36,14 @@ class CustomFieldTestCase(ViewTestCases.PrimaryObjectViewTestCase):
'default': None,
'weight': 200,
'required': True,
'ui_visibility': CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE,
}
cls.csv_data = (
'name,label,type,content_types,weight,filter_logic,choices,validation_minimum,validation_maximum,validation_regex',
'field4,Field 4,text,dcim.site,100,exact,,,,[a-z]{3}',
'field5,Field 5,integer,dcim.site,100,exact,,1,100,',
'field6,Field 6,select,dcim.site,100,exact,"A,B,C",,,',
'name,label,type,content_types,weight,filter_logic,choices,validation_minimum,validation_maximum,validation_regex,ui_visibility',
'field4,Field 4,text,dcim.site,100,exact,,,,[a-z]{3},read-write',
'field5,Field 5,integer,dcim.site,100,exact,,1,100,,read-write',
'field6,Field 6,select,dcim.site,100,exact,"A,B,C",,,,read-write',
)
cls.bulk_edit_data = {

View File

@ -9,7 +9,7 @@ from django.core.validators import ValidationError
from django.db import models
from taggit.managers import TaggableManager
from extras.choices import ObjectChangeActionChoices
from extras.choices import CustomFieldVisibilityChoices, ObjectChangeActionChoices
from extras.utils import register_features
from netbox.signals import post_clean
from utilities.utils import serialize_object
@ -100,7 +100,7 @@ class CustomFieldsMixin(models.Model):
"""
return self.custom_field_data
def get_custom_fields(self):
def get_custom_fields(self, omit_hidden=False):
"""
Return a dictionary of custom fields for a single object in the form `{field: value}`.
@ -114,6 +114,10 @@ class CustomFieldsMixin(models.Model):
data = {}
for field in CustomField.objects.get_for_model(self):
# Skip fields that are hidden if 'omit_hidden' is set
if omit_hidden and field.ui_visibility == CustomFieldVisibilityChoices.VISIBILITY_HIDDEN:
continue
value = self.custom_field_data.get(field.name)
data[field] = field.deserialize(value)
@ -124,7 +128,7 @@ class CustomFieldsMixin(models.Model):
Return a dictionary of custom field/value mappings organized by group.
"""
grouped_custom_fields = defaultdict(dict)
for cf, value in self.get_custom_fields().items():
for cf, value in self.get_custom_fields(omit_hidden=True).items():
grouped_custom_fields[cf.group_name][cf] = value
return dict(grouped_custom_fields)

View File

@ -42,6 +42,10 @@
<th scope="row">Weight</th>
<td>{{ object.weight }}</td>
</tr>
<tr>
<th scope="row">UI Visibility</th>
<td>{{ object.get_ui_visibility_display }}</td>
</tr>
</table>
</div>
</div>