commit
1abbaf99dc
|
|
@ -10,3 +10,5 @@
|
|||
fabfile.py
|
||||
*.swp
|
||||
gunicorn_config.py
|
||||
.DS_Store
|
||||
.vscode
|
||||
|
|
|
|||
3813
CHANGELOG.md
3813
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,4 @@
|
|||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Site
|
||||
|
|
@ -7,8 +6,8 @@ from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEdit
|
|||
from tenancy.forms import TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
AnnotatedMultipleChoiceField, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, FilterChoiceField,
|
||||
SmallTextarea, SlugField,
|
||||
APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
|
||||
FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
|
||||
)
|
||||
from .constants import CIRCUIT_STATUS_CHOICES
|
||||
from .models import Circuit, CircuitTermination, CircuitType, Provider
|
||||
|
|
@ -107,7 +106,11 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug'
|
||||
to_field_name='slug',
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
asn = forms.IntegerField(
|
||||
required=False,
|
||||
|
|
@ -161,6 +164,16 @@ class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
'install_date': "Format: YYYY-MM-DD",
|
||||
'commit_rate': "Committed rate",
|
||||
}
|
||||
widgets = {
|
||||
'provider': APISelect(
|
||||
api_url="/api/circuits/providers/"
|
||||
),
|
||||
'type': APISelect(
|
||||
api_url="/api/circuits/circuit-types/"
|
||||
),
|
||||
'status': StaticSelect2(),
|
||||
|
||||
}
|
||||
|
||||
|
||||
class CircuitCSVForm(forms.ModelForm):
|
||||
|
|
@ -209,20 +222,30 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
|
|||
)
|
||||
type = forms.ModelChoiceField(
|
||||
queryset=CircuitType.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/circuits/circuit-types/"
|
||||
)
|
||||
)
|
||||
provider = forms.ModelChoiceField(
|
||||
queryset=Provider.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/circuits/providers/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(CIRCUIT_STATUS_CHOICES),
|
||||
required=False,
|
||||
initial=''
|
||||
initial='',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
commit_rate = forms.IntegerField(
|
||||
required=False,
|
||||
|
|
@ -249,35 +272,43 @@ class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
label='Search'
|
||||
)
|
||||
type = FilterChoiceField(
|
||||
queryset=CircuitType.objects.annotate(
|
||||
filter_count=Count('circuits')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=CircuitType.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/circuits/circuit-types/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
provider = FilterChoiceField(
|
||||
queryset=Provider.objects.annotate(
|
||||
filter_count=Count('circuits')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=Provider.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/circuits/providers/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=CIRCUIT_STATUS_CHOICES,
|
||||
annotate=Circuit.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('circuits')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('circuit_terminations')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
commit_rate = forms.IntegerField(
|
||||
required=False,
|
||||
|
|
@ -304,4 +335,7 @@ class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
|
|||
}
|
||||
widgets = {
|
||||
'term_side': forms.HiddenInput(),
|
||||
'site': APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -760,6 +760,10 @@ class InterfaceFilter(django_filters.FilterSet):
|
|||
"""
|
||||
Not using DeviceComponentFilterSet for Interfaces because we need to check for VirtualChassis membership.
|
||||
"""
|
||||
q = django_filters.CharFilter(
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
device = django_filters.CharFilter(
|
||||
method='filter_device',
|
||||
field_name='name',
|
||||
|
|
@ -806,6 +810,13 @@ class InterfaceFilter(django_filters.FilterSet):
|
|||
model = Interface
|
||||
fields = ['name', 'connection_status', 'form_factor', 'enabled', 'mtu', 'mgmt_only']
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
if not value.strip():
|
||||
return queryset
|
||||
return queryset.filter(
|
||||
Q(name__icontains=value)
|
||||
).distinct()
|
||||
|
||||
def filter_device(self, queryset, name, value):
|
||||
try:
|
||||
device = Device.objects.get(**{name: value})
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,7 +1,6 @@
|
|||
from django import forms
|
||||
from django.core.exceptions import MultipleObjectsReturned
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Site, Rack, Device, Interface
|
||||
|
|
@ -9,9 +8,9 @@ from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEdit
|
|||
from tenancy.forms import TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
AnnotatedMultipleChoiceField, APISelect, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
||||
CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, Livesearch, ReturnURLForm,
|
||||
SlugField, add_blank_choice,
|
||||
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
||||
CSVChoiceField, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm, SlugField,
|
||||
StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
from virtualization.models import VirtualMachine
|
||||
from .constants import (
|
||||
|
|
@ -77,7 +76,10 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
|
|||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
enforce_unique = forms.NullBooleanField(
|
||||
required=False,
|
||||
|
|
@ -102,11 +104,14 @@ class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
label='Search'
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('vrfs')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -139,12 +144,8 @@ class RIRFilterForm(BootstrapMixin, forms.Form):
|
|||
is_private = forms.NullBooleanField(
|
||||
required=False,
|
||||
label='Private',
|
||||
widget=forms.Select(
|
||||
choices=[
|
||||
('', '---------'),
|
||||
('True', 'Yes'),
|
||||
('False', 'No'),
|
||||
]
|
||||
widget=StaticSelect2(
|
||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -168,6 +169,11 @@ class AggregateForm(BootstrapMixin, CustomFieldForm):
|
|||
'rir': "Regional Internet Registry responsible for this prefix",
|
||||
'date_added': "Format: YYYY-MM-DD",
|
||||
}
|
||||
widgets = {
|
||||
'rir': APISelect(
|
||||
api_url="/api/ipam/rirs/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class AggregateCSVForm(forms.ModelForm):
|
||||
|
|
@ -193,7 +199,10 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|||
rir = forms.ModelChoiceField(
|
||||
queryset=RIR.objects.all(),
|
||||
required=False,
|
||||
label='RIR'
|
||||
label='RIR',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/rirs/"
|
||||
)
|
||||
)
|
||||
date_added = forms.DateField(
|
||||
required=False
|
||||
|
|
@ -218,12 +227,17 @@ class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
family = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IP_FAMILY_CHOICES,
|
||||
label='Address family'
|
||||
label='Address family',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
rir = FilterChoiceField(
|
||||
queryset=RIR.objects.annotate(filter_count=Count('aggregates')),
|
||||
queryset=RIR.objects.all(),
|
||||
to_field_name='slug',
|
||||
label='RIR'
|
||||
label='RIR',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/rirs/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -261,9 +275,13 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
label='Site',
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
filter_for={
|
||||
'vlan_group': 'site_id',
|
||||
'vlan': 'site_id',
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'vlan_group',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -276,9 +294,11 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
required=False,
|
||||
label='VLAN group',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
||||
api_url='/api/ipam/vlan-groups/',
|
||||
filter_for={
|
||||
'vlan': 'group_id'
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'vlan',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -292,7 +312,7 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
required=False,
|
||||
label='VLAN',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}',
|
||||
api_url='/api/ipam/vlans/',
|
||||
display_field='display_name'
|
||||
)
|
||||
)
|
||||
|
|
@ -304,6 +324,15 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'description', 'tenant_group', 'tenant',
|
||||
'tags',
|
||||
]
|
||||
widgets = {
|
||||
'vrf': APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
),
|
||||
'status': StaticSelect2(),
|
||||
'role': APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
|
|
@ -415,12 +444,18 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||
)
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
)
|
||||
vrf = forms.ModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='VRF'
|
||||
label='VRF',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
)
|
||||
prefix_length = forms.IntegerField(
|
||||
min_value=1,
|
||||
|
|
@ -429,15 +464,22 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(PREFIX_STATUS_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=Role.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
)
|
||||
is_pool = forms.NullBooleanField(
|
||||
required=False,
|
||||
|
|
@ -473,47 +515,60 @@ class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
family = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IP_FAMILY_CHOICES,
|
||||
label='Address family'
|
||||
label='Address family',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
mask_length = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=PREFIX_MASK_LENGTH_CHOICES,
|
||||
label='Mask length'
|
||||
label='Mask length',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
vrf = FilterChoiceField(
|
||||
queryset=VRF.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='VRF',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/vrfs/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=PREFIX_STATUS_CHOICES,
|
||||
annotate=Prefix.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=Role.objects.annotate(
|
||||
filter_count=Count('prefixes')
|
||||
),
|
||||
queryset=Role.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/roles/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
expand = forms.BooleanField(
|
||||
required=False,
|
||||
|
|
@ -534,9 +589,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
label='Site',
|
||||
widget=forms.Select(
|
||||
attrs={
|
||||
'filter-for': 'nat_rack'
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
filter_for={
|
||||
'nat_rack': 'site_id',
|
||||
'nat_device': 'site_id'
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
@ -548,10 +605,12 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|||
required=False,
|
||||
label='Rack',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/racks/?site_id={{nat_site}}',
|
||||
api_url='/api/dcim/racks/',
|
||||
display_field='display_name',
|
||||
filter_for={
|
||||
'nat_device': 'rack_id'
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'nat_device',
|
||||
'nullable': 'true'
|
||||
}
|
||||
)
|
||||
|
|
@ -565,9 +624,11 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|||
required=False,
|
||||
label='Device',
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/devices/?site_id={{nat_site}}&rack_id={{nat_rack}}',
|
||||
api_url='/api/dcim/devices/',
|
||||
display_field='display_name',
|
||||
attrs={'filter-for': 'nat_inside'}
|
||||
filter_for={
|
||||
'nat_inside': 'device_id'
|
||||
}
|
||||
)
|
||||
)
|
||||
nat_inside = ChainedModelChoiceField(
|
||||
|
|
@ -578,20 +639,10 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|||
required=False,
|
||||
label='IP Address',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/ip-addresses/?device_id={{nat_device}}',
|
||||
api_url='/api/ipam/ip-addresses/',
|
||||
display_field='address'
|
||||
)
|
||||
)
|
||||
livesearch = forms.CharField(
|
||||
required=False,
|
||||
label='Search',
|
||||
widget=Livesearch(
|
||||
query_key='q',
|
||||
query_url='ipam-api:ipaddress-list',
|
||||
field_to_update='nat_inside',
|
||||
obj_label='address'
|
||||
)
|
||||
)
|
||||
primary_for_parent = forms.BooleanField(
|
||||
required=False,
|
||||
label='Make this the primary IP for the device/VM'
|
||||
|
|
@ -606,6 +657,13 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
|||
'address', 'vrf', 'status', 'role', 'description', 'interface', 'primary_for_parent', 'nat_site',
|
||||
'nat_rack', 'nat_inside', 'tenant_group', 'tenant', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'status': StaticSelect2(),
|
||||
'role': StaticSelect2(),
|
||||
'vrf': APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
|
|
@ -685,6 +743,13 @@ class IPAddressBulkAddForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
fields = [
|
||||
'address', 'vrf', 'status', 'role', 'description', 'tenant_group', 'tenant',
|
||||
]
|
||||
widgets = {
|
||||
'status': StaticSelect2(),
|
||||
'role': StaticSelect2(),
|
||||
'vrf': APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
@ -822,7 +887,10 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|||
vrf = forms.ModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='VRF'
|
||||
label='VRF',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
)
|
||||
mask_length = forms.IntegerField(
|
||||
min_value=1,
|
||||
|
|
@ -831,15 +899,20 @@ class IPAddressBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
|
|||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(IPADDRESS_STATUS_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
role = forms.ChoiceField(
|
||||
choices=add_blank_choice(IPADDRESS_ROLE_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
description = forms.CharField(
|
||||
max_length=100, required=False
|
||||
|
|
@ -856,7 +929,10 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
|
|||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='VRF',
|
||||
empty_label='Global'
|
||||
empty_label='Global',
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vrfs/"
|
||||
)
|
||||
)
|
||||
address = forms.CharField(
|
||||
label='IP Address'
|
||||
|
|
@ -881,40 +957,45 @@ class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
family = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IP_FAMILY_CHOICES,
|
||||
label='Address family'
|
||||
label='Address family',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
mask_length = forms.ChoiceField(
|
||||
required=False,
|
||||
choices=IPADDRESS_MASK_LENGTH_CHOICES,
|
||||
label='Mask length'
|
||||
label='Mask length',
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
vrf = FilterChoiceField(
|
||||
queryset=VRF.objects.annotate(
|
||||
filter_count=Count('ip_addresses')
|
||||
),
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='VRF',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/vrfs/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('ip_addresses')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=IPADDRESS_STATUS_CHOICES,
|
||||
annotate=IPAddress.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
role = AnnotatedMultipleChoiceField(
|
||||
role = forms.MultipleChoiceField(
|
||||
choices=IPADDRESS_ROLE_CHOICES,
|
||||
annotate=IPAddress.objects.all(),
|
||||
annotate_field='role',
|
||||
include_null=True,
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -930,6 +1011,11 @@ class VLANGroupForm(BootstrapMixin, forms.ModelForm):
|
|||
fields = [
|
||||
'site', 'name', 'slug',
|
||||
]
|
||||
widgets = {
|
||||
'site': APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class VLANGroupCSVForm(forms.ModelForm):
|
||||
|
|
@ -954,11 +1040,14 @@ class VLANGroupCSVForm(forms.ModelForm):
|
|||
|
||||
class VLANGroupFilterForm(BootstrapMixin, forms.Form):
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('vlan_groups')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -970,9 +1059,12 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/",
|
||||
filter_for={
|
||||
'group': 'site_id'
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'group',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -985,7 +1077,7 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
required=False,
|
||||
label='Group',
|
||||
widget=APISelect(
|
||||
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
||||
api_url='/api/ipam/vlan-groups/',
|
||||
)
|
||||
)
|
||||
tags = TagField(required=False)
|
||||
|
|
@ -1003,6 +1095,12 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
'status': "Operational status of this VLAN",
|
||||
'role': "The primary function of this VLAN",
|
||||
}
|
||||
widgets = {
|
||||
'status': StaticSelect2(),
|
||||
'role': APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class VLANCSVForm(forms.ModelForm):
|
||||
|
|
@ -1078,23 +1176,36 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|||
)
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
)
|
||||
group = forms.ModelChoiceField(
|
||||
queryset=VLANGroup.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/vlan-groups/"
|
||||
)
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenants/"
|
||||
)
|
||||
)
|
||||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(VLAN_STATUS_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=Role.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/ipam/roles/"
|
||||
)
|
||||
)
|
||||
description = forms.CharField(
|
||||
max_length=100,
|
||||
|
|
@ -1114,38 +1225,48 @@ class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
label='Search'
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- Global --'
|
||||
null_label='-- Global --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
group_id = FilterChoiceField(
|
||||
queryset=VLANGroup.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=VLANGroup.objects.all(),
|
||||
label='VLAN group',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/vlan-groups/",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenants/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=VLAN_STATUS_CHOICES,
|
||||
annotate=VLAN.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=Role.objects.annotate(
|
||||
filter_count=Count('vlans')
|
||||
),
|
||||
queryset=Role.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/ipam/roles/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1167,6 +1288,10 @@ class ServiceForm(BootstrapMixin, CustomFieldForm):
|
|||
'ipaddresses': "IP address assignment is optional. If no IPs are selected, the service is assumed to be "
|
||||
"reachable via all IPs assigned to the device.",
|
||||
}
|
||||
widgets = {
|
||||
'protocol': StaticSelect2(),
|
||||
'ipaddresses': StaticSelect2Multiple(),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
@ -1193,10 +1318,11 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
)
|
||||
protocol = forms.ChoiceField(
|
||||
choices=add_blank_choice(IP_PROTOCOL_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
port = forms.IntegerField(
|
||||
required=False
|
||||
required=False,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -1207,7 +1333,8 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||
)
|
||||
protocol = forms.ChoiceField(
|
||||
choices=add_blank_choice(IP_PROTOCOL_CHOICES),
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2()
|
||||
)
|
||||
port = forms.IntegerField(
|
||||
validators=[
|
||||
|
|
@ -1223,5 +1350,5 @@ class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
|||
|
||||
class Meta:
|
||||
nullable_fields = [
|
||||
'site', 'group', 'tenant', 'role', 'description',
|
||||
'site', 'tenant', 'role', 'description',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -120,6 +120,117 @@ input[name="pk"] {
|
|||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Color Selections */
|
||||
.color-selection-aa1409 {
|
||||
background-color: #aa1409;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-f44336 {
|
||||
background-color: #f44336;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-e91e63 {
|
||||
background-color: #e91e63;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-ffe4e1 {
|
||||
background-color: #ffe4e1;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ff66ff {
|
||||
background-color: #ff66ff;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-9c27b0 {
|
||||
background-color: #9c27b0;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-673ab7 {
|
||||
background-color: #673ab7;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-3f51b5 {
|
||||
background-color: #3f51b5;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-2196f3 {
|
||||
background-color: #2196f3;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-03a9f4 {
|
||||
background-color: #03a9f4;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-00bcd4 {
|
||||
background-color: #00bcd4;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-009688 {
|
||||
background-color: #009688;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-00ffff {
|
||||
background-color: #00ffff;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-2f6a31 {
|
||||
background-color: #2f6a31;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-4caf50 {
|
||||
background-color: #4caf50;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-8bc34a {
|
||||
background-color: #8bc34a;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-cddc39 {
|
||||
background-color: #cddc39;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ffeb3b {
|
||||
background-color: #ffeb3b;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ffc107 {
|
||||
background-color: #ffc107;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-ff9800 {
|
||||
background-color: #ff9800;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-ff5722 {
|
||||
background-color: #ff5722;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-795548 {
|
||||
background-color: #795548;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-c0c0c0 {
|
||||
background-color: #c0c0c0;
|
||||
color: #000000;
|
||||
}
|
||||
.color-selection-9e9e9e {
|
||||
background-color: #9e9e9e;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-607d8b {
|
||||
background-color: #607d8b;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-111111 {
|
||||
background-color: #111111;
|
||||
color: #ffffff;
|
||||
}
|
||||
.color-selection-ffffff {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
|
||||
/* Tables */
|
||||
th.pk, td.pk {
|
||||
padding-bottom: 6px;
|
||||
|
|
|
|||
|
|
@ -67,135 +67,221 @@ $(document).ready(function() {
|
|||
form.submit();
|
||||
});
|
||||
|
||||
// API select widget
|
||||
$('select[filter-for]').change(function() {
|
||||
|
||||
// Resolve child field by ID specified in parent
|
||||
var child_names = $(this).attr('filter-for');
|
||||
var parent = this;
|
||||
|
||||
// allow more than one child
|
||||
$.each(child_names.split(" "), function(_, child_name){
|
||||
|
||||
var child_field = $('#id_' + child_name);
|
||||
var child_selected = child_field.val();
|
||||
|
||||
// Wipe out any existing options within the child field and create a default option
|
||||
child_field.empty();
|
||||
if (!child_field.attr('multiple')) {
|
||||
child_field.append($("<option></option>").attr("value", "").text("---------"));
|
||||
// Parse URLs which may contain variable refrences to other field values
|
||||
function parseURL(url) {
|
||||
var filter_regex = /\{\{([a-z_]+)\}\}/g;
|
||||
var match;
|
||||
var rendered_url = url;
|
||||
var filter_field;
|
||||
while (match = filter_regex.exec(url)) {
|
||||
filter_field = $('#id_' + match[1]);
|
||||
var custom_attr = $('option:selected', filter_field).attr('api-value');
|
||||
if (custom_attr) {
|
||||
rendered_url = rendered_url.replace(match[0], custom_attr);
|
||||
} else if (filter_field.val()) {
|
||||
rendered_url = rendered_url.replace(match[0], filter_field.val());
|
||||
} else if (filter_field.attr('nullable') == 'true') {
|
||||
rendered_url = rendered_url.replace(match[0], 'null');
|
||||
}
|
||||
}
|
||||
return rendered_url
|
||||
}
|
||||
|
||||
if ($(parent).val() || $(parent).attr('nullable') == 'true') {
|
||||
var api_url = child_field.attr('api-url') + '&limit=0&brief=1';
|
||||
var disabled_indicator = child_field.attr('disabled-indicator');
|
||||
var initial_value = child_field.attr('initial');
|
||||
var display_field = child_field.attr('display-field') || 'name';
|
||||
// Assign color picker selection classes
|
||||
function colorPickerClassCopy(data, container) {
|
||||
if (data.element) {
|
||||
$(container).addClass($(data.element).attr("class"));
|
||||
}
|
||||
return data.text;
|
||||
}
|
||||
|
||||
// Determine the filter fields needed to make an API call
|
||||
var filter_regex = /\{\{([a-z_]+)\}\}/g;
|
||||
var match;
|
||||
var rendered_url = api_url;
|
||||
var filter_field;
|
||||
while (match = filter_regex.exec(api_url)) {
|
||||
filter_field = $('#id_' + match[1]);
|
||||
var custom_attr = $('option:selected', filter_field).attr('api-value');
|
||||
if (custom_attr) {
|
||||
rendered_url = rendered_url.replace(match[0], custom_attr);
|
||||
} else if (filter_field.val()) {
|
||||
rendered_url = rendered_url.replace(match[0], filter_field.val());
|
||||
} else if (filter_field.attr('nullable') == 'true') {
|
||||
rendered_url = rendered_url.replace(match[0], 'null');
|
||||
}
|
||||
// Color Picker
|
||||
$('.netbox-select2-color-picker').select2({
|
||||
allowClear: true,
|
||||
placeholder: "---------",
|
||||
templateResult: colorPickerClassCopy,
|
||||
templateSelection: colorPickerClassCopy,
|
||||
})
|
||||
|
||||
// Static choice selection
|
||||
$('.netbox-select2-static').select2({
|
||||
allowClear: true,
|
||||
placeholder: "---------",
|
||||
})
|
||||
|
||||
// API backed selection
|
||||
// Includes live search and chained fields
|
||||
// The `multiple` setting may be controled via a data-* attribute
|
||||
$('.netbox-select2-api').select2({
|
||||
allowClear: true,
|
||||
placeholder: "---------",
|
||||
|
||||
ajax: {
|
||||
delay: 500,
|
||||
|
||||
url: function(params) {
|
||||
var element = this[0];
|
||||
var url = parseURL(element.getAttribute("data-url"));
|
||||
|
||||
if (url.includes("{{")) {
|
||||
// URL is not fully rendered yet, abort the request
|
||||
return false;
|
||||
}
|
||||
return url;
|
||||
},
|
||||
|
||||
// Account for any conditional URL append strings
|
||||
$.each(child_field[0].attributes, function(index, attr){
|
||||
if (attr.name.includes("data-url-conditional-append-")){
|
||||
var conditional = attr.name.split("data-url-conditional-append-")[1].split("__");
|
||||
data: function(params) {
|
||||
var element = this[0];
|
||||
// Paging
|
||||
var offset = params.page * 50 || 0;
|
||||
// Base query params
|
||||
var parameters = {
|
||||
q: params.term,
|
||||
brief: 1,
|
||||
limit: 50,
|
||||
offset: offset,
|
||||
};
|
||||
|
||||
// filter-for fields from a chain
|
||||
var attr_name = "data-filter-for-" + $(element).attr("name");
|
||||
var form = $(element).closest('form');
|
||||
var filter_for_elements = form.find("select[" + attr_name + "]");
|
||||
|
||||
filter_for_elements.each(function(index, filter_for_element) {
|
||||
var param_name = $(filter_for_element).attr(attr_name);
|
||||
var value = $(filter_for_element).val();
|
||||
|
||||
if (param_name && value) {
|
||||
parameters[param_name] = value;
|
||||
}
|
||||
});
|
||||
|
||||
// Conditional query params
|
||||
$.each(element.attributes, function(index, attr){
|
||||
if (attr.name.includes("data-conditional-query-param-")){
|
||||
var conditional = attr.name.split("data-conditional-query-param-")[1].split("__");
|
||||
var field = $("#id_" + conditional[0]);
|
||||
var field_value = conditional[1];
|
||||
|
||||
if ($('option:selected', field).attr('api-value') === field_value){
|
||||
rendered_url = rendered_url + attr.value;
|
||||
var _val = attr.value.split("=");
|
||||
parameters[_val[0]] = _val[1];
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// If all URL variables have been replaced, make the API call
|
||||
if (rendered_url.search('{{') < 0) {
|
||||
console.log(child_name + ": Fetching " + rendered_url);
|
||||
$.ajax({
|
||||
url: rendered_url,
|
||||
dataType: 'json',
|
||||
success: function(response, status) {
|
||||
$.each(response.results, function(index, choice) {
|
||||
var option = $("<option></option>").attr("value", choice.id).text(choice[display_field]);
|
||||
if (disabled_indicator && choice[disabled_indicator] && choice.id != initial_value) {
|
||||
option.attr("disabled", "disabled");
|
||||
} else if (choice.id == child_selected) {
|
||||
option.attr("selected", "selected");
|
||||
}
|
||||
child_field.append(option);
|
||||
});
|
||||
}
|
||||
// Additional query params
|
||||
$.each(element.attributes, function(index, attr){
|
||||
if (attr.name.includes("data-additional-query-param-")){
|
||||
var param_name = attr.name.split("data-additional-query-param-")[1]
|
||||
parameters[param_name] = attr.value;
|
||||
}
|
||||
})
|
||||
|
||||
// This will handle params with multiple values (i.e. for list filter forms)
|
||||
return $.param(parameters, true);
|
||||
},
|
||||
|
||||
processResults: function (data) {
|
||||
var element = this.$element[0];
|
||||
var results = $.map(data.results, function (obj) {
|
||||
obj.text = obj[element.getAttribute('display-field')] || obj.name;
|
||||
obj.id = obj[element.getAttribute('value-field')] || obj.id;
|
||||
|
||||
if(element.getAttribute('disabled-indicator') && obj[element.getAttribute('disabled-indicator')]) {
|
||||
// The disabled-indicator equated to true, so we disable this option
|
||||
obj.disabled = true;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
// Handle the null option
|
||||
if (element.getAttribute('data-null-option')) {
|
||||
var null_option = $(element).children()[0]
|
||||
results.unshift({
|
||||
id: null_option.value,
|
||||
text: null_option.text
|
||||
});
|
||||
}
|
||||
|
||||
// Check if there are more results to page
|
||||
var page = data.next !== null;
|
||||
return {
|
||||
results: results,
|
||||
pagination: {
|
||||
more: page
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Trigger change event in case the child field is the parent of another field
|
||||
child_field.change();
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Auto-complete tags
|
||||
function split_tags(val) {
|
||||
return val.split(/,\s*/);
|
||||
// API backed tags
|
||||
var tags = $('#id_tags');
|
||||
if (tags.length > 0 && tags.val().length > 0){
|
||||
tags = $('#id_tags').val().split(/,\s*/);
|
||||
} else {
|
||||
tags = [];
|
||||
}
|
||||
$("#id_tags")
|
||||
.on("keydown", function(event) {
|
||||
if (event.keyCode === $.ui.keyCode.TAB &&
|
||||
$(this).autocomplete("instance").menu.active) {
|
||||
event.preventDefault();
|
||||
tag_objs = $.map(tags, function (tag) {
|
||||
return {
|
||||
id: tag,
|
||||
text: tag,
|
||||
selected: true
|
||||
}
|
||||
})
|
||||
.autocomplete({
|
||||
source: function(request, response) {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: netbox_api_path + 'extras/tags/',
|
||||
data: 'q=' + split_tags(request.term).pop(),
|
||||
success: function(data) {
|
||||
var choices = [];
|
||||
$.each(data.results, function (index, choice) {
|
||||
choices.push(choice.name);
|
||||
});
|
||||
response(choices);
|
||||
}
|
||||
});
|
||||
},
|
||||
search: function() {
|
||||
// Need 3 or more characters to begin searching
|
||||
var term = split_tags(this.value).pop();
|
||||
if (term.length < 3) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
focus: function() {
|
||||
// prevent value inserted on focus
|
||||
return false;
|
||||
},
|
||||
select: function(event, ui) {
|
||||
var terms = split_tags(this.value);
|
||||
// remove the current input
|
||||
terms.pop();
|
||||
// add the selected item
|
||||
terms.push(ui.item.value);
|
||||
// add placeholder to get the comma-and-space at the end
|
||||
terms.push("");
|
||||
this.value = terms.join(", ");
|
||||
return false;
|
||||
});
|
||||
// Replace the django issued text input with a select element
|
||||
$('#id_tags').replaceWith('<select name="tags" id="id_tags" class="form-control"></select>');
|
||||
$('#id_tags').select2({
|
||||
tags: true,
|
||||
data: tag_objs,
|
||||
multiple: true,
|
||||
allowClear: true,
|
||||
placeholder: "Tags",
|
||||
|
||||
ajax: {
|
||||
delay: 250,
|
||||
url: "/api/extras/tags/",
|
||||
|
||||
data: function(params) {
|
||||
// paging
|
||||
var offset = params.page * 50 || 0;
|
||||
var parameters = {
|
||||
q: params.term,
|
||||
brief: 1,
|
||||
limit: 50,
|
||||
offset: offset,
|
||||
};
|
||||
return parameters;
|
||||
},
|
||||
|
||||
processResults: function (data) {
|
||||
var results = $.map(data.results, function (obj) {
|
||||
return {
|
||||
id: obj.name,
|
||||
text: obj.name
|
||||
}
|
||||
});
|
||||
|
||||
// Check if there are more results to page
|
||||
var page = data.next !== null;
|
||||
return {
|
||||
results: results,
|
||||
pagination: {
|
||||
more: page
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
$('#id_tags').closest('form').submit(function(event){
|
||||
// django-taggit can only accept a single comma seperated string value
|
||||
var value = $('#id_tags').val();
|
||||
if (value.length > 0){
|
||||
var final_tags = value.join(', ');
|
||||
$('#id_tags').val(null).trigger('change');
|
||||
var option = new Option(final_tags, final_tags, true, true);
|
||||
$('#id_tags').append(option).trigger('change');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
Select2
|
||||
=======
|
||||
[![Build Status][travis-ci-image]][travis-ci-status]
|
||||
|
||||
Select2 is a jQuery-based replacement for select boxes. It supports searching,
|
||||
remote data sets, and pagination of results.
|
||||
|
||||
To get started, checkout examples and documentation at
|
||||
https://select2.org/
|
||||
|
||||
Use cases
|
||||
---------
|
||||
* Enhancing native selects with search.
|
||||
* Enhancing native selects with a better multi-select interface.
|
||||
* Loading data from JavaScript: easily load items via AJAX and have them
|
||||
searchable.
|
||||
* Nesting optgroups: native selects only support one level of nesting. Select2
|
||||
does not have this restriction.
|
||||
* Tagging: ability to add new items on the fly.
|
||||
* Working with large, remote datasets: ability to partially load a dataset based
|
||||
on the search term.
|
||||
* Paging of large datasets: easy support for loading more pages when the results
|
||||
are scrolled to the end.
|
||||
* Templating: support for custom rendering of results and selections.
|
||||
|
||||
Browser compatibility
|
||||
---------------------
|
||||
* IE 8+
|
||||
* Chrome 8+
|
||||
* Firefox 10+
|
||||
* Safari 3+
|
||||
* Opera 10.6+
|
||||
|
||||
Select2 is automatically tested on the following browsers.
|
||||
|
||||
[![Sauce Labs Test Status][saucelabs-matrix]][saucelabs-status]
|
||||
|
||||
Usage
|
||||
-----
|
||||
You can source Select2 directly from a CDN like [JSDliver][jsdelivr] or
|
||||
[CDNJS][cdnjs], [download it from this GitHub repo][releases], or use one of
|
||||
the integrations below.
|
||||
|
||||
Integrations
|
||||
------------
|
||||
Third party developers have created plugins for platforms which allow Select2 to be integrated more natively and quickly. For many platforms, additional plugins are not required because Select2 acts as a standard `<select>` box.
|
||||
|
||||
Plugins
|
||||
|
||||
* [Django]
|
||||
- [django-autocomplete-light]
|
||||
- [django-easy-select2]
|
||||
- [django-select2]
|
||||
* [Meteor] - [meteor-select2]
|
||||
* [Ruby on Rails][ruby-on-rails] - [select2-rails]
|
||||
* [Wicket] - [wicketstuff-select2]
|
||||
* [Yii 2][yii2] - [yii2-widget-select2]
|
||||
|
||||
Themes
|
||||
|
||||
- [Bootstrap 3][bootstrap3] - [select2-bootstrap-theme]
|
||||
- [Flat UI][flat-ui] - [select2-flat-theme]
|
||||
- [Metro UI][metro-ui] - [select2-metro]
|
||||
|
||||
Missing an integration? Modify this `README` and make a pull request back here to Select2 on GitHub.
|
||||
|
||||
Internationalization (i18n)
|
||||
---------------------------
|
||||
Select2 supports multiple languages by simply including the right language JS
|
||||
file (`dist/js/i18n/it.js`, `dist/js/i18n/nl.js`, etc.) after
|
||||
`dist/js/select2.js`.
|
||||
|
||||
Missing a language? Just copy `src/js/select2/i18n/en.js`, translate it, and
|
||||
make a pull request back to Select2 here on GitHub.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
The documentation for Select2 is available
|
||||
[through GitHub Pages][documentation] and is located within this repository
|
||||
in the [`docs` folder][documentation-folder].
|
||||
|
||||
Community
|
||||
---------
|
||||
You can find out about the different ways to get in touch with the Select2
|
||||
community at the [Select2 community page][community].
|
||||
|
||||
Copyright and license
|
||||
---------------------
|
||||
The license is available within the repository in the [LICENSE][license] file.
|
||||
|
||||
[cdnjs]: http://www.cdnjs.com/libraries/select2
|
||||
[community]: https://select2.org/getting-help
|
||||
[documentation]: https://select2.org
|
||||
[documentation-folder]: https://github.com/select2/select2/tree/master/docs
|
||||
[freenode]: https://freenode.net/
|
||||
[jsdelivr]: http://www.jsdelivr.com/#!select2
|
||||
[license]: LICENSE.md
|
||||
[releases]: https://github.com/select2/select2/releases
|
||||
[saucelabs-matrix]: https://saucelabs.com/browser-matrix/select2.svg
|
||||
[saucelabs-status]: https://saucelabs.com/u/select2
|
||||
[travis-ci-image]: https://img.shields.io/travis/select2/select2/master.svg
|
||||
[travis-ci-status]: https://travis-ci.org/select2/select2
|
||||
|
||||
[bootstrap3]: https://getbootstrap.com/
|
||||
[django]: https://www.djangoproject.com/
|
||||
[django-autocomplete-light]: https://github.com/yourlabs/django-autocomplete-light
|
||||
[django-easy-select2]: https://github.com/asyncee/django-easy-select2
|
||||
[django-select2]: https://github.com/applegrew/django-select2
|
||||
[flat-ui]: http://designmodo.github.io/Flat-UI/
|
||||
[meteor]: https://www.meteor.com/
|
||||
[meteor-select2]: https://github.com/nate-strauser/meteor-select2
|
||||
[metro-ui]: http://metroui.org.ua/
|
||||
[select2-metro]: http://metroui.org.ua/select2.html
|
||||
[ruby-on-rails]: http://rubyonrails.org/
|
||||
[select2-bootstrap-theme]: https://github.com/select2/select2-bootstrap-theme
|
||||
[select2-flat-theme]: https://github.com/techhysahil/select2-Flat_Theme
|
||||
[select2-rails]: https://github.com/argerim/select2-rails
|
||||
[vue.js]: http://vuejs.org/
|
||||
[select2-vue]: http://vuejs.org/examples/select2.html
|
||||
[wicket]: https://wicket.apache.org/
|
||||
[wicketstuff-select2]: https://github.com/wicketstuff/core/tree/master/select2-parent
|
||||
[yii2]: http://www.yiiframework.com/
|
||||
[yii2-widget-select2]: https://github.com/kartik-v/yii2-widget-select2
|
||||
|
|
@ -0,0 +1,484 @@
|
|||
.select2-container {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
vertical-align: middle; }
|
||||
.select2-container .select2-selection--single {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: 28px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--single .select2-selection__rendered {
|
||||
display: block;
|
||||
padding-left: 8px;
|
||||
padding-right: 20px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-selection--single .select2-selection__clear {
|
||||
position: relative; }
|
||||
.select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
|
||||
padding-right: 8px;
|
||||
padding-left: 20px; }
|
||||
.select2-container .select2-selection--multiple {
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
min-height: 32px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-container .select2-selection--multiple .select2-selection__rendered {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-left: 8px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.select2-container .select2-search--inline {
|
||||
float: left; }
|
||||
.select2-container .select2-search--inline .select2-search__field {
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
font-size: 100%;
|
||||
margin-top: 5px;
|
||||
padding: 0; }
|
||||
.select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
|
||||
.select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: -100000px;
|
||||
width: 100%;
|
||||
z-index: 1051; }
|
||||
|
||||
.select2-results {
|
||||
display: block; }
|
||||
|
||||
.select2-results__options {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.select2-results__option {
|
||||
padding: 6px;
|
||||
user-select: none;
|
||||
-webkit-user-select: none; }
|
||||
.select2-results__option[aria-selected] {
|
||||
cursor: pointer; }
|
||||
|
||||
.select2-container--open .select2-dropdown {
|
||||
left: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--above {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--open .select2-dropdown--below {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-search--dropdown {
|
||||
display: block;
|
||||
padding: 4px; }
|
||||
.select2-search--dropdown .select2-search__field {
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none; }
|
||||
.select2-search--dropdown.select2-search--hide {
|
||||
display: none; }
|
||||
|
||||
.select2-close-mask {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: block;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
min-height: 100%;
|
||||
min-width: 100%;
|
||||
height: auto;
|
||||
width: auto;
|
||||
opacity: 0;
|
||||
z-index: 99;
|
||||
background-color: #fff;
|
||||
filter: alpha(opacity=0); }
|
||||
|
||||
.select2-hidden-accessible {
|
||||
border: 0 !important;
|
||||
clip: rect(0 0 0 0) !important;
|
||||
height: 1px !important;
|
||||
margin: -1px !important;
|
||||
overflow: hidden !important;
|
||||
padding: 0 !important;
|
||||
position: absolute !important;
|
||||
width: 1px !important; }
|
||||
|
||||
.select2-container--default .select2-selection--single {
|
||||
background-color: #fff;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow {
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px; }
|
||||
.select2-container--default .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
.select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--default .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered {
|
||||
box-sizing: border-box;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px;
|
||||
width: 100%; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__rendered li {
|
||||
list-style: none; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__placeholder {
|
||||
color: #999;
|
||||
margin-top: 5px;
|
||||
float: left; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
margin-right: 10px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #333; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__placeholder, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
|
||||
float: right; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--default.select2-container--focus .select2-selection--multiple {
|
||||
border: solid black 1px;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection--multiple {
|
||||
background-color: #eee;
|
||||
cursor: default; }
|
||||
|
||||
.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
|
||||
display: none; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--default .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa; }
|
||||
|
||||
.select2-container--default .select2-search--inline .select2-search__field {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: 0;
|
||||
box-shadow: none;
|
||||
-webkit-appearance: textfield; }
|
||||
|
||||
.select2-container--default .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--default .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-disabled=true] {
|
||||
color: #999; }
|
||||
|
||||
.select2-container--default .select2-results__option[aria-selected=true] {
|
||||
background-color: #ddd; }
|
||||
|
||||
.select2-container--default .select2-results__option .select2-results__option {
|
||||
padding-left: 1em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__group {
|
||||
padding-left: 0; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -1em;
|
||||
padding-left: 2em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -2em;
|
||||
padding-left: 3em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -3em;
|
||||
padding-left: 4em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -4em;
|
||||
padding-left: 5em; }
|
||||
.select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
|
||||
margin-left: -5em;
|
||||
padding-left: 6em; }
|
||||
|
||||
.select2-container--default .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #5897fb;
|
||||
color: white; }
|
||||
|
||||
.select2-container--default .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic .select2-selection--single {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
outline: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
|
||||
background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__rendered {
|
||||
color: #444;
|
||||
line-height: 28px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__clear {
|
||||
cursor: pointer;
|
||||
float: right;
|
||||
font-weight: bold;
|
||||
margin-right: 10px; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__placeholder {
|
||||
color: #999; }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow {
|
||||
background-color: #ddd;
|
||||
border: none;
|
||||
border-left: 1px solid #aaa;
|
||||
border-top-right-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
height: 26px;
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
width: 20px;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
|
||||
.select2-container--classic .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: #888 transparent transparent transparent;
|
||||
border-style: solid;
|
||||
border-width: 5px 4px 0 4px;
|
||||
height: 0;
|
||||
left: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -2px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 0; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
|
||||
float: left; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
|
||||
border: none;
|
||||
border-right: 1px solid #aaa;
|
||||
border-radius: 0;
|
||||
border-top-left-radius: 4px;
|
||||
border-bottom-left-radius: 4px;
|
||||
left: 1px;
|
||||
right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--single {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
|
||||
background: transparent;
|
||||
border: none; }
|
||||
.select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
|
||||
border-color: transparent transparent #888 transparent;
|
||||
border-width: 0 4px 5px 4px; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
|
||||
background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
|
||||
background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
|
||||
|
||||
.select2-container--classic .select2-selection--multiple {
|
||||
background-color: white;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: text;
|
||||
outline: 0; }
|
||||
.select2-container--classic .select2-selection--multiple:focus {
|
||||
border: 1px solid #5897fb; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__rendered {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__clear {
|
||||
display: none; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #e4e4e4;
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 4px;
|
||||
cursor: default;
|
||||
float: left;
|
||||
margin-right: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 0 5px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
margin-right: 2px; }
|
||||
.select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
|
||||
color: #555; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
float: right; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
|
||||
margin-left: 5px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
|
||||
margin-left: 2px;
|
||||
margin-right: auto; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-selection--multiple {
|
||||
border: 1px solid #5897fb; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
|
||||
border-top: none;
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
|
||||
.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
|
||||
border-bottom: none;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--dropdown .select2-search__field {
|
||||
border: 1px solid #aaa;
|
||||
outline: 0; }
|
||||
|
||||
.select2-container--classic .select2-search--inline .select2-search__field {
|
||||
outline: 0;
|
||||
box-shadow: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown {
|
||||
background-color: white;
|
||||
border: 1px solid transparent; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--above {
|
||||
border-bottom: none; }
|
||||
|
||||
.select2-container--classic .select2-dropdown--below {
|
||||
border-top: none; }
|
||||
|
||||
.select2-container--classic .select2-results > .select2-results__options {
|
||||
max-height: 200px;
|
||||
overflow-y: auto; }
|
||||
|
||||
.select2-container--classic .select2-results__option[role=group] {
|
||||
padding: 0; }
|
||||
|
||||
.select2-container--classic .select2-results__option[aria-disabled=true] {
|
||||
color: grey; }
|
||||
|
||||
.select2-container--classic .select2-results__option--highlighted[aria-selected] {
|
||||
background-color: #3875d7;
|
||||
color: white; }
|
||||
|
||||
.select2-container--classic .select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px; }
|
||||
|
||||
.select2-container--classic.select2-container--open .select2-dropdown {
|
||||
border-color: #5897fb; }
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/af",[],function(){return{errorLoading:function(){return"Die resultate kon nie gelaai word nie."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Verwyders asseblief "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Voer asseblief "+t+" of meer karakters";return n},loadingMore:function(){return"Meer resultate word gelaai…"},maximumSelected:function(e){var t="Kies asseblief net "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"Geen resultate gevind"},searching:function(){return"Besig…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ar",[],function(){return{errorLoading:function(){return"لا يمكن تحميل النتائج"},inputTooLong:function(e){var t=e.input.length-e.maximum;return"الرجاء حذف "+t+" عناصر"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"الرجاء إضافة "+t+" عناصر"},loadingMore:function(){return"جاري تحميل نتائج إضافية..."},maximumSelected:function(e){return"تستطيع إختيار "+e.maximum+" بنود فقط"},noResults:function(){return"لم يتم العثور على أي نتائج"},searching:function(){return"جاري البحث…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/az",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum;return t+" simvol silin"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t+" simvol daxil edin"},loadingMore:function(){return"Daha çox nəticə yüklənir…"},maximumSelected:function(e){return"Sadəcə "+e.maximum+" element seçə bilərsiniz"},noResults:function(){return"Nəticə tapılmadı"},searching:function(){return"Axtarılır…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bg",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Моля въведете с "+t+" по-малко символ";return t>1&&(n+="a"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Моля въведете още "+t+" символ";return t>1&&(n+="a"),n},loadingMore:function(){return"Зареждат се още…"},maximumSelected:function(e){var t="Можете да направите до "+e.maximum+" ";return e.maximum>1?t+="избора":t+="избор",t},noResults:function(){return"Няма намерени съвпадения"},searching:function(){return"Търсене…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/bs",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspijelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ca",[],function(){return{errorLoading:function(){return"La càrrega ha fallat"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Si us plau, elimina "+t+" car";return t==1?n+="àcter":n+="àcters",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Si us plau, introdueix "+t+" car";return t==1?n+="àcter":n+="àcters",n},loadingMore:function(){return"Carregant més resultats…"},maximumSelected:function(e){var t="Només es pot seleccionar "+e.maximum+" element";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No s'han trobat resultats"},searching:function(){return"Cercant…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/cs",[],function(){function e(e,t){switch(e){case 2:return t?"dva":"dvě";case 3:return"tři";case 4:return"čtyři"}return""}return{errorLoading:function(){return"Výsledky nemohly být načteny."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadejte o jeden znak méně.":n<=4?"Prosím, zadejte o "+e(n,!0)+" znaky méně.":"Prosím, zadejte o "+n+" znaků méně."},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadejte ještě jeden znak.":n<=4?"Prosím, zadejte ještě další "+e(n,!0)+" znaky.":"Prosím, zadejte ještě dalších "+n+" znaků."},loadingMore:function(){return"Načítají se další výsledky…"},maximumSelected:function(t){var n=t.maximum;return n==1?"Můžete zvolit jen jednu položku.":n<=4?"Můžete zvolit maximálně "+e(n,!1)+" položky.":"Můžete zvolit maximálně "+n+" položek."},noResults:function(){return"Nenalezeny žádné položky."},searching:function(){return"Vyhledávání…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/da",[],function(){return{errorLoading:function(){return"Resultaterne kunne ikke indlæses."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Angiv venligst "+t+" tegn mindre"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Angiv venligst "+t+" tegn mere"},loadingMore:function(){return"Indlæser flere resultater…"},maximumSelected:function(e){var t="Du kan kun vælge "+e.maximum+" emne";return e.maximum!=1&&(t+="r"),t},noResults:function(){return"Ingen resultater fundet"},searching:function(){return"Søger…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/de",[],function(){return{errorLoading:function(){return"Die Ergebnisse konnten nicht geladen werden."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Bitte "+t+" Zeichen weniger eingeben"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Bitte "+t+" Zeichen mehr eingeben"},loadingMore:function(){return"Lade mehr Ergebnisse…"},maximumSelected:function(e){var t="Sie können nur "+e.maximum+" Eintr";return e.maximum===1?t+="ag":t+="äge",t+=" auswählen",t},noResults:function(){return"Keine Übereinstimmungen gefunden"},searching:function(){return"Suche…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/dsb",[],function(){var e=["znamuško","znamušce","znamuška","znamuškow"],t=["zapisk","zapiska","zapiski","zapiskow"],n=function(t,n){if(t===1)return n[0];if(t===2)return n[1];if(t>2&&t<=4)return n[2];if(t>=5)return n[3]};return{errorLoading:function(){return"Wuslědki njejsu se dali zacytaś."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Pšosym lašuj "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Pšosym zapódaj nanejmjenjej "+r+" "+n(r,e)},loadingMore:function(){return"Dalšne wuslědki se zacytaju…"},maximumSelected:function(e){return"Móžoš jano "+e.maximum+" "+n(e.maximum,t)+"wubraś."},noResults:function(){return"Žedne wuslědki namakane"},searching:function(){return"Pyta se…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/el",[],function(){return{errorLoading:function(){return"Τα αποτελέσματα δεν μπόρεσαν να φορτώσουν."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Παρακαλώ διαγράψτε "+t+" χαρακτήρ";return t==1&&(n+="α"),t!=1&&(n+="ες"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Παρακαλώ συμπληρώστε "+t+" ή περισσότερους χαρακτήρες";return n},loadingMore:function(){return"Φόρτωση περισσότερων αποτελεσμάτων…"},maximumSelected:function(e){var t="Μπορείτε να επιλέξετε μόνο "+e.maximum+" επιλογ";return e.maximum==1&&(t+="ή"),e.maximum!=1&&(t+="ές"),t},noResults:function(){return"Δεν βρέθηκαν αποτελέσματα"},searching:function(){return"Αναζήτηση…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/en",[],function(){return{errorLoading:function(){return"The results could not be loaded."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Please delete "+t+" character";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Please enter "+t+" or more characters";return n},loadingMore:function(){return"Loading more results…"},maximumSelected:function(e){var t="You can only select "+e.maximum+" item";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No results found"},searching:function(){return"Searching…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/es",[],function(){return{errorLoading:function(){return"No se pudieron cargar los resultados"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor, elimine "+t+" car";return t==1?n+="ácter":n+="acteres",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Por favor, introduzca "+t+" car";return t==1?n+="ácter":n+="acteres",n},loadingMore:function(){return"Cargando más resultados…"},maximumSelected:function(e){var t="Sólo puede seleccionar "+e.maximum+" elemento";return e.maximum!=1&&(t+="s"),t},noResults:function(){return"No se encontraron resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/et",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" vähem",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Sisesta "+t+" täht";return t!=1&&(n+="e"),n+=" rohkem",n},loadingMore:function(){return"Laen tulemusi…"},maximumSelected:function(e){var t="Saad vaid "+e.maximum+" tulemus";return e.maximum==1?t+="e":t+="t",t+=" valida",t},noResults:function(){return"Tulemused puuduvad"},searching:function(){return"Otsin…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/eu",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gutxiago",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Idatzi ";return t==1?n+="karaktere bat":n+=t+" karaktere",n+=" gehiago",n},loadingMore:function(){return"Emaitza gehiago kargatzen…"},maximumSelected:function(e){return e.maximum===1?"Elementu bakarra hauta dezakezu":e.maximum+" elementu hauta ditzakezu soilik"},noResults:function(){return"Ez da bat datorrenik aurkitu"},searching:function(){return"Bilatzen…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fa",[],function(){return{errorLoading:function(){return"امکان بارگذاری نتایج وجود ندارد."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="لطفاً "+t+" کاراکتر را حذف نمایید";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لطفاً تعداد "+t+" کاراکتر یا بیشتر وارد نمایید";return n},loadingMore:function(){return"در حال بارگذاری نتایج بیشتر..."},maximumSelected:function(e){var t="شما تنها میتوانید "+e.maximum+" آیتم را انتخاب نمایید";return t},noResults:function(){return"هیچ نتیجهای یافت نشد"},searching:function(){return"در حال جستجو..."}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fi",[],function(){return{errorLoading:function(){return"Tuloksia ei saatu ladattua."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Ole hyvä ja anna "+t+" merkkiä vähemmän"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Ole hyvä ja anna "+t+" merkkiä lisää"},loadingMore:function(){return"Ladataan lisää tuloksia…"},maximumSelected:function(e){return"Voit valita ainoastaan "+e.maximum+" kpl"},noResults:function(){return"Ei tuloksia"},searching:function(){return"Haetaan…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/fr",[],function(){return{errorLoading:function(){return"Les résultats ne peuvent pas être chargés."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Supprimez "+t+" caractère"+(t>1)?"s":""},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Saisissez au moins "+t+" caractère"+(t>1)?"s":""},loadingMore:function(){return"Chargement de résultats supplémentaires…"},maximumSelected:function(e){return"Vous pouvez seulement sélectionner "+e.maximum+" élément"+(e.maximum>1)?"s":""},noResults:function(){return"Aucun résultat trouvé"},searching:function(){return"Recherche en cours…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/gl",[],function(){return{errorLoading:function(){return"Non foi posíbel cargar os resultados."},inputTooLong:function(e){var t=e.input.length-e.maximum;return t===1?"Elimine un carácter":"Elimine "+t+" caracteres"},inputTooShort:function(e){var t=e.minimum-e.input.length;return t===1?"Engada un carácter":"Engada "+t+" caracteres"},loadingMore:function(){return"Cargando máis resultados…"},maximumSelected:function(e){return e.maximum===1?"Só pode seleccionar un elemento":"Só pode seleccionar "+e.maximum+" elementos"},noResults:function(){return"Non se atoparon resultados"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/he",[],function(){return{errorLoading:function(){return"שגיאה בטעינת התוצאות"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="נא למחוק ";return t===1?n+="תו אחד":n+=t+" תווים",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="נא להכניס ";return t===1?n+="תו אחד":n+=t+" תווים",n+=" או יותר",n},loadingMore:function(){return"טוען תוצאות נוספות…"},maximumSelected:function(e){var t="באפשרותך לבחור עד ";return e.maximum===1?t+="פריט אחד":t+=e.maximum+" פריטים",t},noResults:function(){return"לא נמצאו תוצאות"},searching:function(){return"מחפש…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hi",[],function(){return{errorLoading:function(){return"परिणामों को लोड नहीं किया जा सका।"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" अक्षर को हटा दें";return t>1&&(n=t+" अक्षरों को हटा दें "),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="कृपया "+t+" या अधिक अक्षर दर्ज करें";return n},loadingMore:function(){return"अधिक परिणाम लोड हो रहे है..."},maximumSelected:function(e){var t="आप केवल "+e.maximum+" आइटम का चयन कर सकते हैं";return t},noResults:function(){return"कोई परिणाम नहीं मिला"},searching:function(){return"खोज रहा है..."}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hr",[],function(){function e(e){var t=" "+e+" znak";return e%10<5&&e%10>0&&(e%100<5||e%100>19)?e%10>1&&(t+="a"):t+="ova",t}return{errorLoading:function(){return"Preuzimanje nije uspjelo."},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Unesite "+e(n)},inputTooShort:function(t){var n=t.minimum-t.input.length;return"Unesite još "+e(n)},loadingMore:function(){return"Učitavanje rezultata…"},maximumSelected:function(e){return"Maksimalan broj odabranih stavki je "+e.maximum},noResults:function(){return"Nema rezultata"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hsb",[],function(){var e=["znamješko","znamješce","znamješka","znamješkow"],t=["zapisk","zapiskaj","zapiski","zapiskow"],n=function(t,n){if(t===1)return n[0];if(t===2)return n[1];if(t>2&&t<=4)return n[2];if(t>=5)return n[3]};return{errorLoading:function(){return"Wuslědki njedachu so začitać."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Prošu zhašej "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Prošu zapodaj znajmjeńša "+r+" "+n(r,e)},loadingMore:function(){return"Dalše wuslědki so začitaja…"},maximumSelected:function(e){return"Móžeš jenož "+e.maximum+" "+n(e.maximum,t)+"wubrać"},noResults:function(){return"Žane wuslědki namakane"},searching:function(){return"Pyta so…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hu",[],function(){return{errorLoading:function(){return"Az eredmények betöltése nem sikerült."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Túl hosszú. "+t+" karakterrel több, mint kellene."},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Túl rövid. Még "+t+" karakter hiányzik."},loadingMore:function(){return"Töltés…"},maximumSelected:function(e){return"Csak "+e.maximum+" elemet lehet kiválasztani."},noResults:function(){return"Nincs találat."},searching:function(){return"Keresés…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/hy",[],function(){return{errorLoading:function(){return"Արդյունքները հնարավոր չէ բեռնել։"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Խնդրում ենք հեռացնել "+t+" նշան";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Խնդրում ենք մուտքագրել "+t+" կամ ավել նշաններ";return n},loadingMore:function(){return"Բեռնվում են նոր արդյունքներ․․․"},maximumSelected:function(e){var t="Դուք կարող եք ընտրել առավելագույնը "+e.maximum+" կետ";return t},noResults:function(){return"Արդյունքներ չեն գտնվել"},searching:function(){return"Որոնում․․․"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/id",[],function(){return{errorLoading:function(){return"Data tidak boleh diambil."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Hapuskan "+t+" huruf"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Masukkan "+t+" huruf lagi"},loadingMore:function(){return"Mengambil data…"},maximumSelected:function(e){return"Anda hanya dapat memilih "+e.maximum+" pilihan"},noResults:function(){return"Tidak ada data yang sesuai"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/is",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vinsamlegast styttið texta um "+t+" staf";return t<=1?n:n+"i"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vinsamlegast skrifið "+t+" staf";return t>1&&(n+="i"),n+=" í viðbót",n},loadingMore:function(){return"Sæki fleiri niðurstöður…"},maximumSelected:function(e){return"Þú getur aðeins valið "+e.maximum+" atriði"},noResults:function(){return"Ekkert fannst"},searching:function(){return"Leita…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/it",[],function(){return{errorLoading:function(){return"I risultati non possono essere caricati."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Per favore cancella "+t+" caratter";return t!==1?n+="i":n+="e",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Per favore inserisci "+t+" o più caratteri";return n},loadingMore:function(){return"Caricando più risultati…"},maximumSelected:function(e){var t="Puoi selezionare solo "+e.maximum+" element";return e.maximum!==1?t+="i":t+="o",t},noResults:function(){return"Nessun risultato trovato"},searching:function(){return"Sto cercando…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ja",[],function(){return{errorLoading:function(){return"結果が読み込まれませんでした"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" 文字を削除してください";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="少なくとも "+t+" 文字を入力してください";return n},loadingMore:function(){return"読み込み中…"},maximumSelected:function(e){var t=e.maximum+" 件しか選択できません";return t},noResults:function(){return"対象が見つかりません"},searching:function(){return"検索しています…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/km",[],function(){return{errorLoading:function(){return"មិនអាចទាញយកទិន្នន័យ"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="សូមលុបចេញ "+t+" អក្សរ";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="សូមបញ្ចូល"+t+" អក្សរ រឺ ច្រើនជាងនេះ";return n},loadingMore:function(){return"កំពុងទាញយកទិន្នន័យបន្ថែម..."},maximumSelected:function(e){var t="អ្នកអាចជ្រើសរើសបានតែ "+e.maximum+" ជម្រើសប៉ុណ្ណោះ";return t},noResults:function(){return"មិនមានលទ្ធផល"},searching:function(){return"កំពុងស្វែងរក..."}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ko",[],function(){return{errorLoading:function(){return"결과를 불러올 수 없습니다."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="너무 깁니다. "+t+" 글자 지워주세요.";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="너무 짧습니다. "+t+" 글자 더 입력해주세요.";return n},loadingMore:function(){return"불러오는 중…"},maximumSelected:function(e){var t="최대 "+e.maximum+"개까지만 선택 가능합니다.";return t},noResults:function(){return"결과가 없습니다."},searching:function(){return"검색 중…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lt",[],function(){function e(e,t,n,r){return e%10===1&&(e%100<11||e%100>19)?t:e%10>=2&&e%10<=9&&(e%100<11||e%100>19)?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Pašalinkite "+n+" simbol";return r+=e(n,"į","ius","ių"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Įrašykite dar "+n+" simbol";return r+=e(n,"į","ius","ių"),r},loadingMore:function(){return"Kraunama daugiau rezultatų…"},maximumSelected:function(t){var n="Jūs galite pasirinkti tik "+t.maximum+" element";return n+=e(t.maximum,"ą","us","ų"),n},noResults:function(){return"Atitikmenų nerasta"},searching:function(){return"Ieškoma…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/lv",[],function(){function e(e,t,n,r){return e===11?t:e%10===1?n:r}return{inputTooLong:function(t){var n=t.input.length-t.maximum,r="Lūdzu ievadiet par "+n;return r+=" simbol"+e(n,"iem","u","iem"),r+" mazāk"},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Lūdzu ievadiet vēl "+n;return r+=" simbol"+e(n,"us","u","us"),r},loadingMore:function(){return"Datu ielāde…"},maximumSelected:function(t){var n="Jūs varat izvēlēties ne vairāk kā "+t.maximum;return n+=" element"+e(t.maximum,"us","u","us"),n},noResults:function(){return"Sakritību nav"},searching:function(){return"Meklēšana…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/mk",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Ве молиме внесете "+e.maximum+" помалку карактер";return e.maximum!==1&&(n+="и"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Ве молиме внесете уште "+e.maximum+" карактер";return e.maximum!==1&&(n+="и"),n},loadingMore:function(){return"Вчитување резултати…"},maximumSelected:function(e){var t="Можете да изберете само "+e.maximum+" ставк";return e.maximum===1?t+="а":t+="и",t},noResults:function(){return"Нема пронајдено совпаѓања"},searching:function(){return"Пребарување…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ms",[],function(){return{errorLoading:function(){return"Keputusan tidak berjaya dimuatkan."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Sila hapuskan "+t+" aksara"},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Sila masukkan "+t+" atau lebih aksara"},loadingMore:function(){return"Sedang memuatkan keputusan…"},maximumSelected:function(e){return"Anda hanya boleh memilih "+e.maximum+" pilihan"},noResults:function(){return"Tiada padanan yang ditemui"},searching:function(){return"Mencari…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nb",[],function(){return{errorLoading:function(){return"Kunne ikke hente resultater."},inputTooLong:function(e){var t=e.input.length-e.maximum;return"Vennligst fjern "+t+" tegn"},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vennligst skriv inn "+t+" tegn til";return n+" tegn til"},loadingMore:function(){return"Laster flere resultater…"},maximumSelected:function(e){return"Du kan velge maks "+e.maximum+" elementer"},noResults:function(){return"Ingen treff"},searching:function(){return"Søker…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/nl",[],function(){return{errorLoading:function(){return"De resultaten konden niet worden geladen."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Gelieve "+t+" karakters te verwijderen";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Gelieve "+t+" of meer karakters in te voeren";return n},loadingMore:function(){return"Meer resultaten laden…"},maximumSelected:function(e){var t=e.maximum==1?"kan":"kunnen",n="Er "+t+" maar "+e.maximum+" item";return e.maximum!=1&&(n+="s"),n+=" worden geselecteerd",n},noResults:function(){return"Geen resultaten gevonden…"},searching:function(){return"Zoeken…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pl",[],function(){var e=["znak","znaki","znaków"],t=["element","elementy","elementów"],n=function(t,n){if(t===1)return n[0];if(t>1&&t<=4)return n[1];if(t>=5)return n[2]};return{errorLoading:function(){return"Nie można załadować wyników."},inputTooLong:function(t){var r=t.input.length-t.maximum;return"Usuń "+r+" "+n(r,e)},inputTooShort:function(t){var r=t.minimum-t.input.length;return"Podaj przynajmniej "+r+" "+n(r,e)},loadingMore:function(){return"Trwa ładowanie…"},maximumSelected:function(e){return"Możesz zaznaczyć tylko "+e.maximum+" "+n(e.maximum,t)},noResults:function(){return"Brak wyników"},searching:function(){return"Trwa wyszukiwanie…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ps",[],function(){return{errorLoading:function(){return"پايلي نه سي ترلاسه کېدای"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="د مهربانۍ لمخي "+t+" توری ړنګ کړئ";return t!=1&&(n=n.replace("توری","توري")),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="لږ تر لږه "+t+" يا ډېر توري وليکئ";return n},loadingMore:function(){return"نوري پايلي ترلاسه کيږي..."},maximumSelected:function(e){var t="تاسو يوازي "+e.maximum+" قلم په نښه کولای سی";return e.maximum!=1&&(t=t.replace("قلم","قلمونه")),t},noResults:function(){return"پايلي و نه موندل سوې"},searching:function(){return"لټول کيږي..."}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt-BR",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Apague "+t+" caracter";return t!=1&&(n+="es"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Digite "+t+" ou mais caracteres";return n},loadingMore:function(){return"Carregando mais resultados…"},maximumSelected:function(e){var t="Você só pode selecionar "+e.maximum+" ite";return e.maximum==1?t+="m":t+="ns",t},noResults:function(){return"Nenhum resultado encontrado"},searching:function(){return"Buscando…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/pt",[],function(){return{errorLoading:function(){return"Os resultados não puderam ser carregados."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Por favor apague "+t+" ";return n+=t!=1?"caracteres":"caractere",n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Introduza "+t+" ou mais caracteres";return n},loadingMore:function(){return"A carregar mais resultados…"},maximumSelected:function(e){var t="Apenas pode seleccionar "+e.maximum+" ";return t+=e.maximum!=1?"itens":"item",t},noResults:function(){return"Sem resultados"},searching:function(){return"A procurar…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ro",[],function(){return{errorLoading:function(){return"Rezultatele nu au putut fi incărcate."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vă rugăm să ștergeți"+t+" caracter";return t!==1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vă rugăm să introduceți "+t+" sau mai multe caractere";return n},loadingMore:function(){return"Se încarcă mai multe rezultate…"},maximumSelected:function(e){var t="Aveți voie să selectați cel mult "+e.maximum;return t+=" element",e.maximum!==1&&(t+="e"),t},noResults:function(){return"Nu au fost găsite rezultate"},searching:function(){return"Căutare…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/ru",[],function(){function e(e,t,n,r){return e%10<5&&e%10>0&&e%100<5||e%100>20?e%10>1?n:t:r}return{errorLoading:function(){return"Невозможно загрузить результаты"},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Пожалуйста, введите на "+n+" символ";return r+=e(n,"","a","ов"),r+=" меньше",r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Пожалуйста, введите еще хотя бы "+n+" символ";return r+=e(n,"","a","ов"),r},loadingMore:function(){return"Загрузка данных…"},maximumSelected:function(t){var n="Вы можете выбрать не более "+t.maximum+" элемент";return n+=e(t.maximum,"","a","ов"),n},noResults:function(){return"Совпадений не найдено"},searching:function(){return"Поиск…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sk",[],function(){var e={2:function(e){return e?"dva":"dve"},3:function(){return"tri"},4:function(){return"štyri"}};return{errorLoading:function(){return"Výsledky sa nepodarilo načítať."},inputTooLong:function(t){var n=t.input.length-t.maximum;return n==1?"Prosím, zadajte o jeden znak menej":n>=2&&n<=4?"Prosím, zadajte o "+e[n](!0)+" znaky menej":"Prosím, zadajte o "+n+" znakov menej"},inputTooShort:function(t){var n=t.minimum-t.input.length;return n==1?"Prosím, zadajte ešte jeden znak":n<=4?"Prosím, zadajte ešte ďalšie "+e[n](!0)+" znaky":"Prosím, zadajte ešte ďalších "+n+" znakov"},loadingMore:function(){return"Načítanie ďalších výsledkov…"},maximumSelected:function(t){return t.maximum==1?"Môžete zvoliť len jednu položku":t.maximum>=2&&t.maximum<=4?"Môžete zvoliť najviac "+e[t.maximum](!1)+" položky":"Môžete zvoliť najviac "+t.maximum+" položiek"},noResults:function(){return"Nenašli sa žiadne položky"},searching:function(){return"Vyhľadávanie…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sl",[],function(){return{errorLoading:function(){return"Zadetkov iskanja ni bilo mogoče naložiti."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Prosim zbrišite "+t+" znak";return t==2?n+="a":t!=1&&(n+="e"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Prosim vpišite še "+t+" znak";return t==2?n+="a":t!=1&&(n+="e"),n},loadingMore:function(){return"Nalagam več zadetkov…"},maximumSelected:function(e){var t="Označite lahko največ "+e.maximum+" predmet";return e.maximum==2?t+="a":e.maximum!=1&&(t+="e"),t},noResults:function(){return"Ni zadetkov."},searching:function(){return"Iščem…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr-Cyrl",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Преузимање није успело."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Обришите "+n+" симбол";return r+=e(n,"","а","а"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Укуцајте бар још "+n+" симбол";return r+=e(n,"","а","а"),r},loadingMore:function(){return"Преузимање још резултата…"},maximumSelected:function(t){var n="Можете изабрати само "+t.maximum+" ставк";return n+=e(t.maximum,"у","е","и"),n},noResults:function(){return"Ништа није пронађено"},searching:function(){return"Претрага…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sr",[],function(){function e(e,t,n,r){return e%10==1&&e%100!=11?t:e%10>=2&&e%10<=4&&(e%100<12||e%100>14)?n:r}return{errorLoading:function(){return"Preuzimanje nije uspelo."},inputTooLong:function(t){var n=t.input.length-t.maximum,r="Obrišite "+n+" simbol";return r+=e(n,"","a","a"),r},inputTooShort:function(t){var n=t.minimum-t.input.length,r="Ukucajte bar još "+n+" simbol";return r+=e(n,"","a","a"),r},loadingMore:function(){return"Preuzimanje još rezultata…"},maximumSelected:function(t){var n="Možete izabrati samo "+t.maximum+" stavk";return n+=e(t.maximum,"u","e","i"),n},noResults:function(){return"Ništa nije pronađeno"},searching:function(){return"Pretraga…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/sv",[],function(){return{errorLoading:function(){return"Resultat kunde inte laddas."},inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vänligen sudda ut "+t+" tecken";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vänligen skriv in "+t+" eller fler tecken";return n},loadingMore:function(){return"Laddar fler resultat…"},maximumSelected:function(e){var t="Du kan max välja "+e.maximum+" element";return t},noResults:function(){return"Inga träffar"},searching:function(){return"Söker…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/th",[],function(){return{errorLoading:function(){return"ไม่สามารถค้นข้อมูลได้"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="โปรดลบออก "+t+" ตัวอักษร";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="โปรดพิมพ์เพิ่มอีก "+t+" ตัวอักษร";return n},loadingMore:function(){return"กำลังค้นข้อมูลเพิ่ม…"},maximumSelected:function(e){var t="คุณสามารถเลือกได้ไม่เกิน "+e.maximum+" รายการ";return t},noResults:function(){return"ไม่พบข้อมูล"},searching:function(){return"กำลังค้นข้อมูล…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/tr",[],function(){return{errorLoading:function(){return"Sonuç yüklenemedi"},inputTooLong:function(e){var t=e.input.length-e.maximum,n=t+" karakter daha girmelisiniz";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="En az "+t+" karakter daha girmelisiniz";return n},loadingMore:function(){return"Daha fazla…"},maximumSelected:function(e){var t="Sadece "+e.maximum+" seçim yapabilirsiniz";return t},noResults:function(){return"Sonuç bulunamadı"},searching:function(){return"Aranıyor…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/uk",[],function(){function e(e,t,n,r){return e%100>10&&e%100<15?r:e%10===1?t:e%10>1&&e%10<5?n:r}return{errorLoading:function(){return"Неможливо завантажити результати"},inputTooLong:function(t){var n=t.input.length-t.maximum;return"Будь ласка, видаліть "+n+" "+e(t.maximum,"літеру","літери","літер")},inputTooShort:function(e){var t=e.minimum-e.input.length;return"Будь ласка, введіть "+t+" або більше літер"},loadingMore:function(){return"Завантаження інших результатів…"},maximumSelected:function(t){return"Ви можете вибрати лише "+t.maximum+" "+e(t.maximum,"пункт","пункти","пунктів")},noResults:function(){return"Нічого не знайдено"},searching:function(){return"Пошук…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/vi",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="Vui lòng nhập ít hơn "+t+" ký tự";return t!=1&&(n+="s"),n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="Vui lòng nhập nhiều hơn "+t+" ký tự";return n},loadingMore:function(){return"Đang lấy thêm kết quả…"},maximumSelected:function(e){var t="Chỉ có thể chọn được "+e.maximum+" lựa chọn";return t},noResults:function(){return"Không tìm thấy kết quả"},searching:function(){return"Đang tìm…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(e){var t=e.input.length-e.maximum,n="请删除"+t+"个字符";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="请再输入至少"+t+"个字符";return n},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(e){var t="最多只能选择"+e.maximum+"个项目";return t},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"}}}),{define:e.define,require:e.require}})();
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/*! Select2 4.0.5 | https://github.com/select2/select2/blob/master/LICENSE.md */
|
||||
|
||||
(function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var e=jQuery.fn.select2.amd;return e.define("select2/i18n/zh-TW",[],function(){return{inputTooLong:function(e){var t=e.input.length-e.maximum,n="請刪掉"+t+"個字元";return n},inputTooShort:function(e){var t=e.minimum-e.input.length,n="請再輸入"+t+"個字元";return n},loadingMore:function(){return"載入中…"},maximumSelected:function(e){var t="你只能選擇最多"+e.maximum+"項";return t},noResults:function(){return"沒有找到相符的項目"},searching:function(){return"搜尋中…"}}}),{define:e.define,require:e.require}})();
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
|
@ -1,12 +1,14 @@
|
|||
from Crypto.Cipher import PKCS1_OAEP
|
||||
from Crypto.PublicKey import RSA
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Device
|
||||
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldForm
|
||||
from utilities.forms import BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField
|
||||
from utilities.forms import (
|
||||
APISelect, APISelectMultiple, BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField,
|
||||
StaticSelect2Multiple
|
||||
)
|
||||
from .models import Secret, SecretRole, UserKey
|
||||
|
||||
|
||||
|
|
@ -42,6 +44,10 @@ class SecretRoleForm(BootstrapMixin, forms.ModelForm):
|
|||
fields = [
|
||||
'name', 'slug', 'users', 'groups',
|
||||
]
|
||||
widgets = {
|
||||
'users': StaticSelect2Multiple(),
|
||||
'groups': StaticSelect2Multiple(),
|
||||
}
|
||||
|
||||
|
||||
class SecretRoleCSVForm(forms.ModelForm):
|
||||
|
|
@ -85,6 +91,11 @@ class SecretForm(BootstrapMixin, CustomFieldForm):
|
|||
fields = [
|
||||
'role', 'name', 'plaintext', 'plaintext2', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'role': APISelect(
|
||||
api_url="/api/secrets/secret-roles/"
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
|
@ -143,7 +154,10 @@ class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=SecretRole.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/secrets/secret-roles/"
|
||||
)
|
||||
)
|
||||
name = forms.CharField(
|
||||
max_length=100,
|
||||
|
|
@ -163,10 +177,12 @@ class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
label='Search'
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=SecretRole.objects.annotate(
|
||||
filter_count=Count('secrets')
|
||||
),
|
||||
to_field_name='slug'
|
||||
queryset=SecretRole.objects.all(),
|
||||
to_field_name='slug',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/secrets/secret-roles/",
|
||||
value_field="slug",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'font-awesome-4.7.0/css/font-awesome.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'jquery-ui-1.12.1/jquery-ui.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'select2-4.0.5/css/select2.min.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/base.css' %}?v{{ settings.VERSION }}">
|
||||
<link rel="icon" type="image/png" href="{% static 'img/netbox.ico' %}" />
|
||||
<meta charset="UTF-8">
|
||||
|
|
@ -66,6 +67,7 @@
|
|||
<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
|
||||
<script src="{% static 'jquery-ui-1.12.1/jquery-ui.min.js' %}"></script>
|
||||
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'select2-4.0.5/js/select2.min.js' %}"></script>
|
||||
<script src="{% static 'js/forms.js' %}?v{{ settings.VERSION }}"></script>
|
||||
<script type="text/javascript">
|
||||
var netbox_api_path = "/{{ settings.BASE_PATH }}api/";
|
||||
|
|
|
|||
|
|
@ -107,14 +107,14 @@
|
|||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="search">
|
||||
{% render_field form.livesearch %}
|
||||
|
||||
</div>
|
||||
<div class="tab-pane" id="select">
|
||||
{% render_field form.termination_b_site %}
|
||||
{% render_field form.termination_b_rack %}
|
||||
{% render_field form.termination_b_device %}
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.termination_b_device %}
|
||||
{% render_field form.termination_b_type %}
|
||||
{% render_field form.termination_b_id %}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -20,88 +20,3 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
||||
var site_list = $('#id_site');
|
||||
var rack_group_list = $('#id_rack_group_id');
|
||||
var rack_list = $('#id_rack_id');
|
||||
var manufacturer_list = $('#id_manufacturer_id');
|
||||
var model_list = $('#id_device_type_id');
|
||||
|
||||
// Update device type options based on selected manufacturer
|
||||
manufacturer_list.change(function() {
|
||||
var selected_manufacturers = $(this).val();
|
||||
if (selected_manufacturers) {
|
||||
model_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/device-types/?limit=500&manufacturer_id=' + selected_manufacturers.join('&manufacturer_id='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, device_type) {
|
||||
var option = $("<option></option>").attr("value", device_type.id).text(device_type.model + " (" + device_type.instance_count + ")");
|
||||
model_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Update rack group and rack options based on selected site
|
||||
site_list.change(function() {
|
||||
var selected_sites = $(this).val();
|
||||
if (selected_sites) {
|
||||
|
||||
// Update rack group options
|
||||
rack_group_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/rack-groups/?limit=500&site=' + selected_sites.join('&site='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, group) {
|
||||
var option = $("<option></option>").attr("value", group.id).text(group.name);
|
||||
rack_group_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Update rack options
|
||||
rack_list.empty();
|
||||
rack_list.append($("<option></option>").attr("value", "0").text("None"));
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/racks/?limit=500&site=' + selected_sites.join('&site='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, rack) {
|
||||
var option = $("<option></option>").attr("value", rack.id).text(rack.display_name);
|
||||
rack_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Update rack options based on selected rack group
|
||||
rack_group_list.change(function() {
|
||||
var selected_rack_groups = $(this).val();
|
||||
if (selected_rack_groups) {
|
||||
rack_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/racks/?limit=500&group_id=' + selected_rack_groups.join('&group_id='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, rack) {
|
||||
var option = $("<option></option>").attr("value", rack.id).text(rack.display_name);
|
||||
rack_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
||||
var site_list = $('#id_site');
|
||||
var rack_group_list = $('#id_group_id');
|
||||
|
||||
// Update rack group and rack options based on selected site
|
||||
site_list.change(function() {
|
||||
var selected_sites = $(this).val();
|
||||
if (selected_sites) {
|
||||
|
||||
// Update rack group options
|
||||
rack_group_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'dcim/rack-groups/?limit=500&site=' + selected_sites.join('&site='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, group) {
|
||||
var option = $("<option></option>").attr("value", group.id).text(group.name);
|
||||
rack_group_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
|
@ -20,8 +20,3 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
{% include 'dcim/inc/filter_rack_group.html' %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@
|
|||
{% render_field form.nat_device %}
|
||||
</div>
|
||||
<div class="tab-pane" id="search">
|
||||
{% render_field form.livesearch %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% render_field form.nat_inside %}
|
||||
|
|
|
|||
|
|
@ -20,32 +20,3 @@
|
|||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
||||
var cluster_group_list = $('#id_cluster_group');
|
||||
var cluster_list = $('#id_cluster_id');
|
||||
|
||||
// Update cluster options based on selected group
|
||||
cluster_group_list.change(function() {
|
||||
var selected_groups = $(this).val();
|
||||
if (selected_groups) {
|
||||
cluster_list.empty();
|
||||
$.ajax({
|
||||
url: netbox_api_path + 'virtualization/clusters/?limit=500&group=' + selected_groups.join('&group='),
|
||||
dataType: 'json',
|
||||
success: function (response, status) {
|
||||
$.each(response["results"], function (index, cluster) {
|
||||
var option = $("<option></option>").attr("value", cluster.id).text(cluster.name);
|
||||
cluster_list.append(option);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ from taggit.forms import TagField
|
|||
|
||||
from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||
from utilities.forms import (
|
||||
APISelect, BootstrapMixin, ChainedFieldsMixin, ChainedModelChoiceField, CommentField, FilterChoiceField, SlugField,
|
||||
APISelect, APISelectMultiple, BootstrapMixin, ChainedFieldsMixin, ChainedModelChoiceField, CommentField,
|
||||
FilterChoiceField, SlugField,
|
||||
)
|
||||
from .models import Tenant, TenantGroup
|
||||
|
||||
|
|
@ -50,6 +51,11 @@ class TenantForm(BootstrapMixin, CustomFieldForm):
|
|||
fields = [
|
||||
'name', 'slug', 'group', 'description', 'comments', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'group': APISelect(
|
||||
api_url="/api/tenancy/tenant-groups/"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class TenantCSVForm(forms.ModelForm):
|
||||
|
|
@ -80,7 +86,10 @@ class TenantBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||
)
|
||||
group = forms.ModelChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenant-groups/"
|
||||
)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -96,11 +105,14 @@ class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
label='Search'
|
||||
)
|
||||
group = FilterChoiceField(
|
||||
queryset=TenantGroup.objects.annotate(
|
||||
filter_count=Count('tenants')
|
||||
),
|
||||
queryset=TenantGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/tenancy/tenant-groups/",
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -112,9 +124,12 @@ class TenancyForm(ChainedFieldsMixin, forms.Form):
|
|||
tenant_group = forms.ModelChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url="/api/tenancy/tenant-groups/",
|
||||
filter_for={
|
||||
'tenant': 'group_id',
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'tenant',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -126,7 +141,7 @@ class TenancyForm(ChainedFieldsMixin, forms.Form):
|
|||
),
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/tenancy/tenants/?group_id={{tenant_group}}'
|
||||
api_url='/api/tenancy/tenants/'
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ class ColorSelect(forms.Select):
|
|||
def __init__(self, *args, **kwargs):
|
||||
kwargs['choices'] = add_blank_choice(COLOR_CHOICES)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.attrs['class'] = 'netbox-select2-color-picker'
|
||||
|
||||
|
||||
class BulkEditNullBooleanSelect(forms.NullBooleanSelect):
|
||||
|
|
@ -185,6 +186,7 @@ class BulkEditNullBooleanSelect(forms.NullBooleanSelect):
|
|||
('2', 'Yes'),
|
||||
('3', 'No'),
|
||||
)
|
||||
self.attrs['class'] = 'netbox-select2-static'
|
||||
|
||||
|
||||
class SelectWithDisabled(forms.Select):
|
||||
|
|
@ -195,7 +197,42 @@ class SelectWithDisabled(forms.Select):
|
|||
option_template_name = 'widgets/selectwithdisabled_option.html'
|
||||
|
||||
|
||||
class SelectWithPK(forms.Select):
|
||||
class StaticSelect2(SelectWithDisabled):
|
||||
"""
|
||||
A static content using the Select2 widget
|
||||
|
||||
:param filter_for: (Optional) A dict of chained form fields for which this field is a filter. The key is the
|
||||
name of the filter-for field (child field) and the value is the name of the query param filter.
|
||||
"""
|
||||
|
||||
def __init__(self, filter_for=None, *args, **kwargs):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.attrs['class'] = 'netbox-select2-static'
|
||||
if filter_for:
|
||||
for key, value in filter_for.items():
|
||||
self.add_filter_for(key, value)
|
||||
|
||||
def add_filter_for(self, name, value):
|
||||
"""
|
||||
Add details for an additional query param in the form of a data-filter-for-* attribute.
|
||||
|
||||
:param name: The name of the query param
|
||||
:param value: The value of the query param
|
||||
"""
|
||||
self.attrs['data-filter-for-{}'.format(name)] = value
|
||||
|
||||
|
||||
class StaticSelect2Multiple(StaticSelect2, forms.SelectMultiple):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.attrs['data-multiple'] = 1
|
||||
|
||||
|
||||
class SelectWithPK(StaticSelect2):
|
||||
"""
|
||||
Include the primary key of each option in the option label (e.g. "Router7 (4721)").
|
||||
"""
|
||||
|
|
@ -237,62 +274,91 @@ class APISelect(SelectWithDisabled):
|
|||
|
||||
:param api_url: API URL
|
||||
:param display_field: (Optional) Field to display for child in selection list. Defaults to `name`.
|
||||
:param value_field: (Optional) Field to use for the option value in selection list. Defaults to `id`.
|
||||
:param disabled_indicator: (Optional) Mark option as disabled if this field equates true.
|
||||
:param url_conditional_append: (Optional) A dict of URL query strings to append to the URL if the
|
||||
:param filter_for: (Optional) A dict of chained form fields for which this field is a filter. The key is the
|
||||
name of the filter-for field (child field) and the value is the name of the query param filter.
|
||||
:param conditional_query_params: (Optional) A dict of URL query params to append to the URL if the
|
||||
condition is met. The condition is the dict key and is specified in the form `<field_name>__<field_value>`.
|
||||
If the provided field value is selected for the given field, the URL query string will be appended to
|
||||
the rendered URL. This is useful in cases where a particular field value dictates an additional API filter.
|
||||
If the provided field value is selected for the given field, the URL query param will be appended to
|
||||
the rendered URL. The value is the in the from `<param_name>=<param_value>`. This is useful in cases where
|
||||
a particular field value dictates an additional API filter.
|
||||
:param additional_query_params: Optional) A dict of query params to append to the API request. The key is the
|
||||
name of the query param and the value if the query param's value.
|
||||
:param null_option: If true, include the static null option in the selection list.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
api_url,
|
||||
display_field=None,
|
||||
value_field=None,
|
||||
disabled_indicator=None,
|
||||
url_conditional_append=None,
|
||||
filter_for=None,
|
||||
conditional_query_params=None,
|
||||
additional_query_params=None,
|
||||
null_option=False,
|
||||
*args,
|
||||
**kwargs
|
||||
):
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.attrs['class'] = 'api-select'
|
||||
self.attrs['api-url'] = '/{}{}'.format(settings.BASE_PATH, api_url.lstrip('/')) # Inject BASE_PATH
|
||||
self.attrs['class'] = 'netbox-select2-api'
|
||||
self.attrs['data-url'] = '/{}{}'.format(settings.BASE_PATH, api_url.lstrip('/')) # Inject BASE_PATH
|
||||
if display_field:
|
||||
self.attrs['display-field'] = display_field
|
||||
if value_field:
|
||||
self.attrs['value-field'] = value_field
|
||||
if disabled_indicator:
|
||||
self.attrs['disabled-indicator'] = disabled_indicator
|
||||
if url_conditional_append:
|
||||
for key, value in url_conditional_append.items():
|
||||
self.attrs["data-url-conditional-append-{}".format(key)] = value
|
||||
if filter_for:
|
||||
for key, value in filter_for.items():
|
||||
self.add_filter_for(key, value)
|
||||
if conditional_query_params:
|
||||
for key, value in conditional_query_params.items():
|
||||
self.add_conditional_query_param(key, value)
|
||||
if additional_query_params:
|
||||
for key, value in additional_query_params.items():
|
||||
self.add_additional_query_param(key, value)
|
||||
if null_option:
|
||||
self.attrs['data-null-option'] = 1
|
||||
|
||||
def add_filter_for(self, name, value):
|
||||
"""
|
||||
Add details for an additional query param in the form of a data-filter-for-* attribute.
|
||||
|
||||
:param name: The name of the query param
|
||||
:param value: The value of the query param
|
||||
"""
|
||||
self.attrs['data-filter-for-{}'.format(name)] = value
|
||||
|
||||
def add_additional_query_param(self, name, value):
|
||||
"""
|
||||
Add details for an additional query param in the form of a data-* attribute.
|
||||
|
||||
:param name: The name of the query param
|
||||
:param value: The value of the query param
|
||||
"""
|
||||
self.attrs['data-additional-query-param-{}'.format(name)] = value
|
||||
|
||||
def add_conditional_query_param(self, condition, value):
|
||||
"""
|
||||
Add details for a URL query strings to append to the URL if the condition is met.
|
||||
The condition is specified in the form `<field_name>__<field_value>`.
|
||||
|
||||
:param condition: The condition for the query param
|
||||
:param value: The value of the query param
|
||||
"""
|
||||
self.attrs['data-conditional-query-param-{}'.format(condition)] = value
|
||||
|
||||
|
||||
class APISelectMultiple(APISelect):
|
||||
allow_multiple_selected = True
|
||||
|
||||
|
||||
class Livesearch(forms.TextInput):
|
||||
"""
|
||||
A text widget that carries a few extra bits of data for use in AJAX-powered autocomplete search
|
||||
|
||||
:param query_key: The name of the parameter to query against
|
||||
:param query_url: The name of the API URL to query
|
||||
:param field_to_update: The name of the "real" form field whose value is being set
|
||||
:param obj_label: The field to use as the option label (optional)
|
||||
"""
|
||||
|
||||
def __init__(self, query_key, query_url, field_to_update, obj_label=None, *args, **kwargs):
|
||||
class APISelectMultiple(APISelect, forms.SelectMultiple):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.attrs = {
|
||||
'data-key': query_key,
|
||||
'data-source': reverse_lazy(query_url),
|
||||
'data-field': field_to_update,
|
||||
}
|
||||
|
||||
if obj_label:
|
||||
self.attrs['data-label'] = obj_label
|
||||
self.attrs['data-multiple'] = 1
|
||||
|
||||
|
||||
#
|
||||
|
|
@ -530,53 +596,6 @@ class FilterTreeNodeMultipleChoiceField(FilterChoiceFieldMixin, TreeNodeMultiple
|
|||
pass
|
||||
|
||||
|
||||
class AnnotatedMultipleChoiceField(forms.MultipleChoiceField):
|
||||
"""
|
||||
Render a set of static choices with each choice annotated to include a count of related objects. For example, this
|
||||
field can be used to display a list of all available device statuses along with the number of devices currently
|
||||
assigned to each status.
|
||||
"""
|
||||
|
||||
def annotate_choices(self):
|
||||
|
||||
# Aggregate objects by choice field values
|
||||
queryset = self.annotate.values(
|
||||
self.annotate_field
|
||||
).annotate(
|
||||
count=Count(self.annotate_field)
|
||||
).order_by(
|
||||
self.annotate_field
|
||||
)
|
||||
choice_counts = {
|
||||
c[self.annotate_field]: c['count'] for c in queryset
|
||||
}
|
||||
|
||||
annotated_choices = []
|
||||
|
||||
# Optionally add a "none" choice
|
||||
if self.include_null:
|
||||
annotated_choices.append((
|
||||
settings.FILTERS_NULL_CHOICE_VALUE,
|
||||
'-- {} --'.format(settings.FILTERS_NULL_CHOICE_LABEL)
|
||||
))
|
||||
|
||||
# Append each choice and its annotated count
|
||||
for c in self.static_choices:
|
||||
annotated_choices.append(
|
||||
(c[0], '{} ({})'.format(c[1], choice_counts.get(c[0], 0)))
|
||||
)
|
||||
|
||||
return annotated_choices
|
||||
|
||||
def __init__(self, choices, annotate, annotate_field, include_null=False, **kwargs):
|
||||
self.annotate = annotate
|
||||
self.annotate_field = annotate_field
|
||||
self.include_null = include_null
|
||||
self.static_choices = unpack_grouped_choices(choices)
|
||||
|
||||
super().__init__(choices=self.annotate_choices, **kwargs)
|
||||
|
||||
|
||||
class LaxURLField(forms.URLField):
|
||||
"""
|
||||
Modifies Django's built-in URLField in two ways:
|
||||
|
|
@ -642,7 +661,7 @@ class ChainedFieldsMixin(forms.BaseForm):
|
|||
|
||||
filters_dict = {}
|
||||
for (db_field, parent_field) in field.chains:
|
||||
if self.is_bound and parent_field in self.data:
|
||||
if self.is_bound and parent_field in self.data and self.data[parent_field]:
|
||||
filters_dict[db_field] = self.data[parent_field] or None
|
||||
elif self.initial.get(parent_field):
|
||||
filters_dict[db_field] = self.initial[parent_field]
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
<option value="{{ widget.value }}"{% include "django/forms/widgets/attrs.html" %} style="background-color: #{{ widget.value }}">{{ widget.label }}</option>
|
||||
<option value="{{ widget.value }}"{% include "django/forms/widgets/attrs.html" %} class="color-selection-{{ widget.value }}">{{ widget.label }}</option>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Count
|
||||
from mptt.forms import TreeNodeChoiceField
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.constants import IFACE_FF_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL
|
||||
|
|
@ -12,10 +10,10 @@ from ipam.models import IPAddress
|
|||
from tenancy.forms import TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
AnnotatedMultipleChoiceField, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
||||
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
||||
ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
|
||||
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, FilterTreeNodeMultipleChoiceField,
|
||||
JSONField, SlugField, SmallTextarea, add_blank_choice,
|
||||
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, JSONField, SlugField,
|
||||
SmallTextarea, StaticSelect2, StaticSelect2Multiple
|
||||
)
|
||||
from .constants import VM_STATUS_CHOICES
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
|
|
@ -92,6 +90,17 @@ class ClusterForm(BootstrapMixin, CustomFieldForm):
|
|||
fields = [
|
||||
'name', 'type', 'group', 'site', 'comments', 'tags',
|
||||
]
|
||||
widgets = {
|
||||
'type': APISelect(
|
||||
api_url="/api/virtualization/cluster-types/"
|
||||
),
|
||||
'group': APISelect(
|
||||
api_url="/api/virtualization/cluster-groups/"
|
||||
),
|
||||
'site': APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class ClusterCSVForm(forms.ModelForm):
|
||||
|
|
@ -134,15 +143,24 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
|
|||
)
|
||||
type = forms.ModelChoiceField(
|
||||
queryset=ClusterType.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/virtualization/cluster-types/"
|
||||
)
|
||||
)
|
||||
group = forms.ModelChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/virtualization/cluster-groups/"
|
||||
)
|
||||
)
|
||||
site = forms.ModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/sites/"
|
||||
)
|
||||
)
|
||||
comments = CommentField(
|
||||
widget=SmallTextarea()
|
||||
|
|
@ -158,37 +176,48 @@ class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
model = Cluster
|
||||
q = forms.CharField(required=False, label='Search')
|
||||
type = FilterChoiceField(
|
||||
queryset=ClusterType.objects.annotate(
|
||||
filter_count=Count('clusters')
|
||||
),
|
||||
queryset=ClusterType.objects.all(),
|
||||
to_field_name='slug',
|
||||
required=False,
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/virtualization/cluster-types/",
|
||||
value_field='slug',
|
||||
)
|
||||
)
|
||||
group = FilterChoiceField(
|
||||
queryset=ClusterGroup.objects.annotate(
|
||||
filter_count=Count('clusters')
|
||||
),
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --',
|
||||
required=False,
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/virtualization/cluster-groups/",
|
||||
value_field='slug',
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('clusters')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --',
|
||||
required=False,
|
||||
widget=APISelectMultiple(
|
||||
api_url="/api/dcim/sites/",
|
||||
value_field='slug',
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
|
||||
region = TreeNodeChoiceField(
|
||||
region = forms.ModelChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/regions/",
|
||||
filter_for={
|
||||
"site": "region_id",
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'site',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -200,9 +229,10 @@ class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
|
|||
),
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/sites/?region_id={{region}}',
|
||||
attrs={
|
||||
'filter-for': 'rack',
|
||||
api_url='/api/dcim/sites/',
|
||||
filter_for={
|
||||
"rack": "site_id",
|
||||
"devices": "site_id",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
|
@ -213,9 +243,11 @@ class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
|
|||
),
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/racks/?site_id={{site}}',
|
||||
api_url='/api/dcim/racks/',
|
||||
filter_for={
|
||||
"devices": "rack_id"
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'devices',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -227,7 +259,7 @@ class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
|
|||
('rack', 'rack'),
|
||||
),
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/dcim/devices/?site_id={{site}}&rack_id={{rack}}',
|
||||
api_url='/api/dcim/devices/',
|
||||
display_field='display_name',
|
||||
disabled_indicator='cluster'
|
||||
)
|
||||
|
|
@ -275,9 +307,12 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
cluster_group = forms.ModelChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
required=False,
|
||||
widget=forms.Select(
|
||||
widget=APISelect(
|
||||
api_url='/api/virtualization/cluster-groups/',
|
||||
filter_for={
|
||||
"cluster": "group_id",
|
||||
},
|
||||
attrs={
|
||||
'filter-for': 'cluster',
|
||||
'nullable': 'true',
|
||||
}
|
||||
)
|
||||
|
|
@ -288,7 +323,7 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
('group', 'cluster_group'),
|
||||
),
|
||||
widget=APISelect(
|
||||
api_url='/api/virtualization/clusters/?group_id={{cluster_group}}'
|
||||
api_url='/api/virtualization/clusters/'
|
||||
)
|
||||
)
|
||||
tags = TagField(
|
||||
|
|
@ -308,6 +343,20 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
|||
'local_context_data': "Local config context data overwrites all sources contexts in the final rendered "
|
||||
"config context",
|
||||
}
|
||||
widgets = {
|
||||
"status": StaticSelect2(),
|
||||
"role": APISelect(
|
||||
api_url="/api/dcim/device-roles/",
|
||||
additional_query_params={
|
||||
"vm_role": "true"
|
||||
}
|
||||
),
|
||||
'primary_ip4': StaticSelect2(),
|
||||
'primary_ip6': StaticSelect2(),
|
||||
'platform': APISelect(
|
||||
api_url='/api/dcim/platforms/'
|
||||
)
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
|
|
@ -413,25 +462,41 @@ class VirtualMachineBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldB
|
|||
status = forms.ChoiceField(
|
||||
choices=add_blank_choice(VM_STATUS_CHOICES),
|
||||
required=False,
|
||||
initial=''
|
||||
initial='',
|
||||
widget=StaticSelect2(),
|
||||
)
|
||||
cluster = forms.ModelChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/virtualization/clusters/'
|
||||
)
|
||||
)
|
||||
role = forms.ModelChoiceField(
|
||||
queryset=DeviceRole.objects.filter(
|
||||
vm_role=True
|
||||
),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url="/api/dcim/device-roles/",
|
||||
additional_query_params={
|
||||
"vm_role": "true"
|
||||
}
|
||||
)
|
||||
)
|
||||
tenant = forms.ModelChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/tenancy/tenants/'
|
||||
)
|
||||
)
|
||||
platform = forms.ModelChoiceField(
|
||||
queryset=Platform.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
widget=APISelect(
|
||||
api_url='/api/dcim/platforms/'
|
||||
)
|
||||
)
|
||||
vcpus = forms.IntegerField(
|
||||
required=False,
|
||||
|
|
@ -464,59 +529,87 @@ class VirtualMachineFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||
cluster_group = FilterChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/virtualization/cluster-groups/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
cluster_type = FilterChoiceField(
|
||||
queryset=ClusterType.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/virtualization/cluster-types/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
cluster_id = FilterChoiceField(
|
||||
queryset=Cluster.objects.annotate(
|
||||
filter_count=Count('virtual_machines')
|
||||
),
|
||||
label='Cluster'
|
||||
queryset=Cluster.objects.all(),
|
||||
label='Cluster',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/virtualization/clusters/',
|
||||
)
|
||||
)
|
||||
region = FilterTreeNodeMultipleChoiceField(
|
||||
region = FilterChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
to_field_name='slug',
|
||||
required=False,
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/dcim/regions/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
site = FilterChoiceField(
|
||||
queryset=Site.objects.annotate(
|
||||
filter_count=Count('clusters__virtual_machines')
|
||||
),
|
||||
queryset=Site.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/dcim/sites/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
role = FilterChoiceField(
|
||||
queryset=DeviceRole.objects.filter(
|
||||
vm_role=True
|
||||
).annotate(
|
||||
filter_count=Count('virtual_machines')
|
||||
),
|
||||
queryset=DeviceRole.objects.filter(vm_role=True),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/dcim/device-roles/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
additional_query_params={
|
||||
'vm_role': 'true'
|
||||
}
|
||||
)
|
||||
)
|
||||
status = AnnotatedMultipleChoiceField(
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=VM_STATUS_CHOICES,
|
||||
annotate=VirtualMachine.objects.all(),
|
||||
annotate_field='status',
|
||||
required=False
|
||||
required=False,
|
||||
widget=StaticSelect2Multiple()
|
||||
)
|
||||
tenant = FilterChoiceField(
|
||||
queryset=Tenant.objects.annotate(
|
||||
filter_count=Count('virtual_machines')
|
||||
),
|
||||
queryset=Tenant.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/tenancy/tenants/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
platform = FilterChoiceField(
|
||||
queryset=Platform.objects.annotate(
|
||||
filter_count=Count('virtual_machines')
|
||||
),
|
||||
queryset=Platform.objects.all(),
|
||||
to_field_name='slug',
|
||||
null_label='-- None --'
|
||||
null_label='-- None --',
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/dcim/platforms/',
|
||||
value_field="slug",
|
||||
null_option=True,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -538,6 +631,7 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm):
|
|||
widgets = {
|
||||
'virtual_machine': forms.HiddenInput(),
|
||||
'form_factor': forms.HiddenInput(),
|
||||
'mode': StaticSelect2()
|
||||
}
|
||||
labels = {
|
||||
'mode': '802.1Q Mode',
|
||||
|
|
|
|||
Loading…
Reference in New Issue