diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index dfe4f46e4..8ff6a0718 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -7,7 +7,7 @@ from tenancy.forms import TenancyFilterForm, TenancyForm from tenancy.models import Tenant from utilities.forms import ( APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, - FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple + DatePicker, FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple ) from .constants import * from .models import Circuit, CircuitTermination, CircuitType, Provider @@ -161,7 +161,6 @@ class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm): ] help_texts = { 'cid': "Unique circuit ID", - 'install_date': "Format: YYYY-MM-DD", 'commit_rate': "Committed rate", } widgets = { @@ -172,7 +171,7 @@ class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm): api_url="/api/circuits/circuit-types/" ), 'status': StaticSelect2(), - + 'install_date': DatePicker(), } diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index efb92b2ce..5223c3c05 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -10,8 +10,8 @@ from dcim.models import DeviceRole, Platform, Region, Site from tenancy.models import Tenant, TenantGroup from utilities.forms import ( add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect, - CommentField, ContentTypeSelect, FilterChoiceField, LaxURLField, JSONField, SlugField, StaticSelect2, - BOOLEAN_WITH_BLANK_CHOICES, + CommentField, ContentTypeSelect, DatePicker, DateTimePicker, FilterChoiceField, LaxURLField, JSONField, + SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES, ) from .constants import * from .models import ConfigContext, CustomField, CustomFieldValue, ImageAttachment, ObjectChange, Tag @@ -57,7 +57,7 @@ def get_custom_fields_for_model(content_type, filterable_only=False, bulk_edit=F # Date elif cf.type == CF_TYPE_DATE: - field = forms.DateField(required=cf.required, initial=initial, help_text="Date format: YYYY-MM-DD") + field = forms.DateField(required=cf.required, initial=initial, widget=DatePicker()) # Select elif cf.type == CF_TYPE_SELECT: @@ -388,16 +388,12 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form): time_after = forms.DateTimeField( label='After', required=False, - widget=forms.TextInput( - attrs={'placeholder': 'YYYY-MM-DD hh:mm:ss'} - ) + widget=DateTimePicker() ) time_before = forms.DateTimeField( label='Before', required=False, - widget=forms.TextInput( - attrs={'placeholder': 'YYYY-MM-DD hh:mm:ss'} - ) + widget=DateTimePicker() ) action = forms.ChoiceField( choices=add_blank_choice(OBJECTCHANGE_ACTION_CHOICES), diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index 68529a7f0..a95967b20 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -9,8 +9,8 @@ from tenancy.forms import TenancyFilterForm, TenancyForm from tenancy.models import Tenant from utilities.forms import ( add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField, - CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm, SlugField, - StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES + CSVChoiceField, DatePicker, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm, + SlugField, StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES ) from virtualization.models import VirtualMachine from .constants import * @@ -156,12 +156,12 @@ class AggregateForm(BootstrapMixin, CustomFieldForm): help_texts = { 'prefix': "IPv4 or IPv6 network", 'rir': "Regional Internet Registry responsible for this prefix", - 'date_added': "Format: YYYY-MM-DD", } widgets = { 'rir': APISelect( api_url="/api/ipam/rirs/" - ) + ), + 'date_added': DatePicker(), } @@ -205,6 +205,9 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd nullable_fields = [ 'date_added', 'description', ] + widgets = { + 'date_added': DatePicker(), + } class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm): diff --git a/netbox/users/forms.py b/netbox/users/forms.py index 641a1f3e8..495332d2c 100644 --- a/netbox/users/forms.py +++ b/netbox/users/forms.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm -from utilities.forms import BootstrapMixin +from utilities.forms import BootstrapMixin, DateTimePicker from .models import Token @@ -29,6 +29,6 @@ class TokenForm(BootstrapMixin, forms.ModelForm): fields = [ 'key', 'write_enabled', 'expires', 'description', ] - help_texts = { - 'expires': 'YYYY-MM-DD [HH:MM:SS]' + widgets = { + 'expires': DateTimePicker(), } diff --git a/netbox/utilities/forms.py b/netbox/utilities/forms.py index e75ab4d1c..5f920930d 100644 --- a/netbox/utilities/forms.py +++ b/netbox/utilities/forms.py @@ -362,6 +362,36 @@ class APISelectMultiple(APISelect, forms.SelectMultiple): self.attrs['data-multiple'] = 1 +class DatePicker(forms.TextInput): + """ + Date picker using Flatpickr. + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.attrs['class'] = 'date-picker' + self.attrs['placeholder'] = 'YYYY-MM-DD' + + +class DateTimePicker(forms.TextInput): + """ + DateTime picker using Flatpickr. + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.attrs['class'] = 'datetime-picker' + self.attrs['placeholder'] = 'YYYY-MM-DD hh:mm:ss' + + +class TimePicker(forms.TextInput): + """ + Time picker using Flatpickr. + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.attrs['class'] = 'time-picker' + self.attrs['placeholder'] = 'hh:mm:ss' + + # # Form fields #