From 58862e115cdc72a6d7f74c257bb7aac64e5947ef Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 3 Aug 2021 08:32:53 -0700 Subject: [PATCH] Closes #6863: Add search fields back to filter forms --- netbox/circuits/forms.py | 23 +++- netbox/dcim/forms.py | 111 ++++++++++++++++++-- netbox/extras/forms.py | 46 +++++++- netbox/ipam/forms.py | 67 ++++++++++-- netbox/project-static/dist/netbox-dark.css | Bin 761390 -> 761626 bytes netbox/project-static/dist/netbox-light.css | Bin 473790 -> 473952 bytes netbox/project-static/styles/netbox.scss | 17 ++- netbox/templates/inc/filter_list.html | 9 +- netbox/tenancy/forms.py | 6 ++ netbox/virtualization/forms.py | 20 +++- 10 files changed, 272 insertions(+), 27 deletions(-) diff --git a/netbox/circuits/forms.py b/netbox/circuits/forms.py index 261bb8bd6..126b2a47b 100644 --- a/netbox/circuits/forms.py +++ b/netbox/circuits/forms.py @@ -107,9 +107,15 @@ class ProviderBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBu class ProviderFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = Provider field_groups = [ + ['q'], ['region_id', 'site_id'], ['asn', 'tag'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -196,7 +202,12 @@ class ProviderNetworkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomField class ProviderNetworkFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = ProviderNetwork - field_order = ['provider_id'] + field_order = ['q', 'provider_id', 'tag'] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) provider_id = DynamicModelMultipleChoiceField( queryset=Provider.objects.all(), required=False, @@ -358,16 +369,22 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBul class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Circuit field_order = [ - 'type_id', 'provider_id', 'provider_network_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id', - 'commit_rate', + 'q', 'type_id', 'provider_id', 'provider_network_id', 'status', 'region_id', 'site_id', 'tenant_group_id', + 'tenant_id', 'commit_rate', ] field_groups = [ + ['q'], ['type_id', 'status', 'commit_rate'], ['provider_id', 'provider_network_id'], ['region_id', 'site_id'], ['tenant_group_id', 'tenant_id'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) type_id = DynamicModelMultipleChoiceField( queryset=CircuitType.objects.all(), required=False, diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index da9030ca9..348cb3b62 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -56,12 +56,18 @@ def get_device_by_name_or_pk(name): class DeviceComponentFilterForm(BootstrapMixin, CustomFieldModelFilterForm): field_order = [ - 'name', 'label', 'region_id', 'site_group_id', 'site_id', + 'q', 'name', 'label', 'region_id', 'site_group_id', 'site_id', ] field_groups = [ + ['q'], ['name', 'label'], ['region_id', 'site_group_id', 'site_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) name = forms.CharField( required=False ) @@ -452,12 +458,18 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEd class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Site - field_order = ['status', 'region_id', 'tenant_group_id', 'tenant_id'] + field_order = ['q', 'status', 'region_id', 'tenant_group_id', 'tenant_id'] field_groups = [ + ['q'], ['status', 'region_id'], ['tenant_group_id', 'tenant_id'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) status = forms.MultipleChoiceField( choices=SiteStatusChoices, required=False, @@ -568,6 +580,11 @@ class LocationBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditForm): class LocationFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = Location + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -862,12 +879,18 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEd class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Rack - field_order = ['region_id', 'site_id', 'location_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id'] + field_order = ['q', 'region_id', 'site_id', 'location_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id'] field_groups = [ + ['q'], ['status', 'role_id'], ['region_id', 'site_id', 'location_id'], ['tenant_group_id', 'tenant_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -927,7 +950,8 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterFo class RackElevationFilterForm(RackFilterForm): field_order = [ - 'region_id', 'site_id', 'location_id', 'id', 'status', 'role_id', 'tenant_group_id', 'tenant_id', + 'q', 'region_id', 'site_id', 'location_id', 'id', 'status', 'role_id', 'tenant_group_id', + 'tenant_id', ] id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), @@ -1092,11 +1116,17 @@ class RackReservationBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomField class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = RackReservation - field_order = ['region_id', 'site_id', 'location_id', 'user_id', 'tenant_group_id', 'tenant_id'] + field_order = ['q', 'region_id', 'site_id', 'location_id', 'user_id', 'tenant_group_id', 'tenant_id'] field_groups = [ + ['q'], ['region_id', 'site_id', 'location_id'], ['user_id', 'tenant_group_id', 'tenant_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -1246,12 +1276,18 @@ class DeviceTypeBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModel class DeviceTypeFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = DeviceType field_groups = [ + ['q'], ['manufacturer_id', 'subdevice_role'], ['console_ports', 'console_server_ports'], ['power_ports', 'power_outlets'], ['interfaces', 'pass_through_ports'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) manufacturer_id = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), required=False, @@ -2058,6 +2094,11 @@ class PlatformBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditForm): class PlatformFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = Platform + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) manufacturer_id = DynamicModelMultipleChoiceField( queryset=Manufacturer.objects.all(), required=False, @@ -2465,16 +2506,23 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulk class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldModelFilterForm): model = Device field_order = [ - 'region_id', 'site_id', 'location_id', 'rack_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id', - 'manufacturer_id', 'device_type_id', 'asset_tag', 'mac_address', 'has_primary_ip', + 'q', 'region_id', 'site_id', 'location_id', 'rack_id', 'status', 'role_id', + 'tenant_group_id', 'tenant_id', 'manufacturer_id', 'device_type_id', 'asset_tag', + 'mac_address', 'has_primary_ip', ] field_groups = [ + ['q'], ['region_id', 'site_id', 'location_id', 'rack_id'], ['status', 'role_id', 'asset_tag'], ['tenant_group_id', 'tenant_id'], ['manufacturer_id', 'device_type_id'], ['mac_address', 'has_primary_ip'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -2654,6 +2702,7 @@ class DeviceBulkAddComponentForm(BootstrapMixin, CustomFieldsMixin, ComponentFor class ConsolePortFilterForm(DeviceComponentFilterForm): model = ConsolePort field_groups = [ + ['q'], ['name', 'label'], ['type', 'speed'], ['region_id', 'site_group_id', 'site_id'], @@ -2761,6 +2810,7 @@ class ConsolePortCSVForm(CustomFieldModelCSVForm): class ConsoleServerPortFilterForm(DeviceComponentFilterForm): model = ConsoleServerPort field_groups = [ + ['q'], ['name', 'label'], ['type', 'speed'], ['region_id', 'site_group_id', 'site_id'], @@ -2868,6 +2918,7 @@ class ConsoleServerPortCSVForm(CustomFieldModelCSVForm): class PowerPortFilterForm(DeviceComponentFilterForm): model = PowerPort field_groups = [ + ['q'], ['name', 'label', 'type'], ['region_id', 'site_group_id', 'site_id'], ['tag'], @@ -2973,6 +3024,7 @@ class PowerPortCSVForm(CustomFieldModelCSVForm): class PowerOutletFilterForm(DeviceComponentFilterForm): model = PowerOutlet field_groups = [ + ['q'], ['name', 'label', 'type'], ['region_id', 'site_group_id', 'site_id'], ['tag'], @@ -3145,6 +3197,7 @@ class PowerOutletCSVForm(CustomFieldModelCSVForm): class InterfaceFilterForm(DeviceComponentFilterForm): model = Interface field_groups = [ + ['q'], ['name', 'label', 'type', 'enabled'], ['mgmt_only', 'mac_address'], ['region_id', 'site_group_id', 'site_id'], @@ -3493,6 +3546,7 @@ class InterfaceCSVForm(CustomFieldModelCSVForm): class FrontPortFilterForm(DeviceComponentFilterForm): field_groups = [ + ['q'], ['name', 'label', 'type', 'color'], ['region_id', 'site_group_id', 'site_id'], ['tag'] @@ -3682,6 +3736,7 @@ class FrontPortCSVForm(CustomFieldModelCSVForm): class RearPortFilterForm(DeviceComponentFilterForm): model = RearPort field_groups = [ + ['q'], ['name', 'label', 'type', 'color'], ['region_id', 'site_group_id', 'site_id'], ['tag'] @@ -3783,6 +3838,7 @@ class RearPortCSVForm(CustomFieldModelCSVForm): class DeviceBayFilterForm(DeviceComponentFilterForm): model = DeviceBay field_groups = [ + ['q'], ['name', 'label'], ['region_id', 'site_group_id', 'site_id'], ['tag'] @@ -4013,6 +4069,7 @@ class InventoryItemBulkEditForm( class InventoryItemFilterForm(DeviceComponentFilterForm): model = InventoryItem field_groups = [ + ['q'], ['name', 'label', 'manufacturer_id'], ['serial', 'asset_tag', 'discovered'], ['region_id', 'site_group_id', 'site_id'], @@ -4488,11 +4545,17 @@ class CableBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkE class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = Cable field_groups = [ + ['q'], ['type', 'status', 'color'], ['device_id', 'rack_id'], ['region_id', 'site_id', 'tenant_id'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -4556,6 +4619,11 @@ class CableFilterForm(BootstrapMixin, CustomFieldModelFilterForm): # class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form): + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -4583,6 +4651,11 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form): class PowerConnectionFilterForm(BootstrapMixin, forms.Form): + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -4610,6 +4683,11 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form): class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form): + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -4877,12 +4955,18 @@ class VirtualChassisCSVForm(CustomFieldModelCSVForm): class VirtualChassisFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = VirtualChassis - field_order = ['region_id', 'site_group_id', 'site_id', 'tenant_group_id', 'tenant_id'] + field_order = ['q', 'region_id', 'site_group_id', 'site_id', 'tenant_group_id', 'tenant_id'] field_groups = [ + ['q'], ['region_id', 'site_group_id', 'site_id'], ['tenant_group_id', 'tenant_id'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -5022,6 +5106,11 @@ class PowerPanelBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModel class PowerPanelFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = PowerPanel + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -5260,12 +5349,18 @@ class PowerFeedBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelB class PowerFeedFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = PowerFeed field_groups = [ + ['q'], ['region_id', 'site_group_id', 'site_id'], ['power_panel_id', 'rack_id'], ['type', 'supply', 'max_utilization'], ['phase', 'voltage', 'amperage'], ['status', 'tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, diff --git a/netbox/extras/forms.py b/netbox/extras/forms.py index 16091885c..98f34dfa9 100644 --- a/netbox/extras/forms.py +++ b/netbox/extras/forms.py @@ -77,9 +77,15 @@ class CustomFieldBulkEditForm(BootstrapMixin, BulkEditForm): class CustomFieldFilterForm(BootstrapMixin, forms.Form): field_groups = [ + ['q'], ['type', 'content_types'], ['weight', 'required'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields') @@ -167,9 +173,15 @@ class CustomLinkBulkEditForm(BootstrapMixin, BulkEditForm): class CustomLinkFilterForm(BootstrapMixin, forms.Form): field_groups = [ + ['q'], ['content_type'], ['weight', 'new_window'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields') @@ -252,9 +264,15 @@ class ExportTemplateBulkEditForm(BootstrapMixin, BulkEditForm): class ExportTemplateFilterForm(BootstrapMixin, forms.Form): field_groups = [ + ['q'], ['content_type', 'mime_type'], ['file_extension', 'as_attachment'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) content_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields') @@ -358,9 +376,15 @@ class WebhookBulkEditForm(BootstrapMixin, BulkEditForm): class WebhookFilterForm(BootstrapMixin, forms.Form): field_groups = [ + ['q'], ['content_types', 'http_method'], ['enabled', 'type_create', 'type_update', 'type_delete'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields') @@ -664,15 +688,21 @@ class ConfigContextBulkEditForm(BootstrapMixin, BulkEditForm): class ConfigContextFilterForm(BootstrapMixin, forms.Form): field_order = [ - 'region_id', 'site_group_id', 'site_id', 'role_id', 'platform_id', 'cluster_group_id', 'cluster_id', - 'tenant_group_id', 'tenant_id', + 'q', 'region_id', 'site_group_id', 'site_id', 'role_id', 'platform_id', 'cluster_group_id', + 'cluster_id', 'tenant_group_id', 'tenant_id', ] field_groups = [ + ['q'], ['region_id', 'site_group_id', 'site_id'], ['device_type_id', 'role_id', 'platform_id'], ['cluster_group_id', 'cluster_id'], ['tenant_group_id', 'tenant_id', 'tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -812,9 +842,15 @@ class JournalEntryBulkEditForm(BootstrapMixin, BulkEditForm): class JournalEntryFilterForm(BootstrapMixin, forms.Form): model = JournalEntry field_groups = [ + ['q'], ['created_before', 'created_after', 'created_by_id'], ['assigned_object_type_id', 'kind'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) created_after = forms.DateTimeField( required=False, label=_('After'), @@ -857,9 +893,15 @@ class JournalEntryFilterForm(BootstrapMixin, forms.Form): class ObjectChangeFilterForm(BootstrapMixin, forms.Form): model = ObjectChange field_groups = [ + ['q'], ['time_before', 'time_after', 'action'], ['user_id', 'changed_object_type_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) time_after = forms.DateTimeField( required=False, label=_('After'), diff --git a/netbox/ipam/forms.py b/netbox/ipam/forms.py index f60853525..4bb628b49 100644 --- a/netbox/ipam/forms.py +++ b/netbox/ipam/forms.py @@ -106,12 +106,18 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEdi class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = VRF - field_order = ['import_target_id', 'export_target_id', 'tenant_group_id', 'tenant_id'] + field_order = ['q', 'import_target_id', 'export_target_id', 'tenant_group_id', 'tenant_id'] field_groups = [ + ['q'], ['import_target_id', 'export_target_id'], ['tenant_group_id', 'tenant_id'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) import_target_id = DynamicModelMultipleChoiceField( queryset=RouteTarget.objects.all(), required=False, @@ -179,11 +185,17 @@ class RouteTargetBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldMode class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = RouteTarget - field_order = ['name', 'tenant_group_id', 'tenant_id', 'importing_vrfs', 'exporting_vrfs'] + field_order = ['q', 'name', 'tenant_group_id', 'tenant_id', 'importing_vrfs', 'exporting_vrfs'] field_groups = [ + ['q'], ['importing_vrf_id', 'exporting_vrf_id'], ['tenant_group_id', 'tenant_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) importing_vrf_id = DynamicModelMultipleChoiceField( queryset=VRF.objects.all(), required=False, @@ -335,11 +347,17 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelB class AggregateFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Aggregate - field_order = ['family', 'rir', 'tenant_group_id', 'tenant_id'] + field_order = ['q', 'family', 'rir', 'tenant_group_id', 'tenant_id'] field_groups = [ + ['q'], ['family', 'rir_id'], ['tenant_group_id', 'tenant_id'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), @@ -610,15 +628,22 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulk class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Prefix field_order = [ - 'within_include', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'region_id', - 'site_group_id', 'site_id', 'role_id', 'tenant_group_id', 'tenant_id', 'is_pool', 'mark_utilized', + 'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', + 'region_id', 'site_group_id', 'site_id', 'role_id', 'tenant_group_id', 'tenant_id', + 'is_pool', 'mark_utilized', ] field_groups = [ + ['q'], ['role_id', 'within_include', 'family', 'mask_length'], ['vrf_id', 'present_in_vrf_id', 'is_pool', 'mark_utilized'], ['region_id', 'site_group_id', 'site_id'], ['tenant_group_id', 'tenant_id', 'status', 'tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) mask_length__lte = forms.IntegerField( widget=forms.HiddenInput() ) @@ -813,12 +838,18 @@ class IPRangeBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBul class IPRangeFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = IPRange field_order = [ - 'family', 'vrf_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id', + 'q', 'family', 'vrf_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id', ] field_groups = [ + ['q'], ['family', 'vrf_id', 'status', 'role_id'], ['tenant_group_id', 'tenant_id', 'tag'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) family = forms.ChoiceField( required=False, choices=add_blank_choice(IPAddressFamilyChoices), @@ -1244,15 +1275,21 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form): class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = IPAddress field_order = [ - 'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role', + 'q', 'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role', 'assigned_to_interface', 'tenant_group_id', 'tenant_id', ] field_groups = [ + ['q'], ['parent', 'family', 'mask_length'], ['status', 'vrf_id', 'present_in_vrf_id'], ['role', 'assigned_to_interface'], ['tenant_group_id', 'tenant_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) parent = forms.CharField( required=False, widget=forms.TextInput( @@ -1444,11 +1481,13 @@ class VLANGroupBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditForm): class VLANGroupFilterForm(BootstrapMixin, forms.Form): field_groups = [ + ['q'], ['region', 'sitegroup', 'site'], ['location', 'rack'] ] q = forms.CharField( required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search') ) region = DynamicModelMultipleChoiceField( @@ -1662,13 +1701,20 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEd class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = VLAN field_order = [ - 'region_id', 'site_group_id', 'site_id', 'group_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id', + 'q', 'region_id', 'site_group_id', 'site_id', 'group_id', 'status', 'role_id', + 'tenant_group_id', 'tenant_id', ] field_groups = [ + ['q'], ['region_id', 'site_group_id', 'site_id'], ['group_id', 'role_id', 'status'], ['tenant_group_id', 'tenant_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), required=False, @@ -1765,6 +1811,11 @@ class ServiceForm(BootstrapMixin, CustomFieldModelForm): class ServiceFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = Service + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) protocol = forms.ChoiceField( choices=add_blank_choice(ServiceProtocolChoices), required=False, diff --git a/netbox/project-static/dist/netbox-dark.css b/netbox/project-static/dist/netbox-dark.css index 1ae150baa9303607adbcd1f963fed5f4088a800d..73e693cbf6d74e7c1b99d3c6de3f28740f07263c 100644 GIT binary patch delta 141 zcmV;80CNAXye^u)E`WpqgaU*Egam{Iga(8Mgb0KQgbK6^Wj7RaZDDL|ATDNaa&0YR zZ*FvQZ)|&$#KI&N=tC@y1Ra%3%HZ)ABXKDT5y3s)nT;6McgmmpdT2MAF7M2#)7Pc1l7LFFq7OpMaspi}Fn{$ULPj0xyyM0SEcbYQ* Dn;Q`R diff --git a/netbox/project-static/dist/netbox-light.css b/netbox/project-static/dist/netbox-light.css index b64440802bc1ab5bf76e0a0d5ca921ca0cf64ff2..50949743c34f3f32ae8d3ef6920fab0f4e63c628 100644 GIT binary patch delta 161 zcmdn@Rp!ArnT8g|7N!>F7M2#)Eo>XVniuCL=Hw{orR5jp>L%ysl@#UYRHp%H-Qvuu zR4Y9TbJL>K+*+%={1Oel`%8@{q7i<^N&6d>X$nPr(NsYTW0nJFb1 zR)z)!s@55)nduoNR)z%?*13sA>6v*}hCss<45sJ*U{mMLFGx(zEUC28Gcw&S$jiP~ F7XXXtI}ZQ= delta 46 zcmaFxO=jO$nT8g|7N!>F7M2#)Eo>XVGAHNfOm6HF+s^cj%~O1OI3GLj_Cvhv^K=2p CD-pK< diff --git a/netbox/project-static/styles/netbox.scss b/netbox/project-static/styles/netbox.scss index e3acd687c..9db1ce35a 100644 --- a/netbox/project-static/styles/netbox.scss +++ b/netbox/project-static/styles/netbox.scss @@ -89,8 +89,13 @@ table td > .progress { min-width: 6rem; } -// Automatically space out adjacent columns. -.col:not(:last-child):not(:only-child) { +// Override Bootstrap form-control font-size when contained by .small element. +.small .form-control { + font-size: $font-size-sm; +} + +// Automatically space out adjacent columns, but not within card bodies. +:not(.card-body) > .col:not(:last-child):not(:only-child) { margin-bottom: $spacer; } @@ -479,6 +484,14 @@ span.color-label { .card-body.small .form-select { font-size: $input-font-size-sm; } + + .card-divider { + width: 100%; + height: 1px; + margin: $hr-margin-y 0; + border-top: 1px solid $card-border-color; + opacity: $hr-opacity; + } } .form-floating { diff --git a/netbox/templates/inc/filter_list.html b/netbox/templates/inc/filter_list.html index 07aa2249b..8837a75e2 100644 --- a/netbox/templates/inc/filter_list.html +++ b/netbox/templates/inc/filter_list.html @@ -22,7 +22,7 @@ {{ field }} {% else %} -
+
{{ field }}
@@ -30,17 +30,20 @@ {% endwith %} {% endfor %}
+ {% if forloop.counter != filter_form.field_groups|length %} +
+ {% endif %} {% endfor %} {% else %} {% for field in filter_form.visible_fields %} -
+
{% if field|widget_type == 'checkboxinput' %}
{{ field }}
{% else %} -
+
{{ field }}
diff --git a/netbox/tenancy/forms.py b/netbox/tenancy/forms.py index 05b47ad4c..58c1ae60a 100644 --- a/netbox/tenancy/forms.py +++ b/netbox/tenancy/forms.py @@ -64,6 +64,11 @@ class TenantGroupBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditForm): class TenantGroupFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = TenantGroup + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) parent_id = DynamicModelMultipleChoiceField( queryset=TenantGroup.objects.all(), required=False, @@ -132,6 +137,7 @@ class TenantFilterForm(BootstrapMixin, CustomFieldModelFilterForm): model = Tenant q = forms.CharField( required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search') ) group_id = DynamicModelMultipleChoiceField( diff --git a/netbox/virtualization/forms.py b/netbox/virtualization/forms.py index 7cef7434b..2b352ed3f 100644 --- a/netbox/virtualization/forms.py +++ b/netbox/virtualization/forms.py @@ -225,14 +225,20 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBul class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm): model = Cluster field_order = [ - 'type_id', 'region_id', 'site_id', 'group_id', 'tenant_group_id', 'tenant_id', + 'q', 'type_id', 'region_id', 'site_id', 'group_id', 'tenant_group_id', 'tenant_id', ] field_groups = [ + ['q'], ['type_id'], ['region_id', 'site_id'], ['tenant_group_id', 'tenant_id'], ['tag'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) type_id = DynamicModelMultipleChoiceField( queryset=ClusterType.objects.all(), required=False, @@ -540,6 +546,7 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod 'site_id', 'tenant_group_id', 'tenant_id', 'platform_id', 'mac_address', ] field_groups = [ + ['q'], ['status', 'role_id'], ['platform_id', 'mac_address'], ['cluster_group_id', 'cluster_type_id', 'cluster_id'], @@ -547,6 +554,11 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldMod ['tenant_group_id', 'tenant_id'], ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) cluster_group_id = DynamicModelMultipleChoiceField( queryset=ClusterGroup.objects.all(), required=False, @@ -855,10 +867,16 @@ class VMInterfaceBulkRenameForm(BulkRenameForm): class VMInterfaceFilterForm(BootstrapMixin, forms.Form): model = VMInterface field_groups = [ + ['q'], ['cluster_id', 'virtual_machine_id'], ['enabled', 'mac_address'], ['tag'] ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) cluster_id = DynamicModelMultipleChoiceField( queryset=Cluster.objects.all(), required=False,