13149 add gettext_lazy to forms

This commit is contained in:
Arthur 2023-07-13 12:47:40 +07:00 committed by Jeremy Stretch
parent f849a63401
commit 7fb81a0b4c
6 changed files with 131 additions and 69 deletions

View File

@ -2,7 +2,7 @@ from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.forms import SimpleArrayField from django.contrib.postgres.forms import SimpleArrayField
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from extras.choices import CustomFieldVisibilityChoices, CustomFieldTypeChoices, JournalEntryKindChoices from extras.choices import CustomFieldVisibilityChoices, CustomFieldTypeChoices, JournalEntryKindChoices
from extras.models import * from extras.models import *
@ -28,27 +28,32 @@ __all__ = (
class CustomFieldImportForm(CSVModelForm): class CustomFieldImportForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
help_text=_("One or more assigned object types") help_text=_("One or more assigned object types")
) )
type = CSVChoiceField( type = CSVChoiceField(
label=_('Type'),
choices=CustomFieldTypeChoices, choices=CustomFieldTypeChoices,
help_text=_('Field data type (e.g. text, integer, etc.)') help_text=_('Field data type (e.g. text, integer, etc.)')
) )
object_type = CSVContentTypeField( object_type = CSVContentTypeField(
label=_('Object type'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
required=False, required=False,
help_text=_("Object type (for object or multi-object fields)") help_text=_("Object type (for object or multi-object fields)")
) )
choice_set = CSVModelChoiceField( choice_set = CSVModelChoiceField(
label=_('Choice set'),
queryset=CustomFieldChoiceSet.objects.all(), queryset=CustomFieldChoiceSet.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text=_('Choice set (for selection fields)') help_text=_('Choice set (for selection fields)')
) )
ui_visibility = CSVChoiceField( ui_visibility = CSVChoiceField(
label=_('Ui visitility'),
choices=CustomFieldVisibilityChoices, choices=CustomFieldVisibilityChoices,
help_text=_('How the custom field is displayed in the user interface') help_text=_('How the custom field is displayed in the user interface')
) )
@ -78,6 +83,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm):
class CustomLinkImportForm(CSVModelForm): class CustomLinkImportForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_links'), limit_choices_to=FeatureQuery('custom_links'),
help_text=_("One or more assigned object types") help_text=_("One or more assigned object types")
@ -93,6 +99,7 @@ class CustomLinkImportForm(CSVModelForm):
class ExportTemplateImportForm(CSVModelForm): class ExportTemplateImportForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('export_templates'), limit_choices_to=FeatureQuery('export_templates'),
help_text=_("One or more assigned object types") help_text=_("One or more assigned object types")
@ -116,6 +123,7 @@ class ConfigTemplateImportForm(CSVModelForm):
class SavedFilterImportForm(CSVModelForm): class SavedFilterImportForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
help_text=_("One or more assigned object types") help_text=_("One or more assigned object types")
) )
@ -129,6 +137,7 @@ class SavedFilterImportForm(CSVModelForm):
class WebhookImportForm(CSVModelForm): class WebhookImportForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('webhooks'), limit_choices_to=FeatureQuery('webhooks'),
help_text=_("One or more assigned object types") help_text=_("One or more assigned object types")
@ -144,7 +153,9 @@ class WebhookImportForm(CSVModelForm):
class TagImportForm(CSVModelForm): class TagImportForm(CSVModelForm):
slug = SlugField() slug = SlugField(
label=_('Slug'),
)
class Meta: class Meta:
model = Tag model = Tag
@ -160,6 +171,7 @@ class JournalEntryImportForm(NetBoxModelImportForm):
label=_('Assigned object type'), label=_('Assigned object type'),
) )
kind = CSVChoiceField( kind = CSVChoiceField(
label=_('Kind'),
choices=JournalEntryKindChoices, choices=JournalEntryKindChoices,
help_text=_('The classification of entry') help_text=_('The classification of entry')
) )

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from core.models import DataFile, DataSource from core.models import DataFile, DataSource
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
@ -37,7 +37,7 @@ __all__ = (
class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
('Attributes', ( (_('Attributes'), (
'type', 'content_type_id', 'group_name', 'weight', 'required', 'choice_set_id', 'ui_visibility', 'type', 'content_type_id', 'group_name', 'weight', 'required', 'choice_set_id', 'ui_visibility',
'is_cloneable', 'is_cloneable',
)), )),
@ -53,12 +53,15 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
label=_('Field type') label=_('Field type')
) )
group_name = forms.CharField( group_name = forms.CharField(
label=_('Group name'),
required=False required=False
) )
weight = forms.IntegerField( weight = forms.IntegerField(
label=_('Weight'),
required=False required=False
) )
required = forms.NullBooleanField( required = forms.NullBooleanField(
label=_('Required'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
@ -75,6 +78,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
label=_('UI visibility') label=_('UI visibility')
) )
is_cloneable = forms.NullBooleanField( is_cloneable = forms.NullBooleanField(
label=_('Is cloneable'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
@ -97,22 +101,26 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
(_('Attributes'), ('content_types', 'enabled', 'new_window', 'weight')), (_('Attributes'), ('content_types', 'enabled', 'new_window', 'weight')),
) )
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.filter(FeatureQuery('custom_links').get_query()), queryset=ContentType.objects.filter(FeatureQuery('custom_links').get_query()),
required=False required=False
) )
enabled = forms.NullBooleanField( enabled = forms.NullBooleanField(
label=_('Enabled'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
new_window = forms.NullBooleanField( new_window = forms.NullBooleanField(
label=_('New window'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
weight = forms.IntegerField( weight = forms.IntegerField(
label=_('Weight'),
required=False required=False
) )
@ -120,8 +128,8 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
('Data', ('data_source_id', 'data_file_id')), (_('Data'), ('data_source_id', 'data_file_id')),
('Attributes', ('content_types', 'mime_type', 'file_extension', 'as_attachment')), (_('Attributes'), ('content_types', 'mime_type', 'file_extension', 'as_attachment')),
) )
data_source_id = DynamicModelMultipleChoiceField( data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(), queryset=DataSource.objects.all(),
@ -137,6 +145,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
} }
) )
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()),
required=False required=False
) )
@ -145,9 +154,11 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
label=_('MIME type') label=_('MIME type')
) )
file_extension = forms.CharField( file_extension = forms.CharField(
label=_('File extension'),
required=False required=False
) )
as_attachment = forms.NullBooleanField( as_attachment = forms.NullBooleanField(
label=_('As attachment'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
@ -158,13 +169,15 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm): class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
('Attributes', ('content_type_id', 'name',)), (_('Attributes'), ('content_type_id', 'name',)),
) )
content_type_id = ContentTypeChoiceField( content_type_id = ContentTypeChoiceField(
label=_('Content type id'),
queryset=ContentType.objects.filter(FeatureQuery('custom_fields').get_query()), queryset=ContentType.objects.filter(FeatureQuery('custom_fields').get_query()),
required=False required=False
) )
name = forms.CharField( name = forms.CharField(
label=_('Name'),
required=False required=False
) )
@ -172,25 +185,29 @@ class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
('Attributes', ('content_types', 'enabled', 'shared', 'weight')), (_('Attributes'), ('content_types', 'enabled', 'shared', 'weight')),
) )
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()),
required=False required=False
) )
enabled = forms.NullBooleanField( enabled = forms.NullBooleanField(
label=_('Enabled'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
shared = forms.NullBooleanField( shared = forms.NullBooleanField(
label=_('Shared'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
weight = forms.IntegerField( weight = forms.IntegerField(
label=_('Weight'),
required=False required=False
) )
@ -198,8 +215,8 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
class WebhookFilterForm(SavedFiltersMixin, FilterForm): class WebhookFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
('Attributes', ('content_type_id', 'http_method', 'enabled')), (_('Attributes'), ('content_type_id', 'http_method', 'enabled')),
('Events', ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), (_('Events'), ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')),
) )
content_type_id = ContentTypeMultipleChoiceField( content_type_id = ContentTypeMultipleChoiceField(
queryset=ContentType.objects.filter(FeatureQuery('webhooks').get_query()), queryset=ContentType.objects.filter(FeatureQuery('webhooks').get_query()),
@ -212,6 +229,7 @@ class WebhookFilterForm(SavedFiltersMixin, FilterForm):
label=_('HTTP method') label=_('HTTP method')
) )
enabled = forms.NullBooleanField( enabled = forms.NullBooleanField(
label=_('Enabled'),
required=False, required=False,
widget=forms.Select( widget=forms.Select(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
@ -271,11 +289,11 @@ class TagFilterForm(SavedFiltersMixin, FilterForm):
class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id', 'tag_id')), (None, ('q', 'filter_id', 'tag_id')),
('Data', ('data_source_id', 'data_file_id')), (_('Data'), ('data_source_id', 'data_file_id')),
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')), (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id')),
('Device', ('device_type_id', 'platform_id', 'role_id')), (_('Device'), ('device_type_id', 'platform_id', 'role_id')),
('Cluster', ('cluster_type_id', 'cluster_group_id', 'cluster_id')), (_('Cluster'), ('cluster_type_id', 'cluster_group_id', 'cluster_id')),
('Tenant', ('tenant_group_id', 'tenant_id')) (_('Tenant'), ('tenant_group_id', 'tenant_id'))
) )
data_source_id = DynamicModelMultipleChoiceField( data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(), queryset=DataSource.objects.all(),
@ -361,7 +379,7 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id', 'tag')), (None, ('q', 'filter_id', 'tag')),
('Data', ('data_source_id', 'data_file_id')), (_('Data'), ('data_source_id', 'data_file_id')),
) )
data_source_id = DynamicModelMultipleChoiceField( data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(), queryset=DataSource.objects.all(),
@ -393,8 +411,8 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm):
model = JournalEntry model = JournalEntry
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id', 'tag')), (None, ('q', 'filter_id', 'tag')),
('Creation', ('created_before', 'created_after', 'created_by_id')), (_('Creation'), ('created_before', 'created_after', 'created_by_id')),
('Attributes', ('assigned_object_type_id', 'kind')) (_('Attributes'), ('assigned_object_type_id', 'kind'))
) )
created_after = forms.DateTimeField( created_after = forms.DateTimeField(
required=False, required=False,
@ -423,6 +441,7 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm):
) )
) )
kind = forms.ChoiceField( kind = forms.ChoiceField(
label=_('Kind'),
choices=add_blank_choice(JournalEntryKindChoices), choices=add_blank_choice(JournalEntryKindChoices),
required=False required=False
) )
@ -433,8 +452,8 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm):
model = ObjectChange model = ObjectChange
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id')), (None, ('q', 'filter_id')),
('Time', ('time_before', 'time_after')), (_('Time'), ('time_before', 'time_after')),
('Attributes', ('action', 'user_id', 'changed_object_type_id')), (_('Attributes'), ('action', 'user_id', 'changed_object_type_id')),
) )
time_after = forms.DateTimeField( time_after = forms.DateTimeField(
required=False, required=False,
@ -447,6 +466,7 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm):
widget=DateTimePicker() widget=DateTimePicker()
) )
action = forms.ChoiceField( action = forms.ChoiceField(
label=_('Action'),
choices=add_blank_choice(ObjectChangeActionChoices), choices=add_blank_choice(ObjectChangeActionChoices),
required=False required=False
) )

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _
__all__ = ( __all__ = (
'RenderMarkdownForm', 'RenderMarkdownForm',
@ -10,5 +11,6 @@ class RenderMarkdownForm(forms.Form):
Provides basic validation for markup to be rendered. Provides basic validation for markup to be rendered.
""" """
text = forms.CharField( text = forms.CharField(
label=_('Text'),
required=False required=False
) )

View File

@ -4,7 +4,7 @@ from django import forms
from django.conf import settings from django.conf import settings
from django.db.models import Q from django.db.models import Q
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from core.forms.mixins import SyncedDataMixin from core.forms.mixins import SyncedDataMixin
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
@ -42,10 +42,12 @@ __all__ = (
class CustomFieldForm(BootstrapMixin, forms.ModelForm): class CustomFieldForm(BootstrapMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
) )
object_type = ContentTypeChoiceField( object_type = ContentTypeChoiceField(
label=_('Object type'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
# TODO: Come up with a canonical way to register suitable models # TODO: Come up with a canonical way to register suitable models
limit_choices_to=FeatureQuery('webhooks').get_query() | Q(app_label='auth', model__in=['user', 'group']), limit_choices_to=FeatureQuery('webhooks').get_query() | Q(app_label='auth', model__in=['user', 'group']),
@ -58,12 +60,12 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
) )
fieldsets = ( fieldsets = (
('Custom Field', ( (_('Custom Field'), (
'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'required', 'description', 'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'required', 'description',
)), )),
('Behavior', ('search_weight', 'filter_logic', 'ui_visibility', 'weight', 'is_cloneable')), (_('Behavior'), ('search_weight', 'filter_logic', 'ui_visibility', 'weight', 'is_cloneable')),
('Values', ('default', 'choice_set')), (_('Values'), ('default', 'choice_set')),
('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')), (_('Validation'), ('validation_minimum', 'validation_maximum', 'validation_regex')),
) )
class Meta: class Meta:
@ -100,13 +102,14 @@ class CustomFieldChoiceSetForm(BootstrapMixin, forms.ModelForm):
class CustomLinkForm(BootstrapMixin, forms.ModelForm): class CustomLinkForm(BootstrapMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_links') limit_choices_to=FeatureQuery('custom_links')
) )
fieldsets = ( fieldsets = (
('Custom Link', ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), (_('Custom Link'), ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')),
('Templates', ('link_text', 'link_url')), (_('Templates'), ('link_text', 'link_url')),
) )
class Meta: class Meta:
@ -127,18 +130,20 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm):
class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('export_templates') limit_choices_to=FeatureQuery('export_templates')
) )
template_code = forms.CharField( template_code = forms.CharField(
label=_('Template code'),
required=False, required=False,
widget=forms.Textarea(attrs={'class': 'font-monospace'}) widget=forms.Textarea(attrs={'class': 'font-monospace'})
) )
fieldsets = ( fieldsets = (
('Export Template', ('name', 'content_types', 'description', 'template_code')), (_('Export Template'), ('name', 'content_types', 'description', 'template_code')),
('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')),
('Rendering', ('mime_type', 'file_extension', 'as_attachment')), (_('Rendering'), ('mime_type', 'file_extension', 'as_attachment')),
) )
class Meta: class Meta:
@ -159,7 +164,7 @@ class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
super().clean() super().clean()
if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'): if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'):
raise forms.ValidationError("Must specify either local content or a data file") raise forms.ValidationError(_("Must specify either local content or a data file"))
return self.cleaned_data return self.cleaned_data
@ -167,13 +172,14 @@ class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
class SavedFilterForm(BootstrapMixin, forms.ModelForm): class SavedFilterForm(BootstrapMixin, forms.ModelForm):
slug = SlugField() slug = SlugField()
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.all() queryset=ContentType.objects.all()
) )
parameters = JSONField() parameters = JSONField()
fieldsets = ( fieldsets = (
('Saved Filter', ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')), (_('Saved Filter'), ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')),
('Parameters', ('parameters',)), (_('Parameters'), ('parameters',)),
) )
class Meta: class Meta:
@ -192,6 +198,7 @@ class SavedFilterForm(BootstrapMixin, forms.ModelForm):
class BookmarkForm(BootstrapMixin, forms.ModelForm): class BookmarkForm(BootstrapMixin, forms.ModelForm):
object_type = ContentTypeChoiceField( object_type = ContentTypeChoiceField(
label=_('Object type'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('bookmarks').get_query() limit_choices_to=FeatureQuery('bookmarks').get_query()
) )
@ -203,29 +210,30 @@ class BookmarkForm(BootstrapMixin, forms.ModelForm):
class WebhookForm(BootstrapMixin, forms.ModelForm): class WebhookForm(BootstrapMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
label=_('Content types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('webhooks') limit_choices_to=FeatureQuery('webhooks')
) )
fieldsets = ( fieldsets = (
('Webhook', ('name', 'content_types', 'enabled')), (_('Webhook'), ('name', 'content_types', 'enabled')),
('Events', ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), (_('Events'), ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')),
('HTTP Request', ( (_('HTTP Request'), (
'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret',
)), )),
('Conditions', ('conditions',)), (_('Conditions'), ('conditions',)),
('SSL', ('ssl_verification', 'ca_file_path')), (_('SSL'), ('ssl_verification', 'ca_file_path')),
) )
class Meta: class Meta:
model = Webhook model = Webhook
fields = '__all__' fields = '__all__'
labels = { labels = {
'type_create': 'Creations', 'type_create': _('Creations'),
'type_update': 'Updates', 'type_update': _('Updates'),
'type_delete': 'Deletions', 'type_delete': _('Deletions'),
'type_job_start': 'Job executions', 'type_job_start': _('Job executions'),
'type_job_end': 'Job terminations', 'type_job_end': _('Job terminations'),
} }
widgets = { widgets = {
'additional_headers': forms.Textarea(attrs={'class': 'font-monospace'}), 'additional_headers': forms.Textarea(attrs={'class': 'font-monospace'}),
@ -237,6 +245,7 @@ class WebhookForm(BootstrapMixin, forms.ModelForm):
class TagForm(BootstrapMixin, forms.ModelForm): class TagForm(BootstrapMixin, forms.ModelForm):
slug = SlugField() slug = SlugField()
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'),
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('tags'), limit_choices_to=FeatureQuery('tags'),
required=False required=False
@ -255,65 +264,79 @@ class TagForm(BootstrapMixin, forms.ModelForm):
class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
regions = DynamicModelMultipleChoiceField( regions = DynamicModelMultipleChoiceField(
label=_('Regions'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False required=False
) )
site_groups = DynamicModelMultipleChoiceField( site_groups = DynamicModelMultipleChoiceField(
label=_('Site groups'),
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
required=False required=False
) )
sites = DynamicModelMultipleChoiceField( sites = DynamicModelMultipleChoiceField(
label=_('Sites'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False required=False
) )
locations = DynamicModelMultipleChoiceField( locations = DynamicModelMultipleChoiceField(
label=_('Locations'),
queryset=Location.objects.all(), queryset=Location.objects.all(),
required=False required=False
) )
device_types = DynamicModelMultipleChoiceField( device_types = DynamicModelMultipleChoiceField(
label=_('Device types'),
queryset=DeviceType.objects.all(), queryset=DeviceType.objects.all(),
required=False required=False
) )
roles = DynamicModelMultipleChoiceField( roles = DynamicModelMultipleChoiceField(
label=_('Roles'),
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
required=False required=False
) )
platforms = DynamicModelMultipleChoiceField( platforms = DynamicModelMultipleChoiceField(
label=_('Platforms'),
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
required=False required=False
) )
cluster_types = DynamicModelMultipleChoiceField( cluster_types = DynamicModelMultipleChoiceField(
label=_('Cluster types'),
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
required=False required=False
) )
cluster_groups = DynamicModelMultipleChoiceField( cluster_groups = DynamicModelMultipleChoiceField(
label=_('Cluster groups'),
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
required=False required=False
) )
clusters = DynamicModelMultipleChoiceField( clusters = DynamicModelMultipleChoiceField(
label=_('Clusters'),
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
required=False required=False
) )
tenant_groups = DynamicModelMultipleChoiceField( tenant_groups = DynamicModelMultipleChoiceField(
label=_('Tenat groups'),
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
required=False required=False
) )
tenants = DynamicModelMultipleChoiceField( tenants = DynamicModelMultipleChoiceField(
label=_('Tenants'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
tags = DynamicModelMultipleChoiceField( tags = DynamicModelMultipleChoiceField(
label=_('Tags'),
queryset=Tag.objects.all(), queryset=Tag.objects.all(),
required=False required=False
) )
data = JSONField( data = JSONField(
label=_('Data'),
required=False required=False
) )
fieldsets = ( fieldsets = (
('Config Context', ('name', 'weight', 'description', 'data', 'is_active')), (_('Config Context'), ('name', 'weight', 'description', 'data', 'is_active')),
('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')),
('Assignment', ( (_('Assignment'), (
'regions', 'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types', 'regions', 'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types',
'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags',
)), )),
@ -345,25 +368,27 @@ class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
super().clean() super().clean()
if not self.cleaned_data.get('data') and not self.cleaned_data.get('data_file'): if not self.cleaned_data.get('data') and not self.cleaned_data.get('data_file'):
raise forms.ValidationError("Must specify either local data or a data file") raise forms.ValidationError(_("Must specify either local data or a data file"))
return self.cleaned_data return self.cleaned_data
class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
tags = DynamicModelMultipleChoiceField( tags = DynamicModelMultipleChoiceField(
label=_('Tags'),
queryset=Tag.objects.all(), queryset=Tag.objects.all(),
required=False required=False
) )
template_code = forms.CharField( template_code = forms.CharField(
label=_('Template code'),
required=False, required=False,
widget=forms.Textarea(attrs={'class': 'font-monospace'}) widget=forms.Textarea(attrs={'class': 'font-monospace'})
) )
fieldsets = ( fieldsets = (
('Config Template', ('name', 'description', 'environment_params', 'tags')), (_('Config Template'), ('name', 'description', 'environment_params', 'tags')),
('Content', ('template_code',)), (_('Content'), ('template_code',)),
('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')),
) )
class Meta: class Meta:
@ -387,7 +412,7 @@ class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm):
super().clean() super().clean()
if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'): if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'):
raise forms.ValidationError("Must specify either local content or a data file") raise forms.ValidationError(_("Must specify either local content or a data file"))
return self.cleaned_data return self.cleaned_data
@ -403,10 +428,13 @@ class ImageAttachmentForm(BootstrapMixin, forms.ModelForm):
class JournalEntryForm(NetBoxModelForm): class JournalEntryForm(NetBoxModelForm):
kind = forms.ChoiceField( kind = forms.ChoiceField(
label=_('Kind'),
choices=add_blank_choice(JournalEntryKindChoices), choices=add_blank_choice(JournalEntryKindChoices),
required=False required=False
) )
comments = CommentField() comments = CommentField(
label=_('Comments'),
)
class Meta: class Meta:
model = JournalEntry model = JournalEntry
@ -445,16 +473,16 @@ class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMe
""" """
fieldsets = ( fieldsets = (
('Rack Elevations', ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')), (_('Rack Elevations'), ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')),
('Power', ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')), (_('Power'), ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')),
('IPAM', ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')), (_('IPAM'), ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')),
('Security', ('ALLOWED_URL_SCHEMES',)), (_('Security'), ('ALLOWED_URL_SCHEMES',)),
('Banners', ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')), (_('Banners'), ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')),
('Pagination', ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')), (_('Pagination'), ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')),
('Validation', ('CUSTOM_VALIDATORS',)), (_('Validation'), ('CUSTOM_VALIDATORS',)),
('User Preferences', ('DEFAULT_USER_PREFERENCES',)), (_('User Preferences'), ('DEFAULT_USER_PREFERENCES',)),
('Miscellaneous', ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')), (_('Miscellaneous'), ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')),
('Config Revision', ('comment',)) (_('Config Revision'), ('comment',))
) )
class Meta: class Meta:
@ -481,11 +509,11 @@ class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMe
help_text = self.fields[param.name].help_text help_text = self.fields[param.name].help_text
if help_text: if help_text:
help_text += '<br />' # Line break help_text += '<br />' # Line break
help_text += f'Current value: <strong>{value}</strong>' help_text += _('Current value: <strong>{value}</strong>').format(value=value)
if is_static: if is_static:
help_text += ' (defined statically)' help_text += _(' (defined statically)')
elif value == param.default: elif value == param.default:
help_text += ' (default)' help_text += _(' (default)')
self.fields[param.name].help_text = help_text self.fields[param.name].help_text = help_text
self.fields[param.name].initial = value self.fields[param.name].initial = value
if is_static: if is_static:

View File

@ -1,5 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from extras.choices import DurationChoices from extras.choices import DurationChoices
from utilities.forms import BootstrapMixin from utilities.forms import BootstrapMixin
@ -33,7 +33,7 @@ class ReportForm(BootstrapMixin, forms.Form):
# Annotate the current system time for reference # Annotate the current system time for reference
now = local_now().strftime('%Y-%m-%d %H:%M:%S') now = local_now().strftime('%Y-%m-%d %H:%M:%S')
self.fields['schedule_at'].help_text += f' (current time: <strong>{now}</strong>)' self.fields['schedule_at'].help_text += _(' (current time: <strong>{now}</strong>)').format(now=now)
# Remove scheduling fields if scheduling is disabled # Remove scheduling fields if scheduling is disabled
if not scheduling_enabled: if not scheduling_enabled:

View File

@ -1,5 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _ from django.utils.translation import gettext_lazy as _
from extras.choices import DurationChoices from extras.choices import DurationChoices
from utilities.forms import BootstrapMixin from utilities.forms import BootstrapMixin
@ -39,7 +39,7 @@ class ScriptForm(BootstrapMixin, forms.Form):
# Annotate the current system time for reference # Annotate the current system time for reference
now = local_now().strftime('%Y-%m-%d %H:%M:%S') now = local_now().strftime('%Y-%m-%d %H:%M:%S')
self.fields['_schedule_at'].help_text += f' (current time: <strong>{now}</strong>)' self.fields['_schedule_at'].help_text += _(' (current time: <strong>{now}</strong>)').format(now=now)
# Remove scheduling fields if scheduling is disabled # Remove scheduling fields if scheduling is disabled
if not scheduling_enabled: if not scheduling_enabled: