mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 03:27:21 -06:00
Deprecate collapsible advanced search and re-implement field-based filtering on object views
This commit is contained in:
parent
0b09365d0d
commit
863048cda2
@ -113,7 +113,8 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -121,7 +122,8 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
asn = forms.IntegerField(
|
||||
required=False,
|
||||
@ -198,7 +200,8 @@ class ProviderNetworkFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
provider_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Provider.objects.all(),
|
||||
required=False,
|
||||
label=_('Provider')
|
||||
label=_('Provider'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -368,12 +371,14 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=CircuitType.objects.all(),
|
||||
required=False,
|
||||
label=_('Type')
|
||||
label=_('Type'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
provider_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Provider.objects.all(),
|
||||
required=False,
|
||||
label=_('Provider')
|
||||
label=_('Provider'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
provider_network_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ProviderNetwork.objects.all(),
|
||||
@ -381,7 +386,8 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
query_params={
|
||||
'provider_id': '$provider_id'
|
||||
},
|
||||
label=_('Provider network')
|
||||
label=_('Provider network'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=CircuitStatusChoices,
|
||||
@ -391,7 +397,8 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -399,7 +406,8 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
commit_rate = forms.IntegerField(
|
||||
required=False,
|
||||
|
@ -71,12 +71,14 @@ class DeviceComponentFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -84,7 +86,8 @@ class DeviceComponentFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
device_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
@ -92,7 +95,8 @@ class DeviceComponentFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Device')
|
||||
label=_('Device'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -457,17 +461,19 @@ class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=SiteStatusChoices,
|
||||
required=False,
|
||||
widget=StaticSelectMultiple()
|
||||
widget=StaticSelectMultiple(),
|
||||
)
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Group')
|
||||
label=_('Group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -565,7 +571,8 @@ class LocationFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -573,7 +580,8 @@ class LocationFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
parent_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Location.objects.all(),
|
||||
@ -582,7 +590,8 @@ class LocationFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
'region_id': '$region_id',
|
||||
'site_id': '$site_id',
|
||||
},
|
||||
label=_('Parent')
|
||||
label=_('Parent'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -862,7 +871,8 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -870,7 +880,8 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
location_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Location.objects.all(),
|
||||
@ -879,7 +890,8 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Location')
|
||||
label=_('Location'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=RackStatusChoices,
|
||||
@ -900,7 +912,8 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
queryset=RackRole.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Role')
|
||||
label=_('Role'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
asset_tag = forms.CharField(
|
||||
required=False
|
||||
@ -923,7 +936,8 @@ class RackElevationFilterForm(RackFilterForm):
|
||||
query_params={
|
||||
'site_id': '$site_id',
|
||||
'location_id': '$location_id',
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -937,14 +951,16 @@ class RackReservationForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
required=False,
|
||||
initial_params={
|
||||
'sites': '$site'
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group = DynamicModelChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
initial_params={
|
||||
'sites': '$site'
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site = DynamicModelChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -952,21 +968,24 @@ class RackReservationForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
query_params={
|
||||
'region_id': '$region',
|
||||
'group_id': '$site_group',
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
location = DynamicModelChoiceField(
|
||||
queryset=Location.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'site_id': '$site'
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
rack = DynamicModelChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
query_params={
|
||||
'site_id': '$site',
|
||||
'location_id': '$location',
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
units = NumericArrayField(
|
||||
base_field=forms.IntegerField(),
|
||||
@ -980,7 +999,8 @@ class RackReservationForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
)
|
||||
tags = DynamicModelMultipleChoiceField(
|
||||
queryset=Tag.objects.all(),
|
||||
required=False
|
||||
required=False,
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
@ -1080,7 +1100,8 @@ class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMo
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -1088,13 +1109,15 @@ class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMo
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
location_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Location.objects.prefetch_related('site'),
|
||||
required=False,
|
||||
label=_('Location'),
|
||||
null_option='None'
|
||||
null_option='None',
|
||||
fetch_trigger='open'
|
||||
)
|
||||
user_id = DynamicModelMultipleChoiceField(
|
||||
queryset=User.objects.all(),
|
||||
@ -1102,7 +1125,8 @@ class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMo
|
||||
label=_('User'),
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/users/users/',
|
||||
)
|
||||
),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -1231,7 +1255,8 @@ class DeviceTypeFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label=_('Manufacturer')
|
||||
label=_('Manufacturer'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
subdevice_role = forms.MultipleChoiceField(
|
||||
choices=add_blank_choice(SubdeviceRoleChoices),
|
||||
@ -2036,7 +2061,8 @@ class PlatformFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label=_('Manufacturer')
|
||||
label=_('Manufacturer'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -2452,7 +2478,8 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -2460,7 +2487,8 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
location_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Location.objects.all(),
|
||||
@ -2469,7 +2497,8 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Location')
|
||||
label=_('Location'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
rack_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
@ -2479,17 +2508,20 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
|
||||
'site_id': '$site_id',
|
||||
'location_id': '$location_id',
|
||||
},
|
||||
label=_('Rack')
|
||||
label=_('Rack'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
role_id = DynamicModelMultipleChoiceField(
|
||||
queryset=DeviceRole.objects.all(),
|
||||
required=False,
|
||||
label=_('Role')
|
||||
label=_('Role'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label=_('Manufacturer')
|
||||
label=_('Manufacturer'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
device_type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=DeviceType.objects.all(),
|
||||
@ -2497,13 +2529,15 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
|
||||
query_params={
|
||||
'manufacturer_id': '$manufacturer_id'
|
||||
},
|
||||
label=_('Model')
|
||||
label=_('Model'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
platform_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Platform.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Platform')
|
||||
label=_('Platform'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=DeviceStatusChoices,
|
||||
@ -3987,7 +4021,8 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
|
||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False,
|
||||
label=_('Manufacturer')
|
||||
label=_('Manufacturer'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
serial = forms.CharField(
|
||||
required=False
|
||||
@ -4461,7 +4496,8 @@ class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -4469,12 +4505,14 @@ class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tenant_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False,
|
||||
label=_('Tenant')
|
||||
label=_('Tenant'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
rack_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
@ -4483,7 +4521,8 @@ class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
null_option='None',
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
}
|
||||
},
|
||||
fetch_trigger='open'
|
||||
)
|
||||
type = forms.MultipleChoiceField(
|
||||
choices=add_blank_choice(CableTypeChoices),
|
||||
@ -4506,7 +4545,8 @@ class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
'tenant_id': '$tenant_id',
|
||||
'rack_id': '$rack_id',
|
||||
},
|
||||
label=_('Device')
|
||||
label=_('Device'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -4519,7 +4559,8 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -4527,7 +4568,8 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
device_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
@ -4535,7 +4577,8 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Device')
|
||||
label=_('Device'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -4543,7 +4586,8 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -4551,7 +4595,8 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
device_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
@ -4559,7 +4604,8 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Device')
|
||||
label=_('Device'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -4567,7 +4613,8 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -4575,7 +4622,8 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
device_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Device.objects.all(),
|
||||
@ -4583,7 +4631,8 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Device')
|
||||
label=_('Device'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -4837,12 +4886,14 @@ class VirtualChassisFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -4850,7 +4901,8 @@ class VirtualChassisFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -4973,12 +5025,14 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -4986,7 +5040,8 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
location_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Location.objects.all(),
|
||||
@ -4995,7 +5050,8 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Location')
|
||||
label=_('Location'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -5213,12 +5269,14 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -5226,7 +5284,8 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
power_panel_id = DynamicModelMultipleChoiceField(
|
||||
queryset=PowerPanel.objects.all(),
|
||||
@ -5235,7 +5294,8 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Power panel')
|
||||
label=_('Power panel'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
rack_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
@ -5244,7 +5304,8 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
query_params={
|
||||
'site_id': '$site_id'
|
||||
},
|
||||
label=_('Rack')
|
||||
label=_('Rack'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=PowerFeedStatusChoices,
|
||||
|
@ -676,58 +676,69 @@ class ConfigContextFilterForm(BootstrapMixin, forms.Form):
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Regions')
|
||||
label=_('Regions'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site groups')
|
||||
label=_('Site groups'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
label=_('Sites')
|
||||
label=_('Sites'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
device_type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=DeviceType.objects.all(),
|
||||
required=False,
|
||||
label=_('Device types')
|
||||
label=_('Device types'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
role_id = DynamicModelMultipleChoiceField(
|
||||
queryset=DeviceRole.objects.all(),
|
||||
required=False,
|
||||
label=_('Roles')
|
||||
label=_('Roles'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
platform_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Platform.objects.all(),
|
||||
required=False,
|
||||
label=_('Platforms')
|
||||
label=_('Platforms'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
cluster_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Cluster groups')
|
||||
label=_('Cluster groups'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
cluster_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
required=False,
|
||||
label=_('Clusters')
|
||||
label=_('Clusters'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tenant_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Tenant groups')
|
||||
label=_('Tenant groups'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tenant_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
required=False,
|
||||
label=_('Tenant')
|
||||
label=_('Tenant'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = DynamicModelMultipleChoiceField(
|
||||
queryset=Tag.objects.all(),
|
||||
to_field_name='slug',
|
||||
required=False,
|
||||
label=_('Tags')
|
||||
label=_('Tags'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -820,7 +831,8 @@ class JournalEntryFilterForm(BootstrapMixin, forms.Form):
|
||||
label=_('User'),
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/users/users/',
|
||||
)
|
||||
),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
assigned_object_type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ContentType.objects.all(),
|
||||
@ -828,7 +840,8 @@ class JournalEntryFilterForm(BootstrapMixin, forms.Form):
|
||||
label=_('Object Type'),
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/extras/content-types/',
|
||||
)
|
||||
),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
kind = forms.ChoiceField(
|
||||
choices=add_blank_choice(JournalEntryKindChoices),
|
||||
@ -868,7 +881,8 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
|
||||
label=_('User'),
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/users/users/',
|
||||
)
|
||||
),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
changed_object_type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ContentType.objects.all(),
|
||||
@ -876,7 +890,8 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
|
||||
label=_('Object Type'),
|
||||
widget=APISelectMultiple(
|
||||
api_url='/api/extras/content-types/',
|
||||
)
|
||||
),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
|
@ -115,12 +115,14 @@ class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFor
|
||||
import_target_id = DynamicModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
required=False,
|
||||
label=_('Import targets')
|
||||
label=_('Import targets'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
export_target_id = DynamicModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
required=False,
|
||||
label=_('Export targets')
|
||||
label=_('Export targets'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -185,12 +187,14 @@ class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelF
|
||||
importing_vrf_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Imported by VRF')
|
||||
label=_('Imported by VRF'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
exporting_vrf_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Exported by VRF')
|
||||
label=_('Exported by VRF'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -345,7 +349,8 @@ class AggregateFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFil
|
||||
rir_id = DynamicModelMultipleChoiceField(
|
||||
queryset=RIR.objects.all(),
|
||||
required=False,
|
||||
label=_('RIR')
|
||||
label=_('RIR'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -642,12 +647,14 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilter
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Assigned VRF'),
|
||||
null_option='Global'
|
||||
null_option='Global',
|
||||
fetch_trigger='open'
|
||||
)
|
||||
present_in_vrf_id = DynamicModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Present in VRF')
|
||||
label=_('Present in VRF'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=PrefixStatusChoices,
|
||||
@ -657,12 +664,14 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilter
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -671,13 +680,15 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilter
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
role_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Role.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Role')
|
||||
label=_('Role'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
is_pool = forms.NullBooleanField(
|
||||
required=False,
|
||||
@ -818,7 +829,8 @@ class IPRangeFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Assigned VRF'),
|
||||
null_option='Global'
|
||||
null_option='Global',
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=PrefixStatusChoices,
|
||||
@ -829,7 +841,8 @@ class IPRangeFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
queryset=Role.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Role')
|
||||
label=_('Role'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -1265,12 +1278,14 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFil
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Assigned VRF'),
|
||||
null_option='Global'
|
||||
null_option='Global',
|
||||
fetch_trigger='open'
|
||||
)
|
||||
present_in_vrf_id = DynamicModelChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label=_('Present in VRF')
|
||||
label=_('Present in VRF'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=IPAddressStatusChoices,
|
||||
@ -1439,27 +1454,32 @@ class VLANGroupFilterForm(BootstrapMixin, forms.Form):
|
||||
region = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
sitegroup = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
required=False,
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
location = DynamicModelMultipleChoiceField(
|
||||
queryset=Location.objects.all(),
|
||||
required=False,
|
||||
label=_('Location')
|
||||
label=_('Location'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
rack = DynamicModelMultipleChoiceField(
|
||||
queryset=Rack.objects.all(),
|
||||
required=False,
|
||||
label=_('Rack')
|
||||
label=_('Rack'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -1652,12 +1672,14 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -1666,7 +1688,8 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
query_params={
|
||||
'region': '$region'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VLANGroup.objects.all(),
|
||||
@ -1675,7 +1698,8 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
query_params={
|
||||
'region': '$region'
|
||||
},
|
||||
label=_('VLAN group')
|
||||
label=_('VLAN group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=VLANStatusChoices,
|
||||
@ -1686,7 +1710,8 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo
|
||||
queryset=Role.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Role')
|
||||
label=_('Role'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
BIN
netbox/project-static/dist/netbox-dark.css
vendored
BIN
netbox/project-static/dist/netbox-dark.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox-light.css
vendored
BIN
netbox/project-static/dist/netbox-light.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
@ -2,7 +2,7 @@ import queryString from 'query-string';
|
||||
import { readableColor } from 'color2k';
|
||||
import SlimSelect from 'slim-select';
|
||||
import { createToast } from '../bs';
|
||||
import { hasUrl, hasExclusions } from './util';
|
||||
import { hasUrl, hasExclusions, isTrigger } from './util';
|
||||
import {
|
||||
isTruthy,
|
||||
hasError,
|
||||
@ -10,6 +10,7 @@ import {
|
||||
getApiData,
|
||||
isApiError,
|
||||
getElements,
|
||||
createElement,
|
||||
findFirstAdjacent,
|
||||
} from '../util';
|
||||
|
||||
@ -17,6 +18,20 @@ import type { Option } from 'slim-select/dist/data';
|
||||
|
||||
type QueryFilter = Map<string, string | number | boolean>;
|
||||
|
||||
export type Trigger =
|
||||
/**
|
||||
* Load data when the select element is opened.
|
||||
*/
|
||||
| 'open'
|
||||
/**
|
||||
* Load data when the element is loaded.
|
||||
*/
|
||||
| 'load'
|
||||
/**
|
||||
* Load data when a parent element is uncollapsed.
|
||||
*/
|
||||
| 'collapse';
|
||||
|
||||
// Various one-off patterns to replace in query param keys.
|
||||
const REPLACE_PATTERNS = [
|
||||
// Don't query `termination_a_device=1`, but rather `device=1`.
|
||||
@ -57,6 +72,17 @@ class APISelect {
|
||||
*/
|
||||
public readonly placeholder: string;
|
||||
|
||||
/**
|
||||
* Event that will initiate the API call to NetBox to load option data. By default, the trigger
|
||||
* is `'load'`, so data will be fetched when the element renders on the page.
|
||||
*/
|
||||
private readonly trigger: Trigger;
|
||||
|
||||
/**
|
||||
* If `true`, a refresh button will be added next to the search/filter `<input/>` element.
|
||||
*/
|
||||
private readonly allowRefresh: boolean = true;
|
||||
|
||||
/**
|
||||
* Event to be dispatched when dependent fields' values change.
|
||||
*/
|
||||
@ -153,6 +179,7 @@ class APISelect {
|
||||
allowDeselect: true,
|
||||
deselectLabel: `<i class="mdi mdi-close-circle" style="color:currentColor;"></i>`,
|
||||
placeholder: this.placeholder,
|
||||
searchPlaceholder: 'Filter',
|
||||
onChange: () => this.handleSlimChange(),
|
||||
});
|
||||
|
||||
@ -186,20 +213,44 @@ class APISelect {
|
||||
// Initialize controlling elements.
|
||||
this.initResetButton();
|
||||
|
||||
// Add the refresh button to the search element.
|
||||
this.initRefreshButton();
|
||||
|
||||
// Add dependency event listeners.
|
||||
this.addEventListeners();
|
||||
|
||||
// Determine if the fetch trigger has been set.
|
||||
const triggerAttr = this.base.getAttribute('data-fetch-trigger');
|
||||
|
||||
// Determine if this element is part of collapsible element.
|
||||
const collapse = this.base.closest('.content-container .collapse');
|
||||
if (collapse !== null) {
|
||||
// If this element is part of a collapsible element, only load the data when the
|
||||
// collapsible element is shown.
|
||||
// See: https://getbootstrap.com/docs/5.0/components/collapse/#events
|
||||
collapse.addEventListener('show.bs.collapse', () => this.loadData());
|
||||
collapse.addEventListener('hide.bs.collapse', () => this.resetOptions());
|
||||
|
||||
if (isTrigger(triggerAttr)) {
|
||||
this.trigger = triggerAttr;
|
||||
} else if (collapse !== null) {
|
||||
this.trigger = 'collapse';
|
||||
} else {
|
||||
// Otherwise, load the data on render.
|
||||
Promise.all([this.loadData()]);
|
||||
this.trigger = 'load';
|
||||
}
|
||||
|
||||
switch (this.trigger) {
|
||||
case 'collapse':
|
||||
if (collapse !== null) {
|
||||
// If this element is part of a collapsible element, only load the data when the
|
||||
// collapsible element is shown.
|
||||
// See: https://getbootstrap.com/docs/5.0/components/collapse/#events
|
||||
collapse.addEventListener('show.bs.collapse', () => this.loadData());
|
||||
collapse.addEventListener('hide.bs.collapse', () => this.resetOptions());
|
||||
}
|
||||
break;
|
||||
case 'open':
|
||||
// If the trigger is 'open', only load API data when the select element is opened.
|
||||
this.slim.beforeOpen = () => this.loadData();
|
||||
break;
|
||||
case 'load':
|
||||
// Otherwise, load the data immediately.
|
||||
Promise.all([this.loadData()]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -713,21 +764,37 @@ class APISelect {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize any adjacent reset buttons so that when clicked, the instance's selected value is cleared.
|
||||
* Initialize any adjacent reset buttons so that when clicked, the page is reloaded without
|
||||
* query parameters.
|
||||
*/
|
||||
private initResetButton(): void {
|
||||
const resetButton = findFirstAdjacent<HTMLButtonElement>(this.base, 'button[data-reset-select');
|
||||
const resetButton = findFirstAdjacent<HTMLButtonElement>(
|
||||
this.base,
|
||||
'button[data-reset-select]',
|
||||
);
|
||||
if (resetButton !== null) {
|
||||
resetButton.addEventListener('click', () => {
|
||||
this.base.value = '';
|
||||
if (this.base.multiple) {
|
||||
this.slim.setSelected([]);
|
||||
} else {
|
||||
this.slim.setSelected('');
|
||||
}
|
||||
window.location.assign(window.location.origin + window.location.pathname);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a refresh button to the search container element. When clicked, the API data will be
|
||||
* reloaded.
|
||||
*/
|
||||
private initRefreshButton(): void {
|
||||
if (this.allowRefresh) {
|
||||
const refreshButton = createElement(
|
||||
'button',
|
||||
{ type: 'button' },
|
||||
['btn', 'btn-sm', 'btn-ghost-dark'],
|
||||
[createElement('i', {}, ['mdi', 'mdi-reload'])],
|
||||
);
|
||||
refreshButton.addEventListener('click', () => this.loadData());
|
||||
this.slim.slim.search.container.appendChild(refreshButton);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function initApiSelect() {
|
||||
|
@ -1,3 +1,5 @@
|
||||
import type { Trigger } from './api';
|
||||
|
||||
/**
|
||||
* Determine if an element has the `data-url` attribute set.
|
||||
*/
|
||||
@ -15,3 +17,10 @@ export function hasExclusions(
|
||||
const exclude = el.getAttribute('data-query-param-exclude');
|
||||
return typeof exclude === 'string' && exclude !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a trigger value is valid.
|
||||
*/
|
||||
export function isTrigger(value: unknown): value is Trigger {
|
||||
return typeof value === 'string' && ['load', 'open', 'collapse'].includes(value);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@
|
||||
}
|
||||
|
||||
* {
|
||||
transition: $transition-100ms-ease-in-out;
|
||||
transition: background-color, color 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.mw-25 {
|
||||
@ -302,8 +302,13 @@ span.profile-button .dropdown-menu {
|
||||
}
|
||||
}
|
||||
|
||||
div#advanced-search-content div.card div.card-body div.col:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
div#advanced-search-content {
|
||||
&.collapsing {
|
||||
transition: height 0.1s ease-in-out;
|
||||
}
|
||||
div.card div.card-body div.col:not(:last-child) {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
@ -430,6 +435,7 @@ nav.search {
|
||||
background-color: var(--nbx-body-bg);
|
||||
// Don't overtake dropdowns
|
||||
z-index: 999;
|
||||
justify-content: center;
|
||||
form button.dropdown-toggle {
|
||||
border-color: $input-border-color;
|
||||
font-weight: $input-group-addon-font-weight;
|
||||
|
@ -71,8 +71,8 @@ $spacing-s: $input-padding-x;
|
||||
border-color: currentColor;
|
||||
}
|
||||
}
|
||||
// Don't show the depth indicator outside of the menu.
|
||||
.placeholder .depth {
|
||||
// Don't show the depth indicator outside of the menu.
|
||||
display: none;
|
||||
}
|
||||
span.placeholder > *,
|
||||
@ -94,6 +94,11 @@ $spacing-s: $input-padding-x;
|
||||
.ss-value {
|
||||
border-radius: $badge-border-radius;
|
||||
color: var(--nbx-select-value-color);
|
||||
|
||||
// Don't show the depth indicator outside of the menu.
|
||||
.depth {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ss-add {
|
||||
@ -133,10 +138,34 @@ $spacing-s: $input-padding-x;
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
&::-webkit-scrollbar {
|
||||
right: 0;
|
||||
width: 4px;
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
right: 0;
|
||||
width: 2px;
|
||||
background-color: var(--nbx-sidebar-scroll);
|
||||
}
|
||||
}
|
||||
border-bottom-left-radius: $form-select-border-radius;
|
||||
border-bottom-right-radius: $form-select-border-radius;
|
||||
|
||||
.ss-search {
|
||||
padding-right: $spacer * 0.5;
|
||||
|
||||
button {
|
||||
margin-left: $spacer * 0.75;
|
||||
}
|
||||
|
||||
input[type='search'] {
|
||||
background-color: $form-select-bg;
|
||||
color: $input-color;
|
||||
|
@ -1,42 +1,24 @@
|
||||
{% extends 'base/layout.html' %}
|
||||
{% load buttons %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block extra_controls %}{% export_button content_type %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if filter_form %}
|
||||
<div class="col col-md-12 noprint">
|
||||
{% include 'inc/advanced_search.html' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-md-4 offset-md-8 d-flex noprint table-controls">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control object-filter" placeholder="Filter" title="Filter text (regular expressions supported)" />
|
||||
{% if filter_form %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#advanced-search-content">
|
||||
Advanced Search
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% include 'inc/responsive_table.html' %}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-7 col-lg-8 col-xl-9 col-xxl-10">
|
||||
{% include 'inc/table_controls.html' %}
|
||||
|
||||
<div class="table-responsive">
|
||||
{% render_table table 'inc/table.html' %}
|
||||
</div>
|
||||
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
</div>
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
{% if filter_form %}
|
||||
{% include 'inc/filter_list.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -5,63 +5,58 @@
|
||||
{% block title %}Rack Elevations{% endblock %}
|
||||
|
||||
{% block controls %}
|
||||
<div class="container mb-2 mx-0">
|
||||
<div class="d-flex flex-wrap justify-content-end">
|
||||
<button type="button" class="btn btn-sm btn-outline-dark m-1" data-bs-toggle="collapse" data-bs-target="#advanced-search-content">
|
||||
Advanced Search
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-dark toggle-images m-1" selected="selected">
|
||||
<span class="mdi mdi mdi-checkbox-marked-circle-outline" aria-hidden="true"></span> Show Images
|
||||
</button>
|
||||
<div class="btn-group btn-group-sm m-1" role="group">
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face='front' %}" class="btn btn-outline-secondary{% if rack_face == 'front' %} active{% endif %}">Front</a>
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face='rear' %}" class="btn btn-outline-secondary{% if rack_face == 'rear' %} active{% endif %}">Rear</a>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm m-1" role="group">
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request reverse=None %}" class="btn btn-outline-secondary{% if not reverse %} active{% endif %}">Normal</a>
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request reverse='true' %}" class="btn btn-outline-secondary{% if reverse %} active{% endif %}">Reversed</a>
|
||||
<div class="container mb-2 mx-0">
|
||||
<div class="d-flex flex-wrap justify-content-end">
|
||||
<button class="btn btn-sm btn-outline-dark toggle-images m-1" selected="selected">
|
||||
<span class="mdi mdi mdi-checkbox-marked-circle-outline" aria-hidden="true"></span> Show Images
|
||||
</button>
|
||||
<div class="btn-group btn-group-sm m-1" role="group">
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face='front' %}" class="btn btn-outline-secondary{% if rack_face == 'front' %} active{% endif %}">Front</a>
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request face='rear' %}" class="btn btn-outline-secondary{% if rack_face == 'rear' %} active{% endif %}">Rear</a>
|
||||
</div>
|
||||
<div class="btn-group btn-group-sm m-1" role="group">
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request reverse=None %}" class="btn btn-outline-secondary{% if not reverse %} active{% endif %}">Normal</a>
|
||||
<a href="{% url 'dcim:rack_elevation_list' %}{% querystring request reverse='true' %}" class="btn btn-outline-secondary{% if reverse %} active{% endif %}">Reversed</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col col-md-12 noprint">
|
||||
{% include 'inc/advanced_search.html' %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
{% if page %}
|
||||
<div style="white-space: nowrap; overflow-x: scroll;">
|
||||
{% for rack in page %}
|
||||
<div style="display: inline-block; margin-right: 12px; width: 254px">
|
||||
<div style="margin-left: 30px">
|
||||
<div class="text-center">
|
||||
<strong><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack.name }}</a></strong>
|
||||
{% if rack.role %}
|
||||
<br /><span class="badge my-3" style="color: {{ rack.role.color|fgcolor }}; background-color: #{{ rack.role.color }}">{{ rack.role }}</span>
|
||||
{% endif %}
|
||||
{% if rack.facility_id %}
|
||||
<br /><small class="text-muted">{{ rack.facility_id }}</small>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="col col-md-7 col-lg-8 col-xl-9 col-xxl-10">
|
||||
{% if page %}
|
||||
<div style="white-space: nowrap; overflow-x: scroll;">
|
||||
{% for rack in page %}
|
||||
<div style="display: inline-block; margin-right: 12px; width: 254px">
|
||||
<div style="margin-left: 30px">
|
||||
<div class="text-center">
|
||||
<strong><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack.name }}</a></strong>
|
||||
{% if rack.role %}
|
||||
<br /><span class="badge my-3" style="color: {{ rack.role.color|fgcolor }}; background-color: #{{ rack.role.color }}">{{ rack.role }}</span>
|
||||
{% endif %}
|
||||
{% if rack.facility_id %}
|
||||
<br /><small class="text-muted">{{ rack.facility_id }}</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'dcim/inc/rack_elevation.html' with object=rack face=rack_face %}
|
||||
<div class="clearfix"></div>
|
||||
<div class="text-center">
|
||||
<strong><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack.name }}</a></strong>
|
||||
{% if rack.facility_id %}
|
||||
<small class="text-muted">({{ rack.facility_id }})</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'dcim/inc/rack_elevation.html' with object=rack face=rack_face %}
|
||||
<div class="clearfix"></div>
|
||||
<div class="text-center">
|
||||
<strong><a href="{% url 'dcim:rack' pk=rack.pk %}">{{ rack.name }}</a></strong>
|
||||
{% if rack.facility_id %}
|
||||
<small class="text-muted">({{ rack.facility_id }})</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<br />
|
||||
{% include 'inc/paginator.html' %}
|
||||
{% else %}
|
||||
<p>No Racks Found</p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<br />
|
||||
{% include 'inc/paginator.html' %}
|
||||
{% else %}
|
||||
<p>No Racks Found</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'inc/filter_list.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -24,9 +24,6 @@
|
||||
{% endblock controls %}
|
||||
|
||||
{% block content %}
|
||||
{% if filter_form %}
|
||||
{% include 'inc/advanced_search.html' %}
|
||||
{% endif %}
|
||||
{% if table.paginator.num_pages > 1 %}
|
||||
{% with bulk_edit_url=content_type.model_class|validated_viewname:"bulk_edit" bulk_delete_url=content_type.model_class|validated_viewname:"bulk_delete" %}
|
||||
<div id="select-all-box" class="d-none card noprint">
|
||||
@ -57,12 +54,12 @@
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
{# Object list filter, table config #}
|
||||
{% include 'inc/table_controls.html' with table_modal="ObjectTable_config" %}
|
||||
|
||||
{# Object table #}
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<div class="col col-md-7 col-lg-8 col-xl-9 col-xxl-10">
|
||||
{# Object list filter, table config #}
|
||||
{% include 'inc/table_controls.html' with table_modal="ObjectTable_config" %}
|
||||
|
||||
{% with bulk_edit_url=content_type.model_class|validated_viewname:"bulk_edit" bulk_delete_url=content_type.model_class|validated_viewname:"bulk_delete" %}
|
||||
{% if permissions.change or permissions.delete %}
|
||||
<form method="post" class="form form-horizontal">
|
||||
@ -95,6 +92,9 @@
|
||||
{% endwith %}
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
</div>
|
||||
{% if filter_form %}
|
||||
{% include 'inc/filter_list.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% table_config_form table table_name="ObjectTable" %}
|
||||
{% endblock content %}
|
||||
|
62
netbox/templates/inc/filter_list.html
Normal file
62
netbox/templates/inc/filter_list.html
Normal file
@ -0,0 +1,62 @@
|
||||
{% load form_helpers %}
|
||||
{% load helpers %}
|
||||
|
||||
<div class="col col-md-5 col-lg-4 col-xl-3 col-xxl-2 noprint">
|
||||
<form action="." method="get">
|
||||
<div class="card small">
|
||||
<h5 class="card-header">
|
||||
Field Filters
|
||||
</h5>
|
||||
<div class="card-body overflow-visible d-flex flex-wrap justify-content-between py-3">
|
||||
{% for field in filter_form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
{% if filter_form.field_groups %}
|
||||
{% for group in filter_form.field_groups %}
|
||||
<div class="col col-12">
|
||||
{% for name in group %}
|
||||
{% with field=filter_form|get_item:name %}
|
||||
{% if field|widget_type == 'checkboxinput' %}
|
||||
<div class="form-check mb-3">
|
||||
<label class="form-check-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="mb-3 mx-3">
|
||||
<label class="form-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for field in filter_form.visible_fields %}
|
||||
<div class="col">
|
||||
{% if field|widget_type == 'checkboxinput' %}
|
||||
<div class="form-check mb-3">
|
||||
<label class="form-check-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-end noprint border-0">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger m-1" data-reset-select>
|
||||
<i class="mdi mdi-backspace"></i> Reset
|
||||
</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary m-1">
|
||||
<i class="mdi mdi-filter-variant"></i> Filter
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -1,6 +1,6 @@
|
||||
<div class="row mb-3 justify-content-between">
|
||||
<div class="col col-md-2 mb-0 d-flex noprint table-controls">
|
||||
{% if request.user.is_authenticated %}
|
||||
{% if request.user.is_authenticated and table_modal %}
|
||||
<div class="input-group input-group-sm">
|
||||
<button
|
||||
type="button"
|
||||
@ -22,16 +22,6 @@
|
||||
placeholder="Filter"
|
||||
title="Filter text (regular expressions supported)"
|
||||
/>
|
||||
{% if filter_form %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#advanced-search-content"
|
||||
>
|
||||
Advanced Search
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -67,7 +67,8 @@ class TenantGroupFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
parent_id = DynamicModelMultipleChoiceField(
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Parent group')
|
||||
label=_('Parent group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
||||
|
||||
@ -137,7 +138,8 @@ class TenantFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Group')
|
||||
label=_('Group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -169,7 +171,8 @@ class TenancyFilterForm(forms.Form):
|
||||
queryset=TenantGroup.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Tenant group')
|
||||
label=_('Tenant group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tenant_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Tenant.objects.all(),
|
||||
@ -178,5 +181,6 @@ class TenancyFilterForm(forms.Form):
|
||||
query_params={
|
||||
'group_id': '$tenant_group_id'
|
||||
},
|
||||
label=_('Tenant')
|
||||
label=_('Tenant'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
|
@ -363,16 +363,19 @@ class DynamicModelChoiceMixin:
|
||||
:param null_option: The string used to represent a null selection (if any)
|
||||
:param disabled_indicator: The name of the field which, if populated, will disable selection of the
|
||||
choice (optional)
|
||||
:param str fetch_trigger: The event type which will cause the select element to
|
||||
fetch data from the API. Must be 'load', 'open', or 'collapse'. (optional)
|
||||
"""
|
||||
filter = django_filters.ModelChoiceFilter
|
||||
widget = widgets.APISelect
|
||||
|
||||
def __init__(self, query_params=None, initial_params=None, null_option=None, disabled_indicator=None, *args,
|
||||
def __init__(self, query_params=None, initial_params=None, null_option=None, disabled_indicator=None, fetch_trigger=None, *args,
|
||||
**kwargs):
|
||||
self.query_params = query_params or {}
|
||||
self.initial_params = initial_params or {}
|
||||
self.null_option = null_option
|
||||
self.disabled_indicator = disabled_indicator
|
||||
self.fetch_trigger = fetch_trigger
|
||||
|
||||
# to_field_name is set by ModelChoiceField.__init__(), but we need to set it early for reference
|
||||
# by widget_attrs()
|
||||
@ -394,6 +397,10 @@ class DynamicModelChoiceMixin:
|
||||
# Set the disabled indicator, if any
|
||||
if self.disabled_indicator is not None:
|
||||
attrs['disabled-indicator'] = self.disabled_indicator
|
||||
|
||||
# Set the fetch trigger, if any.
|
||||
if self.fetch_trigger is not None:
|
||||
attrs['data-fetch-trigger'] = self.fetch_trigger
|
||||
|
||||
# Attach any static query parameters
|
||||
for key, value in self.query_params.items():
|
||||
|
@ -236,12 +236,14 @@ class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ClusterType.objects.all(),
|
||||
required=False,
|
||||
label=_('Type')
|
||||
label=_('Type'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -250,13 +252,15 @@ class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilte
|
||||
query_params={
|
||||
'region_id': '$region_id'
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Group')
|
||||
label=_('Group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
@ -547,28 +551,33 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod
|
||||
queryset=ClusterGroup.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Cluster group')
|
||||
label=_('Cluster group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
cluster_type_id = DynamicModelMultipleChoiceField(
|
||||
queryset=ClusterType.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Cluster type')
|
||||
label=_('Cluster type'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
cluster_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
required=False,
|
||||
label=_('Cluster')
|
||||
label=_('Cluster'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
region_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Region.objects.all(),
|
||||
required=False,
|
||||
label=_('Region')
|
||||
label=_('Region'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_group_id = DynamicModelMultipleChoiceField(
|
||||
queryset=SiteGroup.objects.all(),
|
||||
required=False,
|
||||
label=_('Site group')
|
||||
label=_('Site group'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
site_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Site.objects.all(),
|
||||
@ -578,7 +587,8 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod
|
||||
'region_id': '$region_id',
|
||||
'group_id': '$site_group_id',
|
||||
},
|
||||
label=_('Site')
|
||||
label=_('Site'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
role_id = DynamicModelMultipleChoiceField(
|
||||
queryset=DeviceRole.objects.all(),
|
||||
@ -587,7 +597,8 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod
|
||||
query_params={
|
||||
'vm_role': "True"
|
||||
},
|
||||
label=_('Role')
|
||||
label=_('Role'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
status = forms.MultipleChoiceField(
|
||||
choices=VirtualMachineStatusChoices,
|
||||
@ -598,7 +609,8 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod
|
||||
queryset=Platform.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Platform')
|
||||
label=_('Platform'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
mac_address = forms.CharField(
|
||||
required=False,
|
||||
@ -850,7 +862,8 @@ class VMInterfaceFilterForm(BootstrapMixin, forms.Form):
|
||||
cluster_id = DynamicModelMultipleChoiceField(
|
||||
queryset=Cluster.objects.all(),
|
||||
required=False,
|
||||
label=_('Cluster')
|
||||
label=_('Cluster'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
virtual_machine_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VirtualMachine.objects.all(),
|
||||
@ -858,7 +871,8 @@ class VMInterfaceFilterForm(BootstrapMixin, forms.Form):
|
||||
query_params={
|
||||
'cluster_id': '$cluster_id'
|
||||
},
|
||||
label=_('Virtual machine')
|
||||
label=_('Virtual machine'),
|
||||
fetch_trigger='open'
|
||||
)
|
||||
enabled = forms.NullBooleanField(
|
||||
required=False,
|
||||
|
Loading…
Reference in New Issue
Block a user