Misc cleanup

This commit is contained in:
Jeremy Stretch 2023-07-27 09:28:31 -04:00
parent 9f93c028f1
commit d8da99f225
9 changed files with 31 additions and 23 deletions

View File

@ -1,6 +1,8 @@
# Custom Field Choice Sets # Custom Field Choice Sets
Single- and multi-selection [custom fields documentation](../../customization/custom-fields.md) must define a set of valid choices from which the user may choose when defining the field value. These choices are defined as sets that may be reused among multiple custom fields. Single- and multi-selection [custom fields](../../customization/custom-fields.md) must define a set of valid choices from which the user may choose when defining the field value. These choices are defined as sets that may be reused among multiple custom fields.
A choice set must define a base choice set and/or a set of arbitrary extra choices.
## Fields ## Fields
@ -12,12 +14,13 @@ The human-friendly name of the choice set.
The set of pre-defined choices to include. Available sets are listed below. This is an optional setting. The set of pre-defined choices to include. Available sets are listed below. This is an optional setting.
* IATA airport codes
* ISO 3166 - Two-letter country codes * ISO 3166 - Two-letter country codes
* UN/LOCODE - Five-character location identifiers * UN/LOCODE - Five-character location identifiers
### Extra Choices ### Extra Choices
A list of additional choices, one per line. A set of custom choices that will be appended to the base choice set (if any).
### Order Alphabetically ### Order Alphabetically

View File

@ -78,13 +78,10 @@ class CustomFieldChoiceSetViewSet(NetBoxModelViewSet):
q = q.lower() q = q.lower()
choices = [c for c in choices if q in c[0].lower() or q in c[1].lower()] choices = [c for c in choices if q in c[0].lower() or q in c[1].lower()]
page = self.paginate_queryset(choices) # Paginate data
if page is not None: if page := self.paginate_queryset(choices):
data = [ data = [
{ {'value': c[0], 'label': c[1]} for c in page
'value': c[0],
'label': c[1],
} for c in page
] ]
return self.get_paginated_response(data) return self.get_paginated_response(data)

View File

@ -73,9 +73,9 @@ class CustomFieldChoiceSetBaseChoices(ChoiceSet):
UN_LOCODE = 'UN_LOCODE' UN_LOCODE = 'UN_LOCODE'
CHOICES = ( CHOICES = (
(IATA, 'IATA'), (IATA, 'IATA (Airport codes)'),
(ISO_3166, 'ISO 3166'), (ISO_3166, 'ISO 3166 (Country codes)'),
(UN_LOCODE, 'UN/LOCODE'), (UN_LOCODE, 'UN/LOCODE (Location codes)'),
) )

View File

@ -66,7 +66,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm):
base_choices = CSVChoiceField( base_choices = CSVChoiceField(
choices=CustomFieldChoiceSetBaseChoices, choices=CustomFieldChoiceSetBaseChoices,
required=False, required=False,
help_text=_('The classification of entry') help_text=_('The base set of predefined choices to use (if any)')
) )
class Meta: class Meta:

View File

@ -19,7 +19,6 @@ from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, CommentField, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField,
DynamicModelMultipleChoiceField, JSONField, SlugField, DynamicModelMultipleChoiceField, JSONField, SlugField,
) )
from utilities.forms.widgets import ChoicesWidget
from virtualization.models import Cluster, ClusterGroup, ClusterType from virtualization.models import Cluster, ClusterGroup, ClusterType

View File

