mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
DCIM filter forms select2
This commit is contained in:
@ -15,11 +15,12 @@ from ipam.models import IPAddress, VLAN, VLANGroup
|
|||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
AnnotatedMultipleChoiceField, APISelect, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm,
|
AnnotatedMultipleChoiceField, APISelect, APISelectMultiple, add_blank_choice, ArrayFieldSelectMultiple,
|
||||||
BulkEditNullBooleanSelect, ChainedFieldsMixin, ChainedModelChoiceField, ColorSelect, CommentField, ComponentForm,
|
BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ChainedFieldsMixin, ChainedModelChoiceField,
|
||||||
ConfirmationForm, ContentTypeSelect, CSVChoiceField, ExpandableNameField, FilterChoiceField,
|
ColorSelect, CommentField, ComponentForm, ConfirmationForm, ContentTypeSelect, CSVChoiceField,
|
||||||
FilterTreeNodeMultipleChoiceField, FlexibleModelChoiceField, JSONField, Livesearch, SelectWithPK, SmallTextarea,
|
ExpandableNameField, FilterChoiceField, FilterTreeNodeMultipleChoiceField, FlexibleModelChoiceField,
|
||||||
SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES, COLOR_CHOICES,
|
JSONField, Livesearch, SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple,
|
||||||
|
BOOLEAN_WITH_BLANK_CHOICES, COLOR_CHOICES,
|
||||||
|
|
||||||
)
|
)
|
||||||
from virtualization.models import Cluster, ClusterGroup
|
from virtualization.models import Cluster, ClusterGroup
|
||||||
@ -218,15 +219,22 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(SITE_STATUS_CHOICES),
|
choices=add_blank_choice(SITE_STATUS_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial=''
|
initial='',
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
region = TreeNodeChoiceField(
|
region = TreeNodeChoiceField(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/regions/"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = forms.ModelChoiceField(
|
tenant = forms.ModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/tenancy/tenants",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
asn = forms.IntegerField(
|
asn = forms.IntegerField(
|
||||||
min_value=1,
|
min_value=1,
|
||||||
@ -240,7 +248,8 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|||||||
)
|
)
|
||||||
time_zone = TimeZoneFormField(
|
time_zone = TimeZoneFormField(
|
||||||
choices=add_blank_choice(TimeZoneFormField().choices),
|
choices=add_blank_choice(TimeZoneFormField().choices),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -259,18 +268,27 @@ class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
choices=SITE_STATUS_CHOICES,
|
choices=SITE_STATUS_CHOICES,
|
||||||
annotate=Site.objects.all(),
|
annotate=Site.objects.all(),
|
||||||
annotate_field='status',
|
annotate_field='status',
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2Multiple()
|
||||||
)
|
)
|
||||||
region = FilterTreeNodeMultipleChoiceField(
|
region = forms.ModelMultipleChoiceField(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
required=False,
|
required=False,
|
||||||
count_attr='site_count'
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/regions/",
|
||||||
|
value_field="slug",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = FilterChoiceField(
|
tenant = FilterChoiceField(
|
||||||
queryset=Tenant.objects.annotate(filter_count=Count('sites')),
|
queryset=Tenant.objects.annotate(filter_count=Count('sites')),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
null_label='-- None --'
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/tenancy/tenants/",
|
||||||
|
value_field="slug",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -317,7 +335,11 @@ class RackGroupFilterForm(BootstrapMixin, forms.Form):
|
|||||||
queryset=Site.objects.annotate(
|
queryset=Site.objects.annotate(
|
||||||
filter_count=Count('rack_groups')
|
filter_count=Count('rack_groups')
|
||||||
),
|
),
|
||||||
to_field_name='slug'
|
to_field_name='slug',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/sites/",
|
||||||
|
value_field="slug",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -494,24 +516,40 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|||||||
)
|
)
|
||||||
site = forms.ModelChoiceField(
|
site = forms.ModelChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/sites",
|
||||||
|
filter_for={
|
||||||
|
'group': 'site_id',
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
group = forms.ModelChoiceField(
|
group = forms.ModelChoiceField(
|
||||||
queryset=RackGroup.objects.all(),
|
queryset=RackGroup.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/rack-groups",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = forms.ModelChoiceField(
|
tenant = forms.ModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/tenancy/tenants",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(RACK_STATUS_CHOICES),
|
choices=add_blank_choice(RACK_STATUS_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial=''
|
initial='',
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
role = forms.ModelChoiceField(
|
role = forms.ModelChoiceField(
|
||||||
queryset=RackRole.objects.all(),
|
queryset=RackRole.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/rack-roles",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
serial = forms.CharField(
|
serial = forms.CharField(
|
||||||
max_length=50,
|
max_length=50,
|
||||||
@ -524,11 +562,13 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|||||||
)
|
)
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(RACK_TYPE_CHOICES),
|
choices=add_blank_choice(RACK_TYPE_CHOICES),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
width = forms.ChoiceField(
|
width = forms.ChoiceField(
|
||||||
choices=add_blank_choice(RACK_WIDTH_CHOICES),
|
choices=add_blank_choice(RACK_WIDTH_CHOICES),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
u_height = forms.IntegerField(
|
u_height = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -549,7 +589,8 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
|
|||||||
)
|
)
|
||||||
outer_unit = forms.ChoiceField(
|
outer_unit = forms.ChoiceField(
|
||||||
choices=add_blank_choice(RACK_DIMENSION_UNIT_CHOICES),
|
choices=add_blank_choice(RACK_DIMENSION_UNIT_CHOICES),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
comments = CommentField(
|
comments = CommentField(
|
||||||
widget=SmallTextarea
|
widget=SmallTextarea
|
||||||
@ -571,7 +612,11 @@ class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
queryset=Site.objects.annotate(
|
queryset=Site.objects.annotate(
|
||||||
filter_count=Count('racks')
|
filter_count=Count('racks')
|
||||||
),
|
),
|
||||||
to_field_name='slug'
|
to_field_name='slug',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/sites/",
|
||||||
|
value_field="slug",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
group_id = FilterChoiceField(
|
group_id = FilterChoiceField(
|
||||||
queryset=RackGroup.objects.select_related(
|
queryset=RackGroup.objects.select_related(
|
||||||
@ -580,27 +625,42 @@ class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
filter_count=Count('racks')
|
filter_count=Count('racks')
|
||||||
),
|
),
|
||||||
label='Rack group',
|
label='Rack group',
|
||||||
null_label='-- None --'
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/rack-groups/",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = FilterChoiceField(
|
tenant = FilterChoiceField(
|
||||||
queryset=Tenant.objects.annotate(
|
queryset=Tenant.objects.annotate(
|
||||||
filter_count=Count('racks')
|
filter_count=Count('racks')
|
||||||
),
|
),
|
||||||
to_field_name='slug',
|
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 = AnnotatedMultipleChoiceField(
|
||||||
choices=RACK_STATUS_CHOICES,
|
choices=RACK_STATUS_CHOICES,
|
||||||
annotate=Rack.objects.all(),
|
annotate=Rack.objects.all(),
|
||||||
annotate_field='status',
|
annotate_field='status',
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2Multiple()
|
||||||
)
|
)
|
||||||
role = FilterChoiceField(
|
role = FilterChoiceField(
|
||||||
queryset=RackRole.objects.annotate(
|
queryset=RackRole.objects.annotate(
|
||||||
filter_count=Count('racks')
|
filter_count=Count('racks')
|
||||||
),
|
),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
null_label='-- None --'
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/rack-roles/",
|
||||||
|
value_field="slug",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -620,7 +680,8 @@ class RackReservationForm(BootstrapMixin, TenancyForm, forms.ModelForm):
|
|||||||
user = forms.ModelChoiceField(
|
user = forms.ModelChoiceField(
|
||||||
queryset=User.objects.order_by(
|
queryset=User.objects.order_by(
|
||||||
'username'
|
'username'
|
||||||
)
|
),
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -655,7 +716,11 @@ class RackReservationFilterForm(BootstrapMixin, forms.Form):
|
|||||||
queryset=Site.objects.annotate(
|
queryset=Site.objects.annotate(
|
||||||
filter_count=Count('racks__reservations')
|
filter_count=Count('racks__reservations')
|
||||||
),
|
),
|
||||||
to_field_name='slug'
|
to_field_name='slug',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/sites/",
|
||||||
|
value_field="slug",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
group_id = FilterChoiceField(
|
group_id = FilterChoiceField(
|
||||||
queryset=RackGroup.objects.select_related(
|
queryset=RackGroup.objects.select_related(
|
||||||
@ -664,14 +729,23 @@ class RackReservationFilterForm(BootstrapMixin, forms.Form):
|
|||||||
filter_count=Count('racks__reservations')
|
filter_count=Count('racks__reservations')
|
||||||
),
|
),
|
||||||
label='Rack group',
|
label='Rack group',
|
||||||
null_label='-- None --'
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/rack-groups/",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = FilterChoiceField(
|
tenant = FilterChoiceField(
|
||||||
queryset=Tenant.objects.annotate(
|
queryset=Tenant.objects.annotate(
|
||||||
filter_count=Count('rackreservations')
|
filter_count=Count('rackreservations')
|
||||||
),
|
),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
null_label='-- None --'
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/tenancy/tenants/",
|
||||||
|
value_field="slug",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -684,11 +758,15 @@ class RackReservationBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
queryset=User.objects.order_by(
|
queryset=User.objects.order_by(
|
||||||
'username'
|
'username'
|
||||||
),
|
),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
tenant = forms.ModelChoiceField(
|
tenant = forms.ModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/tenancy/tenant",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
description = forms.CharField(
|
description = forms.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
@ -782,7 +860,10 @@ class DeviceTypeBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkE
|
|||||||
)
|
)
|
||||||
manufacturer = forms.ModelChoiceField(
|
manufacturer = forms.ModelChoiceField(
|
||||||
queryset=Manufacturer.objects.all(),
|
queryset=Manufacturer.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/manufactureres"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
u_height = forms.IntegerField(
|
u_height = forms.IntegerField(
|
||||||
min_value=1,
|
min_value=1,
|
||||||
@ -808,54 +889,58 @@ class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
queryset=Manufacturer.objects.annotate(
|
queryset=Manufacturer.objects.annotate(
|
||||||
filter_count=Count('device_types')
|
filter_count=Count('device_types')
|
||||||
),
|
),
|
||||||
to_field_name='slug'
|
to_field_name='slug',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/manufacturers/",
|
||||||
|
value_field="slug",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
subdevice_role = forms.NullBooleanField(
|
subdevice_role = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Subdevice role',
|
label='Subdevice role',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=add_blank_choice(SUBDEVICE_ROLE_CHOICES)
|
choices=add_blank_choice(SUBDEVICE_ROLE_CHOICES)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
console_ports = forms.NullBooleanField(
|
console_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has console ports',
|
label='Has console ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
console_server_ports = forms.NullBooleanField(
|
console_server_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has console server ports',
|
label='Has console server ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
power_ports = forms.NullBooleanField(
|
power_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has power ports',
|
label='Has power ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
power_outlets = forms.NullBooleanField(
|
power_outlets = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has power outlets',
|
label='Has power outlets',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
interfaces = forms.NullBooleanField(
|
interfaces = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has interfaces',
|
label='Has interfaces',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
pass_through_ports = forms.NullBooleanField(
|
pass_through_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has pass-through ports',
|
label='Has pass-through ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -971,7 +1056,8 @@ class InterfaceTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
)
|
)
|
||||||
form_factor = forms.ChoiceField(
|
form_factor = forms.ChoiceField(
|
||||||
choices=add_blank_choice(IFACE_FF_CHOICES),
|
choices=add_blank_choice(IFACE_FF_CHOICES),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
mgmt_only = forms.NullBooleanField(
|
mgmt_only = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -1001,7 +1087,8 @@ class FrontPortTemplateCreateForm(ComponentForm):
|
|||||||
label='Name'
|
label='Name'
|
||||||
)
|
)
|
||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=PORT_TYPE_CHOICES
|
choices=PORT_TYPE_CHOICES,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
rear_port_set = forms.MultipleChoiceField(
|
rear_port_set = forms.MultipleChoiceField(
|
||||||
choices=[],
|
choices=[],
|
||||||
@ -1539,25 +1626,38 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
|
|||||||
device_type = forms.ModelChoiceField(
|
device_type = forms.ModelChoiceField(
|
||||||
queryset=DeviceType.objects.all(),
|
queryset=DeviceType.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label='Type'
|
label='Type',
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/device-types"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
device_role = forms.ModelChoiceField(
|
device_role = forms.ModelChoiceField(
|
||||||
queryset=DeviceRole.objects.all(),
|
queryset=DeviceRole.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label='Role'
|
label='Role',
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/device-roles"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = forms.ModelChoiceField(
|
tenant = forms.ModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/tenancy/tenants"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
platform = forms.ModelChoiceField(
|
platform = forms.ModelChoiceField(
|
||||||
queryset=Platform.objects.all(),
|
queryset=Platform.objects.all(),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=APISelect(
|
||||||
|
api_url="/api/dcim/platforms"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(DEVICE_STATUS_CHOICES),
|
choices=add_blank_choice(DEVICE_STATUS_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial=''
|
initial='',
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
serial = forms.CharField(
|
serial = forms.CharField(
|
||||||
max_length=50,
|
max_length=50,
|
||||||
@ -1577,16 +1677,31 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label='Search'
|
label='Search'
|
||||||
)
|
)
|
||||||
region = FilterTreeNodeMultipleChoiceField(
|
region = FilterChoiceField(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
required=False,
|
required=False,
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/regions/",
|
||||||
|
value_field="slug",
|
||||||
|
filter_for={
|
||||||
|
'site': 'region'
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
site = FilterChoiceField(
|
site = FilterChoiceField(
|
||||||
queryset=Site.objects.annotate(
|
queryset=Site.objects.annotate(
|
||||||
filter_count=Count('devices')
|
filter_count=Count('devices')
|
||||||
),
|
),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/sites/",
|
||||||
|
value_field="slug",
|
||||||
|
filter_for={
|
||||||
|
'rack_group_id': 'site',
|
||||||
|
'rack_id': 'site',
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
rack_group_id = FilterChoiceField(
|
rack_group_id = FilterChoiceField(
|
||||||
queryset=RackGroup.objects.select_related(
|
queryset=RackGroup.objects.select_related(
|
||||||
@ -1595,6 +1710,12 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
filter_count=Count('racks__devices')
|
filter_count=Count('racks__devices')
|
||||||
),
|
),
|
||||||
label='Rack group',
|
label='Rack group',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/rack-groups/",
|
||||||
|
filter_for={
|
||||||
|
'rack_id': 'rack_group_id',
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
rack_id = FilterChoiceField(
|
rack_id = FilterChoiceField(
|
||||||
queryset=Rack.objects.annotate(
|
queryset=Rack.objects.annotate(
|
||||||
@ -1602,12 +1723,21 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
),
|
),
|
||||||
label='Rack',
|
label='Rack',
|
||||||
null_label='-- None --',
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/racks/",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
role = FilterChoiceField(
|
role = FilterChoiceField(
|
||||||
queryset=DeviceRole.objects.annotate(
|
queryset=DeviceRole.objects.annotate(
|
||||||
filter_count=Count('devices')
|
filter_count=Count('devices')
|
||||||
),
|
),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/device-roles/",
|
||||||
|
value_field="slug",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
tenant = FilterChoiceField(
|
tenant = FilterChoiceField(
|
||||||
queryset=Tenant.objects.annotate(
|
queryset=Tenant.objects.annotate(
|
||||||
@ -1615,10 +1745,21 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
),
|
),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
null_label='-- None --',
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/tenancy/tenants/",
|
||||||
|
value_field="slug",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
manufacturer_id = FilterChoiceField(
|
manufacturer_id = FilterChoiceField(
|
||||||
queryset=Manufacturer.objects.all(),
|
queryset=Manufacturer.objects.all(),
|
||||||
label='Manufacturer'
|
label='Manufacturer',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/manufacturers/",
|
||||||
|
filter_for={
|
||||||
|
'device_type_id': 'manufacturer_id',
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
device_type_id = FilterChoiceField(
|
device_type_id = FilterChoiceField(
|
||||||
queryset=DeviceType.objects.select_related(
|
queryset=DeviceType.objects.select_related(
|
||||||
@ -1629,6 +1770,10 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
filter_count=Count('instances'),
|
filter_count=Count('instances'),
|
||||||
),
|
),
|
||||||
label='Model',
|
label='Model',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/device-types/",
|
||||||
|
display_field="model",
|
||||||
|
)
|
||||||
)
|
)
|
||||||
platform = FilterChoiceField(
|
platform = FilterChoiceField(
|
||||||
queryset=Platform.objects.annotate(
|
queryset=Platform.objects.annotate(
|
||||||
@ -1636,12 +1781,18 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
),
|
),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
null_label='-- None --',
|
null_label='-- None --',
|
||||||
|
widget=APISelectMultiple(
|
||||||
|
api_url="/api/dcim/platforms/",
|
||||||
|
value_field="slug",
|
||||||
|
null_option=True,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
status = AnnotatedMultipleChoiceField(
|
status = AnnotatedMultipleChoiceField(
|
||||||
choices=DEVICE_STATUS_CHOICES,
|
choices=DEVICE_STATUS_CHOICES,
|
||||||
annotate=Device.objects.all(),
|
annotate=Device.objects.all(),
|
||||||
annotate_field='status',
|
annotate_field='status',
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2Multiple()
|
||||||
)
|
)
|
||||||
mac_address = forms.CharField(
|
mac_address = forms.CharField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -1650,49 +1801,49 @@ class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
|||||||
has_primary_ip = forms.NullBooleanField(
|
has_primary_ip = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has a primary IP',
|
label='Has a primary IP',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
console_ports = forms.NullBooleanField(
|
console_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has console ports',
|
label='Has console ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
console_server_ports = forms.NullBooleanField(
|
console_server_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has console server ports',
|
label='Has console server ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
power_ports = forms.NullBooleanField(
|
power_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has power ports',
|
label='Has power ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
power_outlets = forms.NullBooleanField(
|
power_outlets = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has power outlets',
|
label='Has power outlets',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
interfaces = forms.NullBooleanField(
|
interfaces = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has interfaces',
|
label='Has interfaces',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
pass_through_ports = forms.NullBooleanField(
|
pass_through_ports = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has pass-through ports',
|
label='Has pass-through ports',
|
||||||
widget=forms.Select(
|
widget=StaticSelect2(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -1714,7 +1865,8 @@ class DeviceBulkAddComponentForm(BootstrapMixin, forms.Form):
|
|||||||
|
|
||||||
class DeviceBulkAddInterfaceForm(DeviceBulkAddComponentForm):
|
class DeviceBulkAddInterfaceForm(DeviceBulkAddComponentForm):
|
||||||
form_factor = forms.ChoiceField(
|
form_factor = forms.ChoiceField(
|
||||||
choices=IFACE_FF_CHOICES
|
choices=IFACE_FF_CHOICES,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
enabled = forms.BooleanField(
|
enabled = forms.BooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -1941,7 +2093,7 @@ class InterfaceAssignVLANsForm(BootstrapMixin, forms.ModelForm):
|
|||||||
vlans = forms.MultipleChoiceField(
|
vlans = forms.MultipleChoiceField(
|
||||||
choices=[],
|
choices=[],
|
||||||
label='VLANs',
|
label='VLANs',
|
||||||
widget=forms.SelectMultiple(
|
widget=StaticSelect2Multiple(
|
||||||
attrs={
|
attrs={
|
||||||
'size': 20,
|
'size': 20,
|
||||||
}
|
}
|
||||||
@ -2093,7 +2245,8 @@ class InterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
|
|||||||
)
|
)
|
||||||
form_factor = forms.ChoiceField(
|
form_factor = forms.ChoiceField(
|
||||||
choices=add_blank_choice(IFACE_FF_CHOICES),
|
choices=add_blank_choice(IFACE_FF_CHOICES),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
enabled = forms.NullBooleanField(
|
enabled = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -2102,7 +2255,8 @@ class InterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
|
|||||||
lag = forms.ModelChoiceField(
|
lag = forms.ModelChoiceField(
|
||||||
queryset=Interface.objects.all(),
|
queryset=Interface.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label='Parent LAG'
|
label='Parent LAG',
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
mtu = forms.IntegerField(
|
mtu = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
@ -2121,7 +2275,8 @@ class InterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
|
|||||||
)
|
)
|
||||||
mode = forms.ChoiceField(
|
mode = forms.ChoiceField(
|
||||||
choices=add_blank_choice(IFACE_MODE_CHOICES),
|
choices=add_blank_choice(IFACE_MODE_CHOICES),
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -2199,7 +2354,7 @@ class FrontPortCreateForm(ComponentForm):
|
|||||||
rear_port_set = forms.MultipleChoiceField(
|
rear_port_set = forms.MultipleChoiceField(
|
||||||
choices=[],
|
choices=[],
|
||||||
label='Rear ports',
|
label='Rear ports',
|
||||||
help_text='Select one rear port assignment for each front port being created.'
|
help_text='Select one rear port assignment for each front port being created.',
|
||||||
)
|
)
|
||||||
description = forms.CharField(
|
description = forms.CharField(
|
||||||
required=False
|
required=False
|
||||||
@ -2546,7 +2701,8 @@ class CableBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
type = forms.ChoiceField(
|
type = forms.ChoiceField(
|
||||||
choices=add_blank_choice(CABLE_TYPE_CHOICES),
|
choices=add_blank_choice(CABLE_TYPE_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial=''
|
initial='',
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
status = forms.ChoiceField(
|
status = forms.ChoiceField(
|
||||||
choices=add_blank_choice(CONNECTION_STATUS_CHOICES),
|
choices=add_blank_choice(CONNECTION_STATUS_CHOICES),
|
||||||
@ -2555,7 +2711,8 @@ class CableBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
)
|
)
|
||||||
label = forms.CharField(
|
label = forms.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
required=False
|
required=False,
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
color = forms.CharField(
|
color = forms.CharField(
|
||||||
max_length=6,
|
max_length=6,
|
||||||
@ -2569,7 +2726,8 @@ class CableBulkEditForm(BootstrapMixin, BulkEditForm):
|
|||||||
length_unit = forms.ChoiceField(
|
length_unit = forms.ChoiceField(
|
||||||
choices=add_blank_choice(CABLE_LENGTH_UNIT_CHOICES),
|
choices=add_blank_choice(CABLE_LENGTH_UNIT_CHOICES),
|
||||||
required=False,
|
required=False,
|
||||||
initial=''
|
initial='',
|
||||||
|
widget=StaticSelect2()
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -2594,17 +2752,15 @@ class CableFilterForm(BootstrapMixin, forms.Form):
|
|||||||
required=False,
|
required=False,
|
||||||
label='Search'
|
label='Search'
|
||||||
)
|
)
|
||||||
type = AnnotatedMultipleChoiceField(
|
type = forms.MultipleChoiceField(
|
||||||
choices=CABLE_TYPE_CHOICES,
|
choices=CABLE_TYPE_CHOICES,
|
||||||
annotate=Cable.objects.all(),
|
required=False,
|
||||||
annotate_field='type',
|
widget=StaticSelect2()
|
||||||
required=False
|
|
||||||
)
|
)
|
||||||
color = AnnotatedMultipleChoiceField(
|
color = forms.CharField(
|
||||||
choices=COLOR_CHOICES,
|
max_length=6,
|
||||||
annotate=Cable.objects.all(),
|
required=False,
|
||||||
annotate_field='color',
|
widget=ColorSelect()
|
||||||
required=False
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ $(document).ready(function() {
|
|||||||
form.submit();
|
form.submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Parse URLs which may contain variable refrences to other field values
|
||||||
function parseURL(url) {
|
function parseURL(url) {
|
||||||
var filter_regex = /\{\{([a-z_]+)\}\}/g;
|
var filter_regex = /\{\{([a-z_]+)\}\}/g;
|
||||||
var match;
|
var match;
|
||||||
@ -86,8 +87,8 @@ $(document).ready(function() {
|
|||||||
return rendered_url
|
return rendered_url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assign color picker selection classes
|
||||||
function colorPickerClassCopy(data, container) {
|
function colorPickerClassCopy(data, container) {
|
||||||
console.log("hello");
|
|
||||||
if (data.element) {
|
if (data.element) {
|
||||||
$(container).addClass($(data.element).attr("class"));
|
$(container).addClass($(data.element).attr("class"));
|
||||||
}
|
}
|
||||||
@ -108,23 +109,27 @@ $(document).ready(function() {
|
|||||||
placeholder: "---------",
|
placeholder: "---------",
|
||||||
})
|
})
|
||||||
|
|
||||||
// API backed single selection
|
// API backed selection
|
||||||
// Includes live search and chained fields
|
// Includes live search and chained fields
|
||||||
|
// The `multiple` setting may be controled via a data-* attribute
|
||||||
$('.netbox-select2-api').select2({
|
$('.netbox-select2-api').select2({
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
placeholder: "---------",
|
placeholder: "---------",
|
||||||
|
|
||||||
ajax: {
|
ajax: {
|
||||||
delay: 500,
|
delay: 500,
|
||||||
|
|
||||||
url: function(params) {
|
url: function(params) {
|
||||||
var element = this[0];
|
var element = this[0];
|
||||||
var url = element.getAttribute("data-url");
|
var url = parseURL(element.getAttribute("data-url"));
|
||||||
url = parseURL(url);
|
|
||||||
if (url.includes("{{")) {
|
if (url.includes("{{")) {
|
||||||
// URL is not furry rendered yet, abort the request
|
// URL is not fully rendered yet, abort the request
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
},
|
},
|
||||||
|
|
||||||
data: function(params) {
|
data: function(params) {
|
||||||
var element = this[0];
|
var element = this[0];
|
||||||
// Paging
|
// Paging
|
||||||
@ -136,29 +141,35 @@ $(document).ready(function() {
|
|||||||
limit: 50,
|
limit: 50,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
// filter-for fields from a chain
|
// filter-for fields from a chain
|
||||||
var attr_name = "data-filter-for-" + $(element).attr("name");
|
var attr_name = "data-filter-for-" + $(element).attr("name");
|
||||||
var form = $(element).closest('form');
|
var form = $(element).closest('form');
|
||||||
var filter_for_elements = form.find("select[" + attr_name + "]");
|
var filter_for_elements = form.find("select[" + attr_name + "]");
|
||||||
|
|
||||||
filter_for_elements.each(function(index, filter_for_element) {
|
filter_for_elements.each(function(index, filter_for_element) {
|
||||||
var param_name = $(filter_for_element).attr(attr_name);
|
var param_name = $(filter_for_element).attr(attr_name);
|
||||||
var value = $(filter_for_element).val();
|
var value = $(filter_for_element).val();
|
||||||
|
|
||||||
if (param_name && value) {
|
if (param_name && value) {
|
||||||
parameters[param_name] = $(filter_for_element).val();
|
parameters[param_name] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Conditional query params
|
// Conditional query params
|
||||||
$.each(element.attributes, function(index, attr){
|
$.each(element.attributes, function(index, attr){
|
||||||
if (attr.name.includes("data-conditional-query-param-")){
|
if (attr.name.includes("data-conditional-query-param-")){
|
||||||
var conditional = attr.name.split("data-conditional-query-param-")[1].split("__");
|
var conditional = attr.name.split("data-conditional-query-param-")[1].split("__");
|
||||||
var field = $("#id_" + conditional[0]);
|
var field = $("#id_" + conditional[0]);
|
||||||
var field_value = conditional[1];
|
var field_value = conditional[1];
|
||||||
|
|
||||||
if ($('option:selected', field).attr('api-value') === field_value){
|
if ($('option:selected', field).attr('api-value') === field_value){
|
||||||
var _val = attr.value.split("=");
|
var _val = attr.value.split("=");
|
||||||
parameters[_val[0]] = _val[1];
|
parameters[_val[0]] = _val[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Additional query params
|
// Additional query params
|
||||||
$.each(element.attributes, function(index, attr){
|
$.each(element.attributes, function(index, attr){
|
||||||
if (attr.name.includes("data-additional-query-param-")){
|
if (attr.name.includes("data-additional-query-param-")){
|
||||||
@ -166,14 +177,28 @@ $(document).ready(function() {
|
|||||||
parameters[param_name] = attr.value;
|
parameters[param_name] = attr.value;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return parameters;
|
|
||||||
|
// This will handle params with multiple values (i.e. for list filter forms)
|
||||||
|
return $.param(parameters, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
processResults: function (data) {
|
processResults: function (data) {
|
||||||
var element = this.$element[0];
|
var element = this.$element[0];
|
||||||
var results = $.map(data.results, function (obj) {
|
var results = $.map(data.results, function (obj) {
|
||||||
obj.text = obj.name || obj[element.getAttribute('display-field')];
|
obj.text = obj[element.getAttribute('display-field')] || obj.name;
|
||||||
|
obj.id = obj[element.getAttribute('value-field')] || obj.id;
|
||||||
return obj;
|
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
|
// Check if there are more results to page
|
||||||
var page = data.next !== null;
|
var page = data.next !== null;
|
||||||
return {
|
return {
|
||||||
@ -208,9 +233,11 @@ $(document).ready(function() {
|
|||||||
multiple: true,
|
multiple: true,
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
placeholder: "Tags",
|
placeholder: "Tags",
|
||||||
|
|
||||||
ajax: {
|
ajax: {
|
||||||
delay: 250,
|
delay: 250,
|
||||||
url: "/api/extras/tags/",
|
url: "/api/extras/tags/",
|
||||||
|
|
||||||
data: function(params) {
|
data: function(params) {
|
||||||
// paging
|
// paging
|
||||||
var offset = params.page * 50 || 0;
|
var offset = params.page * 50 || 0;
|
||||||
@ -222,6 +249,7 @@ $(document).ready(function() {
|
|||||||
};
|
};
|
||||||
return parameters;
|
return parameters;
|
||||||
},
|
},
|
||||||
|
|
||||||
processResults: function (data) {
|
processResults: function (data) {
|
||||||
var results = $.map(data.results, function (obj) {
|
var results = $.map(data.results, function (obj) {
|
||||||
return {
|
return {
|
||||||
@ -229,6 +257,7 @@ $(document).ready(function() {
|
|||||||
text: obj.name
|
text: obj.name
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if there are more results to page
|
// Check if there are more results to page
|
||||||
var page = data.next !== null;
|
var page = data.next !== null;
|
||||||
return {
|
return {
|
||||||
|
@ -20,88 +20,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% 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>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block javascript %}
|
|
||||||
{% include 'dcim/inc/filter_rack_group.html' %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
|
@ -186,6 +186,7 @@ class BulkEditNullBooleanSelect(forms.NullBooleanSelect):
|
|||||||
('2', 'Yes'),
|
('2', 'Yes'),
|
||||||
('3', 'No'),
|
('3', 'No'),
|
||||||
)
|
)
|
||||||
|
self.attrs['class'] = 'netbox-select2-static'
|
||||||
|
|
||||||
|
|
||||||
class SelectWithDisabled(forms.Select):
|
class SelectWithDisabled(forms.Select):
|
||||||
@ -223,6 +224,14 @@ class StaticSelect2(SelectWithDisabled):
|
|||||||
self.attrs['data-filter-for-{}'.format(name)] = value
|
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):
|
class SelectWithPK(StaticSelect2):
|
||||||
"""
|
"""
|
||||||
Include the primary key of each option in the option label (e.g. "Router7 (4721)").
|
Include the primary key of each option in the option label (e.g. "Router7 (4721)").
|
||||||
@ -265,6 +274,7 @@ class APISelect(SelectWithDisabled):
|
|||||||
|
|
||||||
:param api_url: API URL
|
:param api_url: API URL
|
||||||
:param display_field: (Optional) Field to display for child in selection list. Defaults to `name`.
|
: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 disabled_indicator: (Optional) Mark option as disabled if this field equates true.
|
||||||
:param filter_for: (Optional) A dict of chained form fields for which this field is a filter. The key is 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.
|
name of the filter-for field (child field) and the value is the name of the query param filter.
|
||||||
@ -273,18 +283,21 @@ class APISelect(SelectWithDisabled):
|
|||||||
If the provided field value is selected for the given field, the URL query param will be appended to
|
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
|
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.
|
a particular field value dictates an additional API filter.
|
||||||
:param additional_query_params: A dict of query params to append to the API request. The key is the name
|
:param additional_query_params: Optional) A dict of query params to append to the API request. The key is the
|
||||||
of the query param and the value if the query param's value.
|
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__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
api_url,
|
api_url,
|
||||||
display_field=None,
|
display_field=None,
|
||||||
|
value_field=None,
|
||||||
disabled_indicator=None,
|
disabled_indicator=None,
|
||||||
filter_for=None,
|
filter_for=None,
|
||||||
conditional_query_params=None,
|
conditional_query_params=None,
|
||||||
additional_query_params=None,
|
additional_query_params=None,
|
||||||
|
null_option=False,
|
||||||
*args,
|
*args,
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
@ -295,6 +308,8 @@ class APISelect(SelectWithDisabled):
|
|||||||
self.attrs['data-url'] = '/{}{}'.format(settings.BASE_PATH, api_url.lstrip('/')) # Inject BASE_PATH
|
self.attrs['data-url'] = '/{}{}'.format(settings.BASE_PATH, api_url.lstrip('/')) # Inject BASE_PATH
|
||||||
if display_field:
|
if display_field:
|
||||||
self.attrs['display-field'] = display_field
|
self.attrs['display-field'] = display_field
|
||||||
|
if value_field:
|
||||||
|
self.attrs['value-field'] = value_field
|
||||||
if disabled_indicator:
|
if disabled_indicator:
|
||||||
self.attrs['disabled-indicator'] = disabled_indicator
|
self.attrs['disabled-indicator'] = disabled_indicator
|
||||||
if filter_for:
|
if filter_for:
|
||||||
@ -306,6 +321,8 @@ class APISelect(SelectWithDisabled):
|
|||||||
if additional_query_params:
|
if additional_query_params:
|
||||||
for key, value in additional_query_params.items():
|
for key, value in additional_query_params.items():
|
||||||
self.add_additional_query_param(key, value)
|
self.add_additional_query_param(key, value)
|
||||||
|
if null_option:
|
||||||
|
self.attrs['data-null-option'] = 1
|
||||||
|
|
||||||
def add_filter_for(self, name, value):
|
def add_filter_for(self, name, value):
|
||||||
"""
|
"""
|
||||||
@ -336,8 +353,12 @@ class APISelect(SelectWithDisabled):
|
|||||||
self.attrs['data-conditional-query-param-{}'.format(condition)] = value
|
self.attrs['data-conditional-query-param-{}'.format(condition)] = value
|
||||||
|
|
||||||
|
|
||||||
class APISelectMultiple(APISelect):
|
class APISelectMultiple(APISelect, forms.SelectMultiple):
|
||||||
allow_multiple_selected = True
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.attrs['data-multiple'] = 1
|
||||||
|
|
||||||
|
|
||||||
class Livesearch(forms.TextInput):
|
class Livesearch(forms.TextInput):
|
||||||
|
Reference in New Issue
Block a user