Просмотр исходного кода

#6372: Move object list search panel into collapsed view & remove search field

checktheroads 4 лет назад
Родитель
Сommit
da0aa38614

+ 13 - 14
netbox/circuits/forms.py

@@ -104,10 +104,10 @@ class ProviderBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdi
 
 class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Provider
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['region_id', 'site_id'],
+        ['asn', 'tag'],
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -192,11 +192,7 @@ class ProviderNetworkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomField
 
 class ProviderNetworkFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = ProviderNetwork
-    field_order = ['q', 'provider_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['provider_id']
     provider_id = DynamicModelMultipleChoiceField(
         queryset=Provider.objects.all(),
         required=False,
@@ -357,13 +353,16 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
 class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Circuit
     field_order = [
-        'q', 'type_id', 'provider_id', 'provider_network_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id',
+        'type_id', 'provider_id', 'provider_network_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id',
         'commit_rate',
     ]
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['type_id', 'status', 'commit_rate'],
+        ['provider_id', 'provider_network_id'],
+        ['region_id', 'site_id'],
+        ['tenant_group_id', 'tenant_id'],
+        ['tag']
+    ]
     type_id = DynamicModelMultipleChoiceField(
         queryset=CircuitType.objects.all(),
         required=False,

+ 106 - 59
netbox/dcim/forms.py

@@ -56,12 +56,12 @@ def get_device_by_name_or_pk(name):
 
 class DeviceComponentFilterForm(BootstrapMixin, CustomFieldFilterForm):
     field_order = [
-        'q', 'name', 'label', 'region_id', 'site_group_id', 'site_id',
+        'name', 'label', 'region_id', 'site_group_id', 'site_id',
+    ]
+    field_groups = [
+        ['name', 'label'],
+        ['region_id', 'site_group_id', 'site_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     name = forms.CharField(
         required=False
     )
@@ -232,10 +232,6 @@ class RegionBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 
 class RegionFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Site
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
 
 
 #
@@ -289,10 +285,6 @@ class SiteGroupBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 
 class SiteGroupFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = SiteGroup
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
 
 
 #
@@ -446,11 +438,12 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
 
 class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Site
-    field_order = ['q', 'status', 'region_id', 'tenant_group_id', 'tenant_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['status', 'region_id', 'tenant_group_id', 'tenant_id']
+    field_groups = [
+        ['status', 'region_id'],
+        ['tenant_group_id', 'tenant_id'],
+        ['tag']
+    ]
     status = forms.MultipleChoiceField(
         choices=SiteStatusChoices,
         required=False,
@@ -559,10 +552,6 @@ class LocationBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 
 class LocationFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Location
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -853,11 +842,12 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
 
 class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Rack
-    field_order = ['q', 'region_id', 'site_id', 'location_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['region_id', 'site_id', 'location_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id']
+    field_groups = [
+        ['status', 'role_id'],
+        ['region_id', 'site_id', 'location_id'],
+        ['tenant_group_id', 'tenant_id'],
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -913,7 +903,7 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 
 class RackElevationFilterForm(RackFilterForm):
     field_order = [
-        'q', 'region_id', 'site_id', 'location_id', 'id', 'status', 'role_id', 'tenant_group_id', 'tenant_id',
+        'region_id', 'site_id', 'location_id', 'id', 'status', 'role_id', 'tenant_group_id', 'tenant_id',
     ]
     id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
@@ -1071,11 +1061,11 @@ class RackReservationBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomField
 
 class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = RackReservation
-    field_order = ['q', 'region_id', 'site_id', 'location_id', 'user_id', 'tenant_group_id', 'tenant_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['region_id', 'site_id', 'location_id', 'user_id', 'tenant_group_id', 'tenant_id']
+    field_groups = [
+        ['region_id', 'site_id', 'location_id'],
+        ['user_id', 'tenant_group_id', 'tenant_id'],
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -1221,10 +1211,13 @@ class DeviceTypeBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkE
 
 class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = DeviceType
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['manufacturer_id', 'subdevice_role'],
+        ['console_ports', 'console_server_ports'],
+        ['power_ports', 'power_outlets'],
+        ['interfaces', 'pass_through_ports'],
+        ['tag']
+    ]
     manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         required=False,
@@ -2406,13 +2399,16 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
 class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldFilterForm):
     model = Device
     field_order = [
-        'q', 'region_id', 'site_id', 'location_id', 'rack_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id',
+        '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 = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['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'],
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -2583,6 +2579,12 @@ class DeviceBulkAddComponentForm(BootstrapMixin, CustomFieldForm, ComponentForm)
 
 class ConsolePortFilterForm(DeviceComponentFilterForm):
     model = ConsolePort
+    field_groups = [
+        ['name', 'label'],
+        ['type', 'speed'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag']
+    ]
     type = forms.MultipleChoiceField(
         choices=ConsolePortTypeChoices,
         required=False,
@@ -2684,6 +2686,12 @@ class ConsolePortCSVForm(CustomFieldModelCSVForm):
 
 class ConsoleServerPortFilterForm(DeviceComponentFilterForm):
     model = ConsoleServerPort
+    field_groups = [
+        ['name', 'label'],
+        ['type', 'speed'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag']
+    ]
     type = forms.MultipleChoiceField(
         choices=ConsolePortTypeChoices,
         required=False,
@@ -2785,6 +2793,11 @@ class ConsoleServerPortCSVForm(CustomFieldModelCSVForm):
 
 class PowerPortFilterForm(DeviceComponentFilterForm):
     model = PowerPort
+    field_groups = [
+        ['name', 'label', 'type'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag'],
+    ]
     type = forms.MultipleChoiceField(
         choices=PowerPortTypeChoices,
         required=False,
@@ -2883,6 +2896,11 @@ class PowerPortCSVForm(CustomFieldModelCSVForm):
 
 class PowerOutletFilterForm(DeviceComponentFilterForm):
     model = PowerOutlet
+    field_groups = [
+        ['name', 'label', 'type'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag'],
+    ]
     type = forms.MultipleChoiceField(
         choices=PowerOutletTypeChoices,
         required=False,
@@ -3050,6 +3068,12 @@ class PowerOutletCSVForm(CustomFieldModelCSVForm):
 
 class InterfaceFilterForm(DeviceComponentFilterForm):
     model = Interface
+    field_groups = [
+        ['name', 'label', 'type', 'enabled'],
+        ['mgmt_only', 'mac_address'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag'],
+    ]
     type = forms.MultipleChoiceField(
         choices=InterfaceTypeChoices,
         required=False,
@@ -3386,6 +3410,11 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
 #
 
 class FrontPortFilterForm(DeviceComponentFilterForm):
+    field_groups = [
+        ['name', 'label', 'type'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag']
+    ]
     model = FrontPort
     type = forms.MultipleChoiceField(
         choices=PortTypeChoices,
@@ -3560,6 +3589,11 @@ class FrontPortCSVForm(CustomFieldModelCSVForm):
 
 class RearPortFilterForm(DeviceComponentFilterForm):
     model = RearPort
+    field_groups = [
+        ['name', 'label', 'type'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag']
+    ]
     type = forms.MultipleChoiceField(
         choices=PortTypeChoices,
         required=False,
@@ -3649,6 +3683,11 @@ class RearPortCSVForm(CustomFieldModelCSVForm):
 
 class DeviceBayFilterForm(DeviceComponentFilterForm):
     model = DeviceBay
+    field_groups = [
+        ['name', 'label'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag']
+    ]
     tag = TagFilterField(model)
 
 
@@ -3872,6 +3911,12 @@ class InventoryItemBulkEditForm(
 
 class InventoryItemFilterForm(DeviceComponentFilterForm):
     model = InventoryItem
+    field_groups = [
+        ['name', 'label', 'manufacturer_id'],
+        ['serial', 'asset_tag', 'discovered'],
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tag']
+    ]
     manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         required=False,
@@ -4331,10 +4376,12 @@ class CableBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFo
 
 class CableFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Cable
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['type', 'status', 'color'],
+        ['device_id', 'rack_id'],
+        ['region_id', 'site_group_id', 'site_id', 'tenant_id'],
+        ['tag']
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -4707,11 +4754,12 @@ class VirtualChassisCSVForm(CustomFieldModelCSVForm):
 
 class VirtualChassisFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VirtualChassis
-    field_order = ['q', 'region_id', 'site_group_id', 'site_id', 'tenant_group_id', 'tenant_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['region_id', 'site_group_id', 'site_id', 'tenant_group_id', 'tenant_id']
+    field_groups = [
+        ['region_id', 'site_group_id', 'site_id'],
+        ['tenant_group_id', 'tenant_id'],
+        ['tag']
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -4848,10 +4896,6 @@ class PowerPanelBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkE
 
 class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = PowerPanel
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -5082,10 +5126,13 @@ class PowerFeedBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
 
 class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = PowerFeed
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['region_id', 'site_group_id', 'site_id'],
+        ['power_panel_id', 'rack_id'],
+        ['type', 'supply', 'max_utilization'],
+        ['phase', 'voltage', 'amperage'],
+        ['status', 'tag']
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,

+ 16 - 17
netbox/extras/forms.py

@@ -47,6 +47,7 @@ class CustomFieldModelForm(forms.ModelForm):
     """
     Extend ModelForm to include custom field support.
     """
+
     def __init__(self, *args, **kwargs):
 
         self.obj_type = ContentType.objects.get_for_model(self._meta.model)
@@ -176,10 +177,6 @@ class AddRemoveTagsForm(forms.Form):
 
 class TagFilterForm(BootstrapMixin, forms.Form):
     model = Tag
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
 
 
 class TagBulkEditForm(BootstrapMixin, BulkEditForm):
@@ -288,13 +285,15 @@ class ConfigContextBulkEditForm(BootstrapMixin, BulkEditForm):
 
 class ConfigContextFilterForm(BootstrapMixin, forms.Form):
     field_order = [
-        'q', 'region_id', 'site_group_id', 'site_id', 'role_id', 'platform_id', 'cluster_group_id', 'cluster_id',
+        'region_id', 'site_group_id', 'site_id', 'role_id', 'platform_id', 'cluster_group_id', 'cluster_id',
         'tenant_group_id', 'tenant_id',
     ]
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['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']
+    ]
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -422,10 +421,10 @@ class JournalEntryBulkEditForm(BootstrapMixin, BulkEditForm):
 
 class JournalEntryFilterForm(BootstrapMixin, forms.Form):
     model = JournalEntry
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['created_before', 'created_after', 'created_by_id'],
+        ['assigned_object_type_id', 'kind']
+    ]
     created_after = forms.DateTimeField(
         required=False,
         label=_('After'),
@@ -465,10 +464,10 @@ class JournalEntryFilterForm(BootstrapMixin, forms.Form):
 
 class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
     model = ObjectChange
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['time_before', 'time_after', 'action'],
+        ['user_id', 'changed_object_type_id'],
+    ]
     time_after = forms.DateTimeField(
         required=False,
         label=_('After'),

+ 40 - 34
netbox/ipam/forms.py

@@ -106,11 +106,12 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
 
 class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VRF
-    field_order = ['q', 'import_target_id', 'export_target_id', 'tenant_group_id', 'tenant_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['import_target_id', 'export_target_id', 'tenant_group_id', 'tenant_id']
+    field_groups = [
+        ['import_target_id', 'export_target_id'],
+        ['tenant_group_id', 'tenant_id'],
+        ['tag']
+    ]
     import_target_id = DynamicModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         required=False,
@@ -176,11 +177,11 @@ class RouteTargetBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulk
 
 class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = RouteTarget
-    field_order = ['q', 'name', 'tenant_group_id', 'tenant_id', 'importing_vrfs', 'exporting_vrfs']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['name', 'tenant_group_id', 'tenant_id', 'importing_vrfs', 'exporting_vrfs']
+    field_groups = [
+        ['name', 'importing_vrfs', 'exporting_vrfs'],
+        ['tenant_group_id', 'tenant_id'],
+    ]
     importing_vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         required=False,
@@ -330,11 +331,11 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
 
 class AggregateFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Aggregate
-    field_order = ['q', 'family', 'rir', 'tenant_group_id', 'tenant_id']
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_order = ['family', 'rir', 'tenant_group_id', 'tenant_id']
+    field_groups = [
+        ['family', 'rir'],
+        ['tenant_group_id', 'tenant_id']
+    ]
     family = forms.ChoiceField(
         required=False,
         choices=add_blank_choice(IPAddressFamilyChoices),
@@ -601,16 +602,18 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
 class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Prefix
     field_order = [
-        'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'region_id',
+        '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 = [
+        ['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']
+    ]
     mask_length__lte = forms.IntegerField(
         widget=forms.HiddenInput()
     )
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     within_include = forms.CharField(
         required=False,
         widget=forms.TextInput(
@@ -1087,13 +1090,15 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
 class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = IPAddress
     field_order = [
-        'q', 'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role',
+        'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role',
         'assigned_to_interface', 'tenant_group_id', 'tenant_id',
     ]
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['parent', 'family', 'mask_length'],
+        ['status', 'vrf_id', 'present_in_vrf_id'],
+        ['role', 'assigned_to_interface'],
+        ['tenant_group_id', 'tenant_id'],
+    ]
     parent = forms.CharField(
         required=False,
         widget=forms.TextInput(
@@ -1282,6 +1287,10 @@ class VLANGroupBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
 
 
 class VLANGroupFilterForm(BootstrapMixin, forms.Form):
+    field_groups = [
+        ['region', 'sitegroup', 'site'],
+        ['location', 'rack']
+    ]
     region = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -1488,12 +1497,13 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
 class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VLAN
     field_order = [
-        'q', 'region_id', 'site_group_id', 'site_id', 'group_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id',
+        'region_id', 'site_group_id', 'site_id', 'group_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id',
+    ]
+    field_groups = [
+        ['region_id', 'site_group_id', 'site_id'],
+        ['group_id', 'role_id', 'status'],
+        ['tenant_group_id', 'tenant_id'],
     ]
-    q = forms.CharField(
-        required=False,
-        label='Search'
-    )
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         required=False,
@@ -1585,10 +1595,6 @@ class ServiceForm(BootstrapMixin, CustomFieldModelForm):
 
 class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Service
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     protocol = forms.ChoiceField(
         choices=add_blank_choice(ServiceProtocolChoices),
         required=False,

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-dark.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-dark.css.map


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-light.css


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
netbox/project-static/dist/netbox-light.css.map


+ 4 - 0
netbox/project-static/netbox.scss

@@ -78,6 +78,10 @@ table td > .progress {
   min-width: 6rem;
 }
 
+div#advanced-search-content div.card div.card-body div.col:not(:last-child) {
+  margin-right: 1rem;
+}
+
 body {
   background-color: var(--nbx-body-bg);
   color: var(--nbx-body-color);

+ 24 - 4
netbox/templates/dcim/connections_list.html

@@ -6,17 +6,37 @@
 {% 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-9">
+    <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>
         </div>
         {% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
     </div>
-    <div class="col col-md-3 float-end right-side-panel noprint">
-        {% include 'inc/search_panel.html' %}
-    </div>
 </div>
 {% endblock %}

+ 6 - 3
netbox/templates/dcim/rack_elevation_list.html

@@ -7,6 +7,9 @@
 {% 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>
@@ -23,11 +26,11 @@
 {% 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">
-        <div class="col col-md-3 float-end right-side-panel noprint">
-            {% include 'inc/search_panel.html' %}
-        </div>
         {% if page %}
             <div style="white-space: nowrap; overflow-x: scroll;">
                 {% for rack in page %}

+ 16 - 8
netbox/templates/generic/object_list.html

@@ -24,6 +24,11 @@
 {% endblock controls %}
 
 {% block content %}
+{% if filter_form %}
+    <div class="col col-md-12 noprint">
+        {% include 'inc/advanced_search.html' %}
+    </div>
+{% 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 class="row mb-3">
@@ -56,11 +61,11 @@
 {% endwith %}
 {% endif %}
 <div class="row mb-3">
-    <div class="col{% if filter_form %} col-md-9{% else %} col-md-12{% endif %}">
+    <div class="col col-md-12">
         <div class="card">
             <div class="card-header">
                 <div class="row">
-                    <div class="col col-md-2 offset-md-10 noprint table-controls">
+                    <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 request.user.is_authenticated and table_config_form %}
@@ -68,6 +73,15 @@
                                     <i class="mdi mdi-table-eye"></i>
                                 </button>
                             {% endif %}
+                            {% 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>
@@ -103,12 +117,6 @@
             </div>
         </div>
     </div>
-    {% if filter_form %}
-    <div class="col col-md-3 noprint">
-        {% block sidebar %}{% endblock %}
-        {% include 'inc/search_panel.html' %}
-    </div>
-    {% endif %}
 </div>
 {% table_config_form table table_name="ObjectTable" %}
 {% endblock content %}

+ 62 - 0
netbox/templates/inc/advanced_search.html

@@ -0,0 +1,62 @@
+{% load form_helpers %}
+{% load helpers %}
+
+<div class="collapse" id="advanced-search-content">
+    <form action="." method="get">
+        <div class="card">
+            <h5 class="card-header">
+                Advanced Search
+            </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">
+                                {% 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="form-floating mb-3 mx-3">
+                                                {{ field }}
+                                                {{ field.label_tag }}
+                                            </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="form-floating mb-3">
+                                        {{ field }}
+                                        {{ field.label_tag }}
+                                    </div>
+                                {% endif %}
+                            </div>
+                        {% endfor %}
+                    {% endif %}
+            </div>
+            <div class="card-footer text-end noprint border-0">
+                <a href="." class="btn btn-sm btn-outline-dark m-1">
+                    <i class="mdi mdi-close"></i> Clear
+                </a>
+                <button type="submit" class="btn btn-sm btn-primary m-1">
+                    <i class="mdi mdi-magnify"></i> Search
+                </button>
+            </div>
+        </div>
+    </form>
+</div>

+ 0 - 42
netbox/templates/inc/search_panel.html

@@ -1,42 +0,0 @@
-{% load form_helpers %}
-
-<div class="card">
-    <h5 class="card-header">
-        Search
-    </h5>
-    <div class="card-body overflow-visible">
-        <form action="." method="get">
-            {% for field in filter_form.hidden_fields %}
-                {{ field }}
-            {% endfor %}
-            {% for field in filter_form.visible_fields %}
-                {% if field.name == "q" %}
-                <div class="input-group mb-3">
-                    <input type="text" name="q" class="form-control" placeholder="Search" {% if request.GET.q %}value="{{ request.GET.q }}" {% endif %}/>
-                    <button type="submit" class="btn btn-primary">
-                        <i class="mdi mdi-magnify"></i>
-                    </button>
-                </div>
-                {% elif 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="form-floating mb-3">
-                    {{ field }}
-                    {{ field.label_tag }}
-                </div>
-                {% endif %}
-            {% endfor %}
-        </form>
-    </div>
-    <div class="card-footer text-end noprint border-0">
-        <a href="." class="btn btn-sm btn-outline-dark m-1">
-            <i class="mdi mdi-close"></i> Clear
-        </a>
-        <button type="submit" class="btn btn-sm btn-primary m-1">
-            <i class="mdi mdi-magnify"></i> Apply
-        </button>
-    </div>
-</div>

+ 9 - 0
netbox/utilities/templatetags/helpers.py

@@ -249,6 +249,15 @@ def get_key(value: Dict, arg: str) -> Any:
     return value.get(arg, None)
 
 
+@register.filter
+def get_item(value: object, attr: str) -> Any:
+    """
+    Template implementation of `__getitem__`, for accessing the `__getitem__` method
+    of a class from a template.
+    """
+    return value[attr]
+
+
 #
 # Tags
 #

+ 21 - 10
netbox/virtualization/forms.py

@@ -224,12 +224,14 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
 class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Cluster
     field_order = [
-        'q', 'type_id', 'region_id', 'site_id', 'group_id', 'tenant_group_id', 'tenant_id',
+        'type_id', 'region_id', 'site_id', 'group_id', 'tenant_group_id', 'tenant_id',
+    ]
+    field_groups = [
+        ['type_id'],
+        ['region_id', 'site_id'],
+        ['tenant_group_id', 'tenant_id'],
+        ['tag'],
     ]
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
     type_id = DynamicModelMultipleChoiceField(
         queryset=ClusterType.objects.all(),
         required=False,
@@ -527,13 +529,17 @@ class VirtualMachineBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldB
 class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VirtualMachine
     field_order = [
-        'q', 'cluster_group_id', 'cluster_type_id', 'cluster_id', 'status', 'role_id', 'region_id', 'site_id',
+        'cluster_group_id', 'cluster_type_id', 'cluster_id', 'status', 'role_id', 'region_id', 'site_id',
         'tenant_group_id', 'tenant_id', 'platform_id', 'mac_address',
     ]
-    q = forms.CharField(
-        required=False,
-        label=_('Search')
-    )
+    field_groups = [
+        ['status', 'role_id'],
+        ['platform_id', 'mac_address'],
+        ['cluster_group_id', 'cluster_type_id', 'cluster_id'],
+        ['region_id', 'site_id'],
+        ['tenant_group_id', 'tenant_id'],
+
+    ]
     cluster_group_id = DynamicModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         required=False,
@@ -830,6 +836,11 @@ class VMInterfaceBulkRenameForm(BulkRenameForm):
 
 class VMInterfaceFilterForm(BootstrapMixin, forms.Form):
     model = VMInterface
+    field_groups = [
+        ['cluster_id', 'virtual_machine_id'],
+        ['enabled', 'mac_address'],
+        ['tag']
+    ]
     cluster_id = DynamicModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         required=False,

Некоторые файлы не были показаны из-за большого количества измененных файлов