diff --git a/netbox/circuits/forms/filtersets.py b/netbox/circuits/forms/filtersets.py index c71f5c65c..ec754f697 100644 --- a/netbox/circuits/forms/filtersets.py +++ b/netbox/circuits/forms/filtersets.py @@ -34,9 +34,10 @@ __all__ = ( class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): model = Provider fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet('asn_id', name=_('ASN')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) region_id = DynamicModelMultipleChoiceField( @@ -69,8 +70,9 @@ class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): model = ProviderAccount fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('provider_id', 'account', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) provider_id = DynamicModelMultipleChoiceField( @@ -88,8 +90,9 @@ class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetFor class ProviderNetworkFilterForm(PrimaryModelFilterSetForm): model = ProviderNetwork fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('provider_id', 'service_id', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) provider_id = DynamicModelMultipleChoiceField( queryset=Provider.objects.all(), @@ -107,8 +110,9 @@ class ProviderNetworkFilterForm(PrimaryModelFilterSetForm): class CircuitTypeFilterForm(OrganizationalModelFilterSetForm): model = CircuitType fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('color', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -121,7 +125,7 @@ class CircuitTypeFilterForm(OrganizationalModelFilterSetForm): class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm): model = Circuit fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), FieldSet( 'type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit', @@ -129,6 +133,7 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelF ), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'provider_id', 'provider_network_id') @@ -274,8 +279,9 @@ class CircuitTerminationFilterForm(NetBoxModelFilterSetForm): class CircuitGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm): model = CircuitGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -312,8 +318,9 @@ class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm): class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm): model = VirtualCircuitType fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('color', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -326,10 +333,11 @@ class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm): class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm): model = VirtualCircuit fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), FieldSet('type_id', 'status', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'provider_id', 'provider_network_id') provider_id = DynamicModelMultipleChoiceField( diff --git a/netbox/core/forms/filtersets.py b/netbox/core/forms/filtersets.py index 69e6a4fbb..90908e479 100644 --- a/netbox/core/forms/filtersets.py +++ b/netbox/core/forms/filtersets.py @@ -26,8 +26,9 @@ __all__ = ( class DataSourceFilterForm(PrimaryModelFilterSetForm): model = DataSource fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) type = forms.MultipleChoiceField( label=_('Type'), diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 63f59c6c8..34cefc6b5 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -14,9 +14,9 @@ from netbox.forms import ( ) from tenancy.forms import ContactModelFilterForm, TenancyFilterForm from tenancy.models import Tenant -from users.models import Owner, User +from users.models import OwnerGroup, Owner, User from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice -from utilities.forms.fields import ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField +from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField from utilities.forms.rendering import FieldSet from utilities.forms.widgets import NumberWithOptions from virtualization.models import Cluster, ClusterGroup, VirtualMachine @@ -70,7 +70,7 @@ __all__ = ( 'SiteFilterForm', 'SiteGroupFilterForm', 'VirtualChassisFilterForm', - 'VirtualDeviceContextFilterForm' + 'VirtualDeviceContextFilterForm', ) @@ -157,9 +157,19 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm): required=False, label=_('Device Status'), ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -167,8 +177,9 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm): class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm): model = Region fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('parent_id', name=_('Region')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) ) parent_id = DynamicModelMultipleChoiceField( @@ -182,8 +193,9 @@ class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm): class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm): model = SiteGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('parent_id', name=_('Site Group')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) ) parent_id = DynamicModelMultipleChoiceField( @@ -197,9 +209,10 @@ class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm) class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm): model = Site fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('status', 'region_id', 'group_id', 'asn_id', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) selector_fields = ('filter_id', 'q', 'region_id', 'group_id') @@ -229,9 +242,10 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilt class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupModelFilterSetForm): model = Location fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', 'parent_id', 'status', 'facility', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) region_id = DynamicModelMultipleChoiceField( @@ -277,7 +291,8 @@ class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupM class RackRoleFilterForm(OrganizationalModelFilterSetForm): model = RackRole fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -328,10 +343,11 @@ class RackBaseFilterForm(PrimaryModelFilterSetForm): class RackTypeFilterForm(RackBaseFilterForm): model = RackType fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('manufacturer_id', 'form_factor', 'width', 'u_height', 'rack_count', name=_('Rack Type')), FieldSet('starting_unit', 'desc_units', name=_('Numbering')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'manufacturer_id') manufacturer_id = DynamicModelMultipleChoiceField( @@ -350,13 +366,14 @@ class RackTypeFilterForm(RackBaseFilterForm): class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm): model = Rack fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('status', 'role_id', 'manufacturer_id', 'rack_type_id', 'serial', 'asset_tag', name=_('Rack')), FieldSet('form_factor', 'width', 'u_height', 'airflow', name=_('Hardware')), FieldSet('starting_unit', 'desc_units', name=_('Numbering')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'location_id') @@ -433,9 +450,10 @@ class RackElevationFilterForm(RackFilterForm): FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'id', name=_('Location')), FieldSet('status', 'role_id', name=_('Function')), FieldSet('type', 'width', 'serial', 'asset_tag', name=_('Hardware')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), - FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), + FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) id = DynamicModelMultipleChoiceField( queryset=Rack.objects.all(), @@ -451,10 +469,11 @@ class RackElevationFilterForm(RackFilterForm): class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = RackReservation fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('status', 'user_id', name=_('Reservation')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -509,7 +528,8 @@ class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm): model = Manufacturer fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) ) tag = TagFilterField(model) @@ -518,7 +538,7 @@ class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe class DeviceTypeFilterForm(PrimaryModelFilterSetForm): model = DeviceType fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet( 'manufacturer_id', 'default_platform_id', 'part_number', 'device_count', 'subdevice_role', 'airflow', name=_('Hardware') @@ -529,6 +549,7 @@ class DeviceTypeFilterForm(PrimaryModelFilterSetForm): 'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items', name=_('Components') ), FieldSet('weight', 'weight_unit', name=_('Weight')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'manufacturer_id') manufacturer_id = DynamicModelMultipleChoiceField( @@ -652,7 +673,8 @@ class DeviceTypeFilterForm(PrimaryModelFilterSetForm): class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm): model = ModuleTypeProfile fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q') tag = TagFilterField(model) @@ -661,7 +683,7 @@ class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm): class ModuleTypeFilterForm(PrimaryModelFilterSetForm): model = ModuleType fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet( 'profile_id', 'manufacturer_id', 'part_number', 'module_count', 'airflow', name=_('Hardware') @@ -671,6 +693,7 @@ class ModuleTypeFilterForm(PrimaryModelFilterSetForm): 'pass_through_ports', name=_('Components') ), FieldSet('weight', 'weight_unit', name=_('Weight')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'manufacturer_id') profile_id = DynamicModelMultipleChoiceField( @@ -754,8 +777,9 @@ class ModuleTypeFilterForm(PrimaryModelFilterSetForm): class DeviceRoleFilterForm(NestedGroupModelFilterSetForm): model = DeviceRole fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), - FieldSet('parent_id', 'config_template_id', name=_('Device Role')) + FieldSet('q', 'filter_id', 'tag'), + FieldSet('parent_id', 'config_template_id', name=_('Device Role')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) config_template_id = DynamicModelMultipleChoiceField( queryset=ConfigTemplate.objects.all(), @@ -773,8 +797,9 @@ class DeviceRoleFilterForm(NestedGroupModelFilterSetForm): class PlatformFilterForm(NestedGroupModelFilterSetForm): model = Platform fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), - FieldSet('manufacturer_id', 'parent_id', 'config_template_id', name=_('Platform')) + FieldSet('q', 'filter_id', 'tag'), + FieldSet('manufacturer_id', 'parent_id', 'config_template_id', name=_('Platform')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'manufacturer_id') parent_id = DynamicModelMultipleChoiceField( @@ -803,11 +828,12 @@ class DeviceFilterForm( ): model = Device fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address', name=_('Operation')), FieldSet('manufacturer_id', 'device_type_id', 'platform_id', name=_('Hardware')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet( 'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports', @@ -996,9 +1022,10 @@ class DeviceFilterForm( class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = VirtualDeviceContext fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('device', 'status', 'has_primary_ip', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) device = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), @@ -1023,9 +1050,10 @@ class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetFor class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = Module fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')), FieldSet('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag', name=_('Hardware')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) device_id = DynamicModelMultipleChoiceField( queryset=Device.objects.all(), @@ -1106,9 +1134,10 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryM class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = VirtualChassis fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -1135,10 +1164,11 @@ class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = Cable fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')), FieldSet('type', 'status', 'profile', 'color', 'length', 'length_unit', 'unterminated', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -1224,8 +1254,9 @@ class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): model = PowerPanel fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) selector_fields = ('filter_id', 'q', 'site_id', 'location_id') @@ -1263,10 +1294,11 @@ class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): class PowerFeedFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = PowerFeed fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id', name=_('Location')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', name=_('Attributes')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) region_id = DynamicModelMultipleChoiceField( queryset=Region.objects.all(), @@ -1390,7 +1422,7 @@ class PathEndpointFilterForm(CabledFilterForm): class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = ConsolePort fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( @@ -1398,6 +1430,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): name=_('Device') ), FieldSet('cabled', 'connected', 'occupied', name=_('Connection')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) type = forms.MultipleChoiceField( label=_('Type'), @@ -1429,7 +1462,7 @@ class ConsolePortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = ConsoleServerPort fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( @@ -1437,6 +1470,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF name=_('Device') ), FieldSet('cabled', 'connected', 'occupied', name=_('Connection')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) type = forms.MultipleChoiceField( label=_('Type'), @@ -1468,7 +1502,7 @@ class ConsoleServerPortTemplateFilterForm(ModularDeviceComponentTemplateFilterFo class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = PowerPort fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'type', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( @@ -1476,6 +1510,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): name=_('Device') ), FieldSet('cabled', 'connected', 'occupied', name=_('Connection')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) type = forms.MultipleChoiceField( label=_('Type'), @@ -1502,7 +1537,7 @@ class PowerPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = PowerOutlet fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( @@ -1510,6 +1545,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): name=_('Device') ), FieldSet('cabled', 'connected', 'occupied', name=_('Connection')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) type = forms.MultipleChoiceField( label=_('Type'), @@ -1545,7 +1581,7 @@ class PowerOutletTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): model = Interface fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only', name=_('Attributes')), FieldSet('vrf_id', 'l2vpn_id', 'mac_address', 'wwn', name=_('Addressing')), FieldSet('poe_mode', 'poe_type', name=_('PoE')), @@ -1558,6 +1594,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): name=_('Device') ), FieldSet('cabled', 'connected', 'occupied', name=_('Connection')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'device_id') vdc_id = DynamicModelMultipleChoiceField( @@ -1716,7 +1753,7 @@ class InterfaceTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'type', 'color', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( @@ -1724,6 +1761,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): name=_('Device') ), FieldSet('cabled', 'occupied', name=_('Cable')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) model = FrontPort type = forms.MultipleChoiceField( @@ -1759,7 +1797,7 @@ class FrontPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): model = RearPort fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'type', 'color', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( @@ -1767,6 +1805,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): name=_('Device') ), FieldSet('cabled', 'occupied', name=_('Cable')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) type = forms.MultipleChoiceField( label=_('Type'), @@ -1801,13 +1840,14 @@ class RearPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class ModuleBayFilterForm(DeviceComponentFilterForm): model = ModuleBay fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', 'position', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( 'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id', name=_('Device') ), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) position = forms.CharField( @@ -1832,13 +1872,14 @@ class ModuleBayTemplateFilterForm(ModularDeviceComponentTemplateFilterForm): class DeviceBayFilterForm(DeviceComponentFilterForm): model = DeviceBay fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'label', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet( 'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id', name=_('Device') ), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -1855,7 +1896,7 @@ class DeviceBayTemplateFilterForm(DeviceComponentTemplateFilterForm): class InventoryItemFilterForm(DeviceComponentFilterForm): model = InventoryItem fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet( 'name', 'label', 'status', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered', name=_('Attributes') @@ -1865,6 +1906,7 @@ class InventoryItemFilterForm(DeviceComponentFilterForm): 'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id', name=_('Device') ), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) role_id = DynamicModelMultipleChoiceField( queryset=InventoryItemRole.objects.all(), @@ -1925,7 +1967,8 @@ class InventoryItemTemplateFilterForm(DeviceComponentTemplateFilterForm): class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm): model = InventoryItemRole fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -1937,9 +1980,10 @@ class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm): class MACAddressFilterForm(PrimaryModelFilterSetForm): model = MACAddress fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('mac_address', name=_('Attributes')), FieldSet('device_id', 'virtual_machine_id', 'assigned', 'primary', name=_('Assignments')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id') mac_address = forms.CharField( diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index 8e0818326..2354ee5c5 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _ from dcim.models import * from netbox.forms import NetBoxModelForm +from netbox.forms.mixins import OwnerMixin from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField from utilities.forms.rendering import FieldSet, TabbedGroups from utilities.forms.widgets import APISelect @@ -271,7 +272,7 @@ class InventoryItemCreateForm(ComponentCreateForm, model_forms.InventoryItemForm # Virtual chassis # -class VirtualChassisCreateForm(NetBoxModelForm): +class VirtualChassisCreateForm(OwnerMixin, NetBoxModelForm): region = DynamicModelChoiceField( label=_('Region'), queryset=Region.objects.all(), diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index 0a3036597..b40742758 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -9,11 +9,10 @@ from netbox.events import get_event_type_choices from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm from netbox.forms.mixins import SavedFiltersMixin from tenancy.models import Tenant, TenantGroup -from users.models import Group, Owner, User +from users.models import Group, OwnerGroup, Owner, User from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice from utilities.forms.fields import ( - ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, - TagFilterField, + ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField, ) from utilities.forms.rendering import FieldSet from utilities.forms.widgets import DateTimePicker @@ -47,6 +46,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): FieldSet('choice_set_id', 'related_object_type_id', name=_('Type Options')), FieldSet('ui_visible', 'ui_editable', 'is_cloneable', name=_('Behavior')), FieldSet('validation_minimum', 'validation_maximum', 'validation_regex', name=_('Validation')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) object_type_id = ContentTypeMultipleChoiceField( queryset=ObjectType.objects.with_feature('custom_fields'), @@ -119,9 +119,19 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): label=_('Validation regex'), required=False ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -131,6 +141,7 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( FieldSet('q', 'filter_id'), FieldSet('base_choices', 'choice', name=_('Choices')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) base_choices = forms.MultipleChoiceField( choices=CustomFieldChoiceSetBaseChoices, @@ -139,9 +150,19 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm): choice = forms.CharField( required=False ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -151,6 +172,7 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( FieldSet('q', 'filter_id'), FieldSet('object_type_id', 'enabled', 'new_window', 'weight', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) object_type_id = ContentTypeMultipleChoiceField( label=_('Object types'), @@ -175,9 +197,19 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): label=_('Weight'), required=False ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -188,6 +220,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): FieldSet('q', 'filter_id', 'object_type_id'), FieldSet('data_source_id', 'data_file_id', name=_('Data')), FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -226,9 +259,19 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): choices=BOOLEAN_WITH_BLANK_CHOICES ) ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -255,6 +298,7 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( FieldSet('q', 'filter_id'), FieldSet('object_type_id', 'enabled', 'shared', 'weight', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) object_type_id = ContentTypeMultipleChoiceField( label=_('Object types'), @@ -279,9 +323,19 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): label=_('Weight'), required=False ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -320,8 +374,9 @@ class TableConfigFilterForm(SavedFiltersMixin, FilterForm): class WebhookFilterForm(NetBoxModelFilterSetForm): model = Webhook fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) http_content_type = forms.CharField( label=_('HTTP content type'), @@ -336,9 +391,19 @@ class WebhookFilterForm(NetBoxModelFilterSetForm): required=False, label=_('HTTP method') ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) tag = TagFilterField(model) @@ -347,8 +412,9 @@ class WebhookFilterForm(NetBoxModelFilterSetForm): class EventRuleFilterForm(NetBoxModelFilterSetForm): model = EventRule fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('object_type_id', 'event_type', 'action_type', 'enabled', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) object_type_id = ContentTypeMultipleChoiceField( queryset=ObjectType.objects.with_feature('event_rules'), @@ -372,9 +438,19 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm): choices=BOOLEAN_WITH_BLANK_CHOICES ) ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) tag = TagFilterField(model) @@ -382,6 +458,11 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm): class TagFilterForm(SavedFiltersMixin, FilterForm): model = Tag + fieldsets = ( + FieldSet('q', 'filter_id'), + FieldSet('content_type_id', 'for_object_type_id', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), + ) content_type_id = ContentTypeMultipleChoiceField( queryset=ObjectType.objects.with_feature('tags'), required=False, @@ -392,9 +473,19 @@ class TagFilterForm(SavedFiltersMixin, FilterForm): required=False, label=_('Allowed object type') ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -404,6 +495,7 @@ class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm): fieldsets = ( FieldSet('q', 'filter_id'), FieldSet('data_source_id', 'data_file_id', name=_('Data')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -418,18 +510,34 @@ class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm): 'source_id': '$data_source_id' } ) + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( + queryset=Owner.objects.all(), + required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, + label=_('Owner'), + ) class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): model = ConfigContext fieldsets = ( FieldSet('q', 'filter_id', 'tag_id'), - FieldSet('profile', name=_('Config Context')), + FieldSet('profile_id', name=_('Config Context')), FieldSet('data_source_id', 'data_file_id', name=_('Data')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), FieldSet('device_type_id', 'platform_id', 'device_role_id', name=_('Device')), FieldSet('cluster_type_id', 'cluster_group_id', 'cluster_id', name=_('Cluster')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')) + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) profile_id = DynamicModelMultipleChoiceField( queryset=ConfigContextProfile.objects.all(), @@ -514,9 +622,19 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): required=False, label=_('Tags') ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) @@ -526,7 +644,8 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( FieldSet('q', 'filter_id', 'tag'), FieldSet('data_source_id', 'data_file_id', 'auto_sync_enabled', name=_('Data')), - FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')) + FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -568,9 +687,19 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): choices=BOOLEAN_WITH_BLANK_CHOICES ) ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 68151c80b..b0252962e 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -178,6 +178,13 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, OwnerMixin, forms.ModelFor ) + ' choice1:First Choice') ) + fieldsets = ( + FieldSet( + 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', + name=_('Custom Field Choice Set') + ), + ) + class Meta: model = CustomFieldChoiceSet fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner') diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py index dd2987f28..e37d17d4b 100644 --- a/netbox/ipam/forms/filtersets.py +++ b/netbox/ipam/forms/filtersets.py @@ -45,9 +45,10 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([ class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = VRF fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('import_target_id', 'export_target_id', name=_('Route Targets')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) import_target_id = DynamicModelMultipleChoiceField( queryset=RouteTarget.objects.all(), @@ -65,9 +66,10 @@ class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = RouteTarget fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('importing_vrf_id', 'exporting_vrf_id', name=_('VRF')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) importing_vrf_id = DynamicModelMultipleChoiceField( queryset=VRF.objects.all(), @@ -85,8 +87,9 @@ class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class RIRFilterForm(OrganizationalModelFilterSetForm): model = RIR fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('is_private', name=_('RIR')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) is_private = forms.NullBooleanField( required=False, @@ -101,9 +104,10 @@ class RIRFilterForm(OrganizationalModelFilterSetForm): class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = Aggregate fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('family', 'rir_id', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) family = forms.ChoiceField( @@ -122,9 +126,10 @@ class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryMode class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm): model = ASNRange fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('rir_id', 'start', 'end', name=_('Range')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) rir_id = DynamicModelMultipleChoiceField( queryset=RIR.objects.all(), @@ -145,9 +150,10 @@ class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm): class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = ASN fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('rir_id', 'site_group_id', 'site_id', name=_('Assignment')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) rir_id = DynamicModelMultipleChoiceField( queryset=RIR.objects.all(), @@ -170,7 +176,8 @@ class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class RoleFilterForm(OrganizationalModelFilterSetForm): model = Role fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -178,7 +185,7 @@ class RoleFilterForm(OrganizationalModelFilterSetForm): class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = Prefix fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet( 'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized', name=_('Addressing') @@ -187,6 +194,7 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFi FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) mask_length__lte = forms.IntegerField( @@ -284,9 +292,10 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFi class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = IPRange fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) family = forms.ChoiceField( @@ -331,14 +340,15 @@ class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelF class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = IPAddress fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet( 'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name', name=_('Attributes') ), FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role') @@ -409,9 +419,10 @@ class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryMode class FHRPGroupFilterForm(PrimaryModelFilterSetForm): model = FHRPGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', 'protocol', 'group_id', name=_('Attributes')), FieldSet('auth_type', 'auth_key', name=_('Authentication')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) name = forms.CharField( label=_('Name'), @@ -441,11 +452,12 @@ class FHRPGroupFilterForm(PrimaryModelFilterSetForm): class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm): fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region', 'site_group', 'site', 'location', 'rack', name=_('Location')), FieldSet('cluster_group', 'cluster', name=_('Cluster')), FieldSet('contains_vid', name=_('VLANs')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) model = VLANGroup region = DynamicModelMultipleChoiceField( @@ -495,8 +507,9 @@ class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm): class VLANTranslationPolicyFilterForm(PrimaryModelFilterSetForm): model = VLANTranslationPolicy fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('name', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) name = forms.CharField( required=False, @@ -532,11 +545,12 @@ class VLANTranslationRuleFilterForm(NetBoxModelFilterSetForm): class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = VLAN fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet('group_id', 'status', 'role_id', 'vid', 'l2vpn_id', name=_('Attributes')), FieldSet('qinq_role', 'qinq_svlan_id', name=_('Q-in-Q/802.1ad')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'group_id') region_id = DynamicModelMultipleChoiceField( @@ -604,8 +618,9 @@ class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class ServiceTemplateFilterForm(PrimaryModelFilterSetForm): model = ServiceTemplate fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('protocol', 'port', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) protocol = forms.ChoiceField( label=_('Protocol'), @@ -622,9 +637,10 @@ class ServiceTemplateFilterForm(PrimaryModelFilterSetForm): class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm): model = Service fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('protocol', 'port', name=_('Attributes')), FieldSet('device_id', 'virtual_machine_id', 'fhrpgroup_id', name=_('Assignment')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) device_id = DynamicModelMultipleChoiceField( diff --git a/netbox/netbox/forms/filtersets.py b/netbox/netbox/forms/filtersets.py index d334ee914..156fdc11c 100644 --- a/netbox/netbox/forms/filtersets.py +++ b/netbox/netbox/forms/filtersets.py @@ -3,8 +3,8 @@ from django.db.models import Q from django.utils.translation import gettext_lazy as _ from extras.choices import * -from users.models import Owner -from utilities.forms.fields import DynamicModelChoiceField, QueryField +from users.models import OwnerGroup, Owner +from utilities.forms.fields import DynamicModelMultipleChoiceField, QueryField from utilities.forms.mixins import FilterModifierMixin from .mixins import CustomFieldsMixin, SavedFiltersMixin @@ -48,9 +48,19 @@ class NetBoxModelFilterSetForm(FilterModifierMixin, CustomFieldsMixin, SavedFilt class OwnerFilterMixin(forms.Form): - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) diff --git a/netbox/netbox/forms/mixins.py b/netbox/netbox/forms/mixins.py index 4ee11b0bb..b960424a0 100644 --- a/netbox/netbox/forms/mixins.py +++ b/netbox/netbox/forms/mixins.py @@ -4,7 +4,7 @@ from django.utils.translation import gettext as _ from core.models import ObjectType from extras.choices import * from extras.models import * -from users.models import Owner +from users.models import OwnerGroup, Owner from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField __all__ = ( @@ -126,8 +126,17 @@ class OwnerMixin(forms.Form): """ Add an `owner` field to forms for models which support Owner assignment. """ + + owner_group = DynamicModelChoiceField( + label=_('Owner group'), + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + initial_params={'members': '$owner'}, + ) owner = DynamicModelChoiceField( queryset=Owner.objects.all(), required=False, + query_params={'group_id': '$owner_group'}, label=_('Owner'), ) diff --git a/netbox/netbox/tables/tables.py b/netbox/netbox/tables/tables.py index a2ba13480..264e1fb05 100644 --- a/netbox/netbox/tables/tables.py +++ b/netbox/netbox/tables/tables.py @@ -271,9 +271,14 @@ class NetBoxTable(BaseTable): class PrimaryModelTable(NetBoxTable): + owner_group = tables.Column( + accessor='owner__group', + linkify=True, + verbose_name=_('Owner Group'), + ) owner = tables.Column( linkify=True, - verbose_name=_('Owner') + verbose_name=_('Owner'), ) comments = columns.MarkdownColumn( verbose_name=_('Comments'), @@ -281,9 +286,14 @@ class PrimaryModelTable(NetBoxTable): class OrganizationalModelTable(NetBoxTable): + owner_group = tables.Column( + accessor='owner__group', + linkify=True, + verbose_name=_('Owner Group'), + ) owner = tables.Column( linkify=True, - verbose_name=_('Owner') + verbose_name=_('Owner'), ) comments = columns.MarkdownColumn( verbose_name=_('Comments'), @@ -291,9 +301,14 @@ class OrganizationalModelTable(NetBoxTable): class NestedGroupModelTable(NetBoxTable): + owner_group = tables.Column( + accessor='owner__group', + linkify=True, + verbose_name=_('Owner Group'), + ) owner = tables.Column( linkify=True, - verbose_name=_('Owner') + verbose_name=_('Owner'), ) name = columns.MPTTColumn( verbose_name=_('Name'), diff --git a/netbox/templates/dcim/device_edit.html b/netbox/templates/dcim/device_edit.html index 454faf8fb..e0d6b30f6 100644 --- a/netbox/templates/dcim/device_edit.html +++ b/netbox/templates/dcim/device_edit.html @@ -101,8 +101,9 @@
-

{% trans "Owner" %}

+

{% trans "Ownership" %}

+ {% render_field form.owner_group %} {% render_field form.owner %}
diff --git a/netbox/templates/dcim/htmx/cable_edit.html b/netbox/templates/dcim/htmx/cable_edit.html index 4e4043c4d..45d528217 100644 --- a/netbox/templates/dcim/htmx/cable_edit.html +++ b/netbox/templates/dcim/htmx/cable_edit.html @@ -80,8 +80,9 @@
-

{% trans "Owner" %}

+

{% trans "Ownership" %}

+ {% render_field form.owner_group %} {% render_field form.owner %}
diff --git a/netbox/templates/dcim/virtualchassis_edit.html b/netbox/templates/dcim/virtualchassis_edit.html index 8744947fa..be55c5f11 100644 --- a/netbox/templates/dcim/virtualchassis_edit.html +++ b/netbox/templates/dcim/virtualchassis_edit.html @@ -38,6 +38,7 @@

{% trans "Owner" %}

+ {% render_field vc_form.owner_group %} {% render_field vc_form.owner %} diff --git a/netbox/templates/htmx/form.html b/netbox/templates/htmx/form.html index c4022cbc2..a6b5dc9c2 100644 --- a/netbox/templates/htmx/form.html +++ b/netbox/templates/htmx/form.html @@ -27,6 +27,9 @@

{% trans "Ownership" %}

+ {% if form.owner_group %} + {% render_field form.owner_group %} + {% endif %} {% render_field form.owner %} {% endif %} diff --git a/netbox/templates/ipam/vlan_edit.html b/netbox/templates/ipam/vlan_edit.html index 623468af2..7c20c801b 100644 --- a/netbox/templates/ipam/vlan_edit.html +++ b/netbox/templates/ipam/vlan_edit.html @@ -67,8 +67,9 @@
-

{% trans "Owner" %}

+

{% trans "Ownership" %}

+ {% render_field form.owner_group %} {% render_field form.owner %}
diff --git a/netbox/tenancy/forms/filtersets.py b/netbox/tenancy/forms/filtersets.py index 239a765c6..78057d4e4 100644 --- a/netbox/tenancy/forms/filtersets.py +++ b/netbox/tenancy/forms/filtersets.py @@ -31,8 +31,9 @@ __all__ = ( class TenantGroupFilterForm(NestedGroupModelFilterSetForm): model = TenantGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('parent_id', name=_('Tenant Group')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) parent_id = DynamicModelMultipleChoiceField( queryset=TenantGroup.objects.all(), @@ -45,8 +46,9 @@ class TenantGroupFilterForm(NestedGroupModelFilterSetForm): class TenantFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): model = Tenant fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('group_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) ) group_id = DynamicModelMultipleChoiceField( @@ -65,8 +67,9 @@ class TenantFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm): class ContactGroupFilterForm(NestedGroupModelFilterSetForm): model = ContactGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('parent_id', name=_('Contact Group')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) parent_id = DynamicModelMultipleChoiceField( queryset=ContactGroup.objects.all(), @@ -79,7 +82,8 @@ class ContactGroupFilterForm(NestedGroupModelFilterSetForm): class ContactRoleFilterForm(OrganizationalModelFilterSetForm): model = ContactRole fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -87,8 +91,9 @@ class ContactRoleFilterForm(OrganizationalModelFilterSetForm): class ContactFilterForm(PrimaryModelFilterSetForm): model = Contact fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('group_id', name=_('Contact')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) group_id = DynamicModelMultipleChoiceField( queryset=ContactGroup.objects.all(), diff --git a/netbox/users/filterset_mixins.py b/netbox/users/filterset_mixins.py index 33eb6f743..f076a2420 100644 --- a/netbox/users/filterset_mixins.py +++ b/netbox/users/filterset_mixins.py @@ -1,7 +1,7 @@ import django_filters from django.utils.translation import gettext as _ -from users.models import Owner +from users.models import OwnerGroup, Owner __all__ = ( 'OwnerFilterMixin', @@ -12,6 +12,17 @@ class OwnerFilterMixin(django_filters.FilterSet): """ Adds owner & owner_id filters for models which inherit from OwnerMixin. """ + owner_group_id = django_filters.ModelMultipleChoiceFilter( + queryset=OwnerGroup.objects.all(), + field_name='owner__group', + label=_('Owner Group (ID)'), + ) + owner_group = django_filters.ModelMultipleChoiceFilter( + queryset=OwnerGroup.objects.all(), + field_name='owner__group', + to_field_name='name', + label=_('Owner Group (name)'), + ) owner_id = django_filters.ModelMultipleChoiceFilter( queryset=Owner.objects.all(), label=_('Owner (ID)'), diff --git a/netbox/virtualization/forms/filtersets.py b/netbox/virtualization/forms/filtersets.py index 27fda4a85..a1570d7c2 100644 --- a/netbox/virtualization/forms/filtersets.py +++ b/netbox/virtualization/forms/filtersets.py @@ -8,9 +8,9 @@ from extras.models import ConfigTemplate from ipam.models import VRF, VLANTranslationPolicy from netbox.forms import NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm, PrimaryModelFilterSetForm from tenancy.forms import ContactModelFilterForm, TenancyFilterForm -from users.models import Owner +from users.models import OwnerGroup, Owner from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES -from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField +from utilities.forms.fields import DynamicModelMultipleChoiceField, TagFilterField from utilities.forms.rendering import FieldSet from virtualization.choices import * from virtualization.models import * @@ -29,7 +29,8 @@ __all__ = ( class ClusterTypeFilterForm(OrganizationalModelFilterSetForm): model = ClusterType fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) tag = TagFilterField(model) @@ -38,7 +39,8 @@ class ClusterGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe model = ClusterGroup tag = TagFilterField(model) fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) @@ -46,10 +48,11 @@ class ClusterGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm): model = Cluster fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('group_id', 'type_id', 'status', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) selector_fields = ('filter_id', 'q', 'group_id') @@ -105,7 +108,7 @@ class VirtualMachineFilterForm( ): model = VirtualMachine fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id', name=_('Cluster')), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet( @@ -113,6 +116,7 @@ class VirtualMachineFilterForm( 'local_context_data', 'serial', name=_('Attributes') ), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) cluster_group_id = DynamicModelMultipleChoiceField( @@ -208,11 +212,12 @@ class VirtualMachineFilterForm( class VMInterfaceFilterForm(NetBoxModelFilterSetForm): model = VMInterface fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('cluster_id', 'virtual_machine_id', name=_('Virtual Machine')), FieldSet('enabled', name=_('Attributes')), FieldSet('vrf_id', 'l2vpn_id', 'mac_address', name=_('Addressing')), FieldSet('mode', 'vlan_translation_policy_id', name=_('802.1Q Switching')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) selector_fields = ('filter_id', 'q', 'virtual_machine_id') cluster_id = DynamicModelMultipleChoiceField( @@ -259,9 +264,19 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm): required=False, label=_('VLAN Translation Policy') ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) tag = TagFilterField(model) @@ -270,9 +285,10 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm): class VirtualDiskFilterForm(NetBoxModelFilterSetForm): model = VirtualDisk fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('virtual_machine_id', name=_('Virtual Machine')), FieldSet('size', name=_('Attributes')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) virtual_machine_id = DynamicModelMultipleChoiceField( queryset=VirtualMachine.objects.all(), @@ -284,9 +300,19 @@ class VirtualDiskFilterForm(NetBoxModelFilterSetForm): required=False, min_value=1 ) - owner_id = DynamicModelChoiceField( + owner_group_id = DynamicModelMultipleChoiceField( + queryset=OwnerGroup.objects.all(), + required=False, + null_option='None', + label=_('Owner Group'), + ) + owner_id = DynamicModelMultipleChoiceField( queryset=Owner.objects.all(), required=False, + null_option='None', + query_params={ + 'group_id': '$owner_group_id' + }, label=_('Owner'), ) tag = TagFilterField(model) diff --git a/netbox/vpn/forms/filtersets.py b/netbox/vpn/forms/filtersets.py index 6108b1389..f47000e92 100644 --- a/netbox/vpn/forms/filtersets.py +++ b/netbox/vpn/forms/filtersets.py @@ -33,7 +33,8 @@ __all__ = ( class TunnelGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm): model = TunnelGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) tag = TagFilterField(model) @@ -42,10 +43,11 @@ class TunnelGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSet class TunnelFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = Tunnel fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('status', 'encapsulation', 'tunnel_id', name=_('Tunnel')), FieldSet('ipsec_profile_id', name=_('Security')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenancy')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) status = forms.MultipleChoiceField( @@ -97,10 +99,11 @@ class TunnelTerminationFilterForm(NetBoxModelFilterSetForm): class IKEProposalFilterForm(PrimaryModelFilterSetForm): model = IKEProposal fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet( 'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', name=_('Parameters') ), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) authentication_method = forms.MultipleChoiceField( label=_('Authentication method'), @@ -128,8 +131,9 @@ class IKEProposalFilterForm(PrimaryModelFilterSetForm): class IKEPolicyFilterForm(PrimaryModelFilterSetForm): model = IKEPolicy fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('version', 'mode', 'proposal_id', name=_('Parameters')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) version = forms.MultipleChoiceField( label=_('IKE version'), @@ -152,8 +156,9 @@ class IKEPolicyFilterForm(PrimaryModelFilterSetForm): class IPSecProposalFilterForm(PrimaryModelFilterSetForm): model = IPSecProposal fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('encryption_algorithm', 'authentication_algorithm', name=_('Parameters')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) encryption_algorithm = forms.MultipleChoiceField( label=_('Encryption algorithm'), @@ -171,8 +176,9 @@ class IPSecProposalFilterForm(PrimaryModelFilterSetForm): class IPSecPolicyFilterForm(PrimaryModelFilterSetForm): model = IPSecPolicy fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('proposal_id', 'pfs_group', name=_('Parameters')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) proposal_id = DynamicModelMultipleChoiceField( queryset=IKEProposal.objects.all(), @@ -190,8 +196,9 @@ class IPSecPolicyFilterForm(PrimaryModelFilterSetForm): class IPSecProfileFilterForm(PrimaryModelFilterSetForm): model = IPSecProfile fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('mode', 'ike_policy_id', 'ipsec_policy_id', name=_('Profile')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) mode = forms.MultipleChoiceField( label=_('Mode'), @@ -214,9 +221,10 @@ class IPSecProfileFilterForm(PrimaryModelFilterSetForm): class L2VPNFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm): model = L2VPN fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('type', 'status', 'import_target_id', 'export_target_id', name=_('Attributes')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), ) status = forms.MultipleChoiceField( diff --git a/netbox/wireless/forms/filtersets.py b/netbox/wireless/forms/filtersets.py index 171a7d8b6..9ba023c04 100644 --- a/netbox/wireless/forms/filtersets.py +++ b/netbox/wireless/forms/filtersets.py @@ -22,8 +22,9 @@ __all__ = ( class WirelessLANGroupFilterForm(NestedGroupModelFilterSetForm): model = WirelessLANGroup fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('parent_id', name=_('Wireless LAN group')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) parent_id = DynamicModelMultipleChoiceField( queryset=WirelessLANGroup.objects.all(), @@ -36,11 +37,12 @@ class WirelessLANGroupFilterForm(NestedGroupModelFilterSetForm): class WirelessLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = WirelessLAN fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('ssid', 'group_id', 'status', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) ssid = forms.CharField( required=False, @@ -102,10 +104,11 @@ class WirelessLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): class WirelessLinkFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm): model = WirelessLink fieldsets = ( - FieldSet('q', 'filter_id', 'tag', 'owner_id'), + FieldSet('q', 'filter_id', 'tag'), FieldSet('ssid', 'status', 'distance', 'distance_unit', name=_('Attributes')), - FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')), + FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), + FieldSet('owner_group_id', 'owner_id', name=_('Ownership')), ) ssid = forms.CharField( required=False,