@ -410,7 +410,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
# Select # Select
elif self.type in (CustomFieldTypeChoices.TYPE_SELECT, CustomFieldTypeChoices.TYPE_MULTISELECT): elif self.type in (CustomFieldTypeChoices.TYPE_SELECT, CustomFieldTypeChoices.TYPE_MULTISELECT):
choices = self.choices choices = self.choice_set.choices
default_choice = self.default if self.default in self.choices else None default_choice = self.default if self.default in self.choices else None
if not required or default_choice is None: if not required or default_choice is None:
@ -427,7 +427,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
field_class = CSVMultipleChoiceField if for_csv_import else DynamicMultipleChoiceField field_class = CSVMultipleChoiceField if for_csv_import else DynamicMultipleChoiceField
widget_class = APISelectMultiple widget_class = APISelectMultiple
field = field_class( field = field_class(
choices=self.choice_set.choices, choices=choices,
required=required, required=required,
initial=initial, initial=initial,
widget=widget_class(api_url=f'/api/extras/custom-field-choices/{self.choice_set.pk}/choices/') widget=widget_class(api_url=f'/api/extras/custom-field-choices/{self.choice_set.pk}/choices/')
@ -664,7 +664,7 @@ class CustomFieldChoiceSet(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel
) )
order_alphabetically = models.BooleanField( order_alphabetically = models.BooleanField(
default=False, default=False,
help_text=_('Choices are automatically ordered alphabetically on save') help_text=_('Choices are automatically ordered alphabetically')
) )
clone_fields = ('extra_choices', 'order_alphabetically') clone_fields = ('extra_choices', 'order_alphabetically')

View File

@ -64,11 +64,9 @@ class CustomFieldTable(NetBoxTable):
) )
content_types = columns.ContentTypesColumn() content_types = columns.ContentTypesColumn()
required = columns.BooleanColumn() required = columns.BooleanColumn()
ui_visibility = columns.ChoiceFieldColumn( ui_visibility = columns.ChoiceFieldColumn(verbose_name="UI visibility")
verbose_name="UI visibility"
)
description = columns.MarkdownColumn() description = columns.MarkdownColumn()
choices = columns.ChoiceSetColumn( choices = columns.ChoicesColumn(
max_items=10, max_items=10,
orderable=False orderable=False
) )
@ -92,7 +90,7 @@ class CustomFieldChoiceSetTable(NetBoxTable):
extra_choices = tables.TemplateColumn( extra_choices = tables.TemplateColumn(
template_code="""{% for k, v in value.items %}{{ v }}{% if not forloop.last %}, {% endif %}{% endfor %}""" template_code="""{% for k, v in value.items %}{{ v }}{% if not forloop.last %}, {% endif %}{% endfor %}"""
) )
choices = columns.ChoiceSetColumn( choices = columns.ChoicesColumn(
max_items=10, max_items=10,
orderable=False orderable=False
) )

View File

@ -24,7 +24,7 @@ __all__ = (
'ArrayColumn', 'ArrayColumn',
'BooleanColumn', 'BooleanColumn',
'ChoiceFieldColumn', 'ChoiceFieldColumn',
'ChoiceSetColumn', 'ChoicesColumn',
'ColorColumn', 'ColorColumn',
'ColoredLabelColumn', 'ColoredLabelColumn',
'ContentTypeColumn', 'ContentTypeColumn',
@ -623,7 +623,7 @@ class ArrayColumn(tables.Column):
return ', '.join(value) return ', '.join(value)
class ChoiceSetColumn(tables.Column): class ChoicesColumn(tables.Column):
""" """
Display the human-friendly labels of a set of choices. Display the human-friendly labels of a set of choices.
""" """

View File

@ -1,6 +1,7 @@
from django import forms from django import forms
__all__ = ( __all__ = (
'ArrayWidget',
'ChoicesWidget', 'ChoicesWidget',
'ClearableFileInput', 'ClearableFileInput',
'MarkdownWidget', 'MarkdownWidget',
@ -46,6 +47,16 @@ class SlugWidget(forms.TextInput):
template_name = 'widgets/sluginput.html' template_name = 'widgets/sluginput.html'
class ArrayWidget(forms.Textarea):
"""
Render each item of an array on a new line within a textarea for easy editing/
"""
def format_value(self, value):
if value is None or not len(value):
return None
return '\n'.join(value)
class ChoicesWidget(forms.Textarea): class ChoicesWidget(forms.Textarea):
""" """
Render each key-value pair of a dictionary on a new line within a textarea for easy editing. Render each key-value pair of a dictionary on a new line within a textarea for easy editing.