From 13f854c91f931c50192ce84dc3631d12cf0d5ad0 Mon Sep 17 00:00:00 2001 From: Pieter Lambrecht Date: Wed, 6 Jul 2022 14:10:10 +0200 Subject: [PATCH 01/17] Re-order journal list and form --- netbox/templates/extras/object_journal.html | 34 ++++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/netbox/templates/extras/object_journal.html b/netbox/templates/extras/object_journal.html index 363b067a8..0ed95d9eb 100644 --- a/netbox/templates/extras/object_journal.html +++ b/netbox/templates/extras/object_journal.html @@ -5,25 +5,29 @@ {% render_errors form %} {% block content %} - {% if perms.extras.add_journalentry %} -
-
-
-

New Journal Entry

- {% csrf_token %} - {% render_form form %} -
-
- Cancel - -
-
-
- {% endif %}
{% render_table table 'inc/table.html' %} {% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
+ {% if perms.extras.add_journalentry %} +
+
+

New Journal Entry

+
+
+
+ {% csrf_token %} + {% render_form form %} +
+
+ Cancel + +
+
+
+
+
+ {% endif %} {% endblock %} From 3c2a55a521b1a8c8a36340bf37f036f242a514a0 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 11:58:45 +0200 Subject: [PATCH 02/17] Add TenantGroupColumn to display Tenant Group on tables Works the same as the existing TenantColumn, but displats the Tenant Group of the Tenant. Views should prefetch the Tenants Group for this to be efficient in large tables. --- netbox/tenancy/tables/columns.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/netbox/tenancy/tables/columns.py b/netbox/tenancy/tables/columns.py index bb5aba5de..aa66e8bc8 100644 --- a/netbox/tenancy/tables/columns.py +++ b/netbox/tenancy/tables/columns.py @@ -2,6 +2,7 @@ import django_tables2 as tables __all__ = ( 'TenantColumn', + 'TenantGroupColumn', ) @@ -24,3 +25,28 @@ class TenantColumn(tables.TemplateColumn): def value(self, value): return str(value) if value else None + + +class TenantGroupColumn(tables.TemplateColumn): + """ + Include the tenant group description. + """ + template_code = """ + {% if record.tenant and record.tenant.group %} + {{ record.tenant.group }} + {% elif record.vrf.tenant and record.vrf.tenant.group %} + {{ record.vrf.tenant.group }}* + {% else %} + — + {% endif %} + """ + + def __init__(self, *args, **kwargs): + if 'verbose_name' not in kwargs: + kwargs['verbose_name'] = 'Tenant Group' + + super().__init__(template_code=self.template_code, *args, **kwargs) + + def value(self, value): + return str(value) if value else None + From bd60d46b8285e62b05e83a36989cf39a3aaa74b4 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 15:08:55 +0200 Subject: [PATCH 03/17] Table mixin for Tenancy columns A mixin to add the Tenant and Tenant Group columns to a table. --- netbox/tenancy/tables/columns.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/netbox/tenancy/tables/columns.py b/netbox/tenancy/tables/columns.py index aa66e8bc8..2d25590aa 100644 --- a/netbox/tenancy/tables/columns.py +++ b/netbox/tenancy/tables/columns.py @@ -3,6 +3,7 @@ import django_tables2 as tables __all__ = ( 'TenantColumn', 'TenantGroupColumn', + 'TenancyColumnsMixin', ) @@ -50,3 +51,7 @@ class TenantGroupColumn(tables.TemplateColumn): def value(self, value): return str(value) if value else None + +class TenancyColumnsMixin(tables.Table): + tenant_group = TenantGroupColumn() + tenant = TenantColumn() From e6bfde1397314950fd11dca01675abf490353cc0 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 15:13:48 +0200 Subject: [PATCH 04/17] Replace TenantColumn with new TenancyColumnsMixin Replaces all usages of the TenantColumn with the new TenancyColumnsMixin. This enables the user to add a column for Tenant Group on all tables which also has a column for Tenant. --- netbox/circuits/tables/circuits.py | 7 ++-- netbox/dcim/tables/cables.py | 7 ++-- netbox/dcim/tables/devices.py | 12 +++---- netbox/dcim/tables/racks.py | 12 +++---- netbox/dcim/tables/sites.py | 12 +++---- netbox/ipam/tables/ip.py | 32 ++++++++----------- netbox/ipam/tables/vlans.py | 12 +++---- netbox/ipam/tables/vrfs.py | 12 +++---- netbox/virtualization/tables/clusters.py | 8 ++--- .../virtualization/tables/virtualmachines.py | 7 ++-- 10 files changed, 50 insertions(+), 71 deletions(-) diff --git a/netbox/circuits/tables/circuits.py b/netbox/circuits/tables/circuits.py index 40f8918ae..ea4310def 100644 --- a/netbox/circuits/tables/circuits.py +++ b/netbox/circuits/tables/circuits.py @@ -2,7 +2,7 @@ import django_tables2 as tables from circuits.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .columns import CommitRateColumn __all__ = ( @@ -39,7 +39,7 @@ class CircuitTypeTable(NetBoxTable): default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug') -class CircuitTable(NetBoxTable): +class CircuitTable(TenancyColumnsMixin, NetBoxTable): cid = tables.Column( linkify=True, verbose_name='Circuit ID' @@ -48,7 +48,6 @@ class CircuitTable(NetBoxTable): linkify=True ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() termination_a = tables.TemplateColumn( template_code=CIRCUITTERMINATION_LINK, verbose_name='Side A' @@ -69,7 +68,7 @@ class CircuitTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Circuit fields = ( - 'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'install_date', + 'pk', 'id', 'cid', 'provider', 'type', 'status', 'tenant', 'tenant_group', 'termination_a', 'termination_z', 'install_date', 'commit_rate', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ( diff --git a/netbox/dcim/tables/cables.py b/netbox/dcim/tables/cables.py index 4b062ad48..4fd1b3266 100644 --- a/netbox/dcim/tables/cables.py +++ b/netbox/dcim/tables/cables.py @@ -3,7 +3,7 @@ from django_tables2.utils import Accessor from dcim.models import Cable from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT __all__ = ( @@ -15,7 +15,7 @@ __all__ = ( # Cables # -class CableTable(NetBoxTable): +class CableTable(TenancyColumnsMixin, NetBoxTable): termination_a_parent = tables.TemplateColumn( template_code=CABLE_TERMINATION_PARENT, accessor=Accessor('termination_a'), @@ -53,7 +53,6 @@ class CableTable(NetBoxTable): verbose_name='Termination B' ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() length = columns.TemplateColumn( template_code=CABLE_LENGTH, order_by=('_abs_length', 'length_unit') @@ -67,7 +66,7 @@ class CableTable(NetBoxTable): model = Cable fields = ( 'pk', 'id', 'label', 'termination_a_parent', 'rack_a', 'termination_a', 'termination_b_parent', 'rack_b', 'termination_b', - 'status', 'type', 'tenant', 'color', 'length', 'tags', 'created', 'last_updated', + 'status', 'type', 'tenant', 'tenant_group', 'color', 'length', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'id', 'label', 'termination_a_parent', 'termination_a', 'termination_b_parent', 'termination_b', diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index 0f015b7f3..710921beb 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -6,7 +6,7 @@ from dcim.models import ( InventoryItemRole, ModuleBay, Platform, PowerOutlet, PowerPort, RearPort, VirtualChassis, ) from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .template_code import * __all__ = ( @@ -137,13 +137,12 @@ class PlatformTable(NetBoxTable): # Devices # -class DeviceTable(NetBoxTable): +class DeviceTable(TenancyColumnsMixin, NetBoxTable): name = tables.TemplateColumn( order_by=('_name',), template_code=DEVICE_LINK ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() site = tables.Column( linkify=True ) @@ -200,7 +199,7 @@ class DeviceTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Device fields = ( - 'pk', 'id', 'name', 'status', 'tenant', 'device_role', 'manufacturer', 'device_type', 'platform', 'serial', + 'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'primary_ip', 'airflow', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', 'contacts', 'tags', 'created', 'last_updated', @@ -211,12 +210,11 @@ class DeviceTable(NetBoxTable): ) -class DeviceImportTable(NetBoxTable): +class DeviceImportTable(TenancyColumnsMixin, NetBoxTable): name = tables.TemplateColumn( template_code=DEVICE_LINK ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() site = tables.Column( linkify=True ) @@ -232,7 +230,7 @@ class DeviceImportTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Device - fields = ('id', 'name', 'status', 'tenant', 'site', 'rack', 'position', 'device_role', 'device_type') + fields = ('id', 'name', 'status', 'tenant', 'tenant_group', 'site', 'rack', 'position', 'device_role', 'device_type') empty_text = False diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index e6368cb74..5412e2297 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -3,7 +3,7 @@ from django_tables2.utils import Accessor from dcim.models import Rack, RackReservation, RackRole from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin __all__ = ( 'RackTable', @@ -37,7 +37,7 @@ class RackRoleTable(NetBoxTable): # Racks # -class RackTable(NetBoxTable): +class RackTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( order_by=('_name',), linkify=True @@ -48,7 +48,6 @@ class RackTable(NetBoxTable): site = tables.Column( linkify=True ) - tenant = TenantColumn() status = columns.ChoiceFieldColumn() role = columns.ColoredLabelColumn() u_height = tables.TemplateColumn( @@ -87,7 +86,7 @@ class RackTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Rack fields = ( - 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'serial', 'asset_tag', + 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'serial', 'asset_tag', 'type', 'width', 'outer_width', 'outer_depth', 'u_height', 'comments', 'device_count', 'get_utilization', 'get_power_utilization', 'contacts', 'tags', 'created', 'last_updated', ) @@ -101,7 +100,7 @@ class RackTable(NetBoxTable): # Rack reservations # -class RackReservationTable(NetBoxTable): +class RackReservationTable(TenancyColumnsMixin, NetBoxTable): reservation = tables.Column( accessor='pk', linkify=True @@ -110,7 +109,6 @@ class RackReservationTable(NetBoxTable): accessor=Accessor('rack__site'), linkify=True ) - tenant = TenantColumn() rack = tables.Column( linkify=True ) @@ -125,7 +123,7 @@ class RackReservationTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = RackReservation fields = ( - 'pk', 'id', 'reservation', 'site', 'rack', 'unit_list', 'user', 'created', 'tenant', 'description', 'tags', + 'pk', 'id', 'reservation', 'site', 'rack', 'unit_list', 'user', 'created', 'tenant', 'tenant_group', 'description', 'tags', 'actions', 'created', 'last_updated', ) default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description') diff --git a/netbox/dcim/tables/sites.py b/netbox/dcim/tables/sites.py index fa3c73e12..1945199a3 100644 --- a/netbox/dcim/tables/sites.py +++ b/netbox/dcim/tables/sites.py @@ -2,7 +2,7 @@ import django_tables2 as tables from dcim.models import Location, Region, Site, SiteGroup from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from .template_code import LOCATION_BUTTONS __all__ = ( @@ -75,7 +75,7 @@ class SiteGroupTable(NetBoxTable): # Sites # -class SiteTable(NetBoxTable): +class SiteTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) @@ -96,7 +96,6 @@ class SiteTable(NetBoxTable): url_params={'site_id': 'pk'}, verbose_name='ASN Count' ) - tenant = TenantColumn() comments = columns.MarkdownColumn() contacts = columns.ManyToManyColumn( linkify_item=True @@ -108,7 +107,7 @@ class SiteTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Site fields = ( - 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'asns', 'asn_count', + 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'tenant_group', 'asns', 'asn_count', 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'contacts', 'tags', 'created', 'last_updated', 'actions', ) @@ -119,14 +118,13 @@ class SiteTable(NetBoxTable): # Locations # -class LocationTable(NetBoxTable): +class LocationTable(TenancyColumnsMixin, NetBoxTable): name = columns.MPTTColumn( linkify=True ) site = tables.Column( linkify=True ) - tenant = TenantColumn() rack_count = columns.LinkedCountColumn( viewname='dcim:rack_list', url_params={'location_id': 'pk'}, @@ -150,7 +148,7 @@ class LocationTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Location fields = ( - 'pk', 'id', 'name', 'site', 'tenant', 'rack_count', 'device_count', 'description', 'slug', 'contacts', + 'pk', 'id', 'name', 'site', 'tenant', 'tenant_group', 'rack_count', 'device_count', 'description', 'slug', 'contacts', 'tags', 'actions', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'site', 'tenant', 'rack_count', 'device_count', 'description') diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 558631585..e61d99fd8 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -4,7 +4,7 @@ from django_tables2.utils import Accessor from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin __all__ = ( 'AggregateTable', @@ -99,7 +99,7 @@ class RIRTable(NetBoxTable): # ASNs # -class ASNTable(NetBoxTable): +class ASNTable(TenancyColumnsMixin, NetBoxTable): asn = tables.Column( linkify=True ) @@ -122,7 +122,6 @@ class ASNTable(NetBoxTable): linkify_item=True, verbose_name='Sites' ) - tenant = TenantColumn() tags = columns.TagColumn( url_name='ipam:asn_list' ) @@ -130,7 +129,7 @@ class ASNTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ASN fields = ( - 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'description', 'sites', 'tags', + 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', 'sites', 'tags', 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'asn', 'rir', 'site_count', 'provider_count', 'sites', 'description', 'tenant') @@ -140,12 +139,11 @@ class ASNTable(NetBoxTable): # Aggregates # -class AggregateTable(NetBoxTable): +class AggregateTable(TenancyColumnsMixin, NetBoxTable): prefix = tables.Column( linkify=True, verbose_name='Aggregate' ) - tenant = TenantColumn() date_added = tables.DateColumn( format="Y-m-d", verbose_name='Added' @@ -164,7 +162,7 @@ class AggregateTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Aggregate fields = ( - 'pk', 'id', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description', 'tags', + 'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added', 'description', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description') @@ -225,7 +223,7 @@ class PrefixUtilizationColumn(columns.UtilizationColumn): """ -class PrefixTable(NetBoxTable): +class PrefixTable(TenancyColumnsMixin, NetBoxTable): prefix = columns.TemplateColumn( template_code=PREFIX_LINK, export_raw=True, @@ -256,7 +254,6 @@ class PrefixTable(NetBoxTable): template_code=VRF_LINK, verbose_name='VRF' ) - tenant = TenantColumn() site = tables.Column( linkify=True ) @@ -289,7 +286,7 @@ class PrefixTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Prefix fields = ( - 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', + 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group', 'site', 'vlan_group', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'tags', 'created', 'last_updated', ) default_columns = ( @@ -303,7 +300,7 @@ class PrefixTable(NetBoxTable): # # IP ranges # -class IPRangeTable(NetBoxTable): +class IPRangeTable(TenancyColumnsMixin, NetBoxTable): start_address = tables.Column( linkify=True ) @@ -317,7 +314,6 @@ class IPRangeTable(NetBoxTable): role = tables.Column( linkify=True ) - tenant = TenantColumn() utilization = columns.UtilizationColumn( accessor='utilization', orderable=False @@ -329,7 +325,7 @@ class IPRangeTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = IPRange fields = ( - 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'description', + 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description', 'utilization', 'tags', 'created', 'last_updated', ) default_columns = ( @@ -344,7 +340,7 @@ class IPRangeTable(NetBoxTable): # IPAddresses # -class IPAddressTable(NetBoxTable): +class IPAddressTable(TenancyColumnsMixin, NetBoxTable): address = tables.TemplateColumn( template_code=IPADDRESS_LINK, verbose_name='IP Address' @@ -357,7 +353,6 @@ class IPAddressTable(NetBoxTable): default=AVAILABLE_LABEL ) role = columns.ChoiceFieldColumn() - tenant = TenantColumn() assigned_object = tables.Column( linkify=True, orderable=False, @@ -386,7 +381,7 @@ class IPAddressTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = IPAddress fields = ( - 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'nat_inside', 'assigned', 'dns_name', 'description', + 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'assigned', 'dns_name', 'description', 'tags', 'created', 'last_updated', ) default_columns = ( @@ -414,7 +409,7 @@ class IPAddressAssignTable(NetBoxTable): orderable = False -class AssignedIPAddressesTable(NetBoxTable): +class AssignedIPAddressesTable(TenancyColumnsMixin, NetBoxTable): """ List IP addresses assigned to an object. """ @@ -427,9 +422,8 @@ class AssignedIPAddressesTable(NetBoxTable): verbose_name='VRF' ) status = columns.ChoiceFieldColumn() - tenant = TenantColumn() class Meta(NetBoxTable.Meta): model = IPAddress - fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description') + fields = ('address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description') exclude = ('id', ) diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index 4551a1c3d..4329177eb 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -5,7 +5,7 @@ from django_tables2.utils import Accessor from dcim.models import Interface from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from virtualization.models import VMInterface __all__ = ( @@ -90,7 +90,7 @@ class VLANGroupTable(NetBoxTable): # VLANs # -class VLANTable(NetBoxTable): +class VLANTable(TenancyColumnsMixin, NetBoxTable): vid = tables.TemplateColumn( template_code=VLAN_LINK, verbose_name='VID' @@ -104,7 +104,6 @@ class VLANTable(NetBoxTable): group = tables.Column( linkify=True ) - tenant = TenantColumn() status = columns.ChoiceFieldColumn( default=AVAILABLE_LABEL ) @@ -123,7 +122,7 @@ class VLANTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VLAN fields = ( - 'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description', 'tags', + 'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'tenant_group', 'status', 'role', 'description', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description') @@ -174,7 +173,7 @@ class VLANVirtualMachinesTable(VLANMembersTable): exclude = ('id', ) -class InterfaceVLANTable(NetBoxTable): +class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): """ List VLANs assigned to a specific Interface. """ @@ -190,7 +189,6 @@ class InterfaceVLANTable(NetBoxTable): accessor=Accessor('group__name'), verbose_name='Group' ) - tenant = TenantColumn() status = columns.ChoiceFieldColumn() role = tables.Column( linkify=True @@ -198,7 +196,7 @@ class InterfaceVLANTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VLAN - fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') + fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'tenant_group', 'status', 'role', 'description') exclude = ('id', ) def __init__(self, interface, *args, **kwargs): diff --git a/netbox/ipam/tables/vrfs.py b/netbox/ipam/tables/vrfs.py index 727f402ff..69807410b 100644 --- a/netbox/ipam/tables/vrfs.py +++ b/netbox/ipam/tables/vrfs.py @@ -2,7 +2,7 @@ import django_tables2 as tables from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin __all__ = ( 'RouteTargetTable', @@ -20,14 +20,13 @@ VRF_TARGETS = """ # VRFs # -class VRFTable(NetBoxTable): +class VRFTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) rd = tables.Column( verbose_name='RD' ) - tenant = TenantColumn() enforce_unique = columns.BooleanColumn( verbose_name='Unique' ) @@ -46,7 +45,7 @@ class VRFTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VRF fields = ( - 'pk', 'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', + 'pk', 'id', 'name', 'rd', 'tenant', 'tenant_group', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'rd', 'tenant', 'description') @@ -56,16 +55,15 @@ class VRFTable(NetBoxTable): # Route targets # -class RouteTargetTable(NetBoxTable): +class RouteTargetTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) - tenant = TenantColumn() tags = columns.TagColumn( url_name='ipam:vrf_list' ) class Meta(NetBoxTable.Meta): model = RouteTarget - fields = ('pk', 'id', 'name', 'tenant', 'description', 'tags', 'created', 'last_updated',) + fields = ('pk', 'id', 'name', 'tenant', 'tenant_group', 'description', 'tags', 'created', 'last_updated',) default_columns = ('pk', 'name', 'tenant', 'description') diff --git a/netbox/virtualization/tables/clusters.py b/netbox/virtualization/tables/clusters.py index a0c98425a..ccffe23fd 100644 --- a/netbox/virtualization/tables/clusters.py +++ b/netbox/virtualization/tables/clusters.py @@ -1,6 +1,7 @@ import django_tables2 as tables from netbox.tables import NetBoxTable, columns +from tenancy.tables import TenancyColumnsMixin from virtualization.models import Cluster, ClusterGroup, ClusterType __all__ = ( @@ -56,7 +57,7 @@ class ClusterGroupTable(NetBoxTable): default_columns = ('pk', 'name', 'cluster_count', 'description') -class ClusterTable(NetBoxTable): +class ClusterTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) @@ -66,9 +67,6 @@ class ClusterTable(NetBoxTable): group = tables.Column( linkify=True ) - tenant = tables.Column( - linkify=True - ) site = tables.Column( linkify=True ) @@ -93,7 +91,7 @@ class ClusterTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Cluster fields = ( - 'pk', 'id', 'name', 'type', 'group', 'tenant', 'site', 'comments', 'device_count', 'vm_count', 'contacts', + 'pk', 'id', 'name', 'type', 'group', 'tenant', 'tenant_group', 'site', 'comments', 'device_count', 'vm_count', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'type', 'group', 'tenant', 'site', 'device_count', 'vm_count') diff --git a/netbox/virtualization/tables/virtualmachines.py b/netbox/virtualization/tables/virtualmachines.py index 89dbdf901..8cff96227 100644 --- a/netbox/virtualization/tables/virtualmachines.py +++ b/netbox/virtualization/tables/virtualmachines.py @@ -2,7 +2,7 @@ import django_tables2 as tables from dcim.tables.devices import BaseInterfaceTable from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenantColumn +from tenancy.tables import TenancyColumnsMixin from virtualization.models import VirtualMachine, VMInterface __all__ = ( @@ -24,7 +24,7 @@ VMINTERFACE_BUTTONS = """ # Virtual machines # -class VirtualMachineTable(NetBoxTable): +class VirtualMachineTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( order_by=('_name',), linkify=True @@ -34,7 +34,6 @@ class VirtualMachineTable(NetBoxTable): linkify=True ) role = columns.ColoredLabelColumn() - tenant = TenantColumn() comments = columns.MarkdownColumn() primary_ip4 = tables.Column( linkify=True, @@ -56,7 +55,7 @@ class VirtualMachineTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = VirtualMachine fields = ( - 'pk', 'id', 'name', 'status', 'cluster', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', + 'pk', 'id', 'name', 'status', 'cluster', 'role', 'tenant', 'tenant_group', 'platform', 'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( From 69a22ffe5e3aefafa540f13c40e88f9c5ca0b7ec Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 15:38:21 +0200 Subject: [PATCH 05/17] Prefetch Tenant Group in global search Configure the prefetch to also include the Tenant Group, avoids additional database queries when the Tenant Group column is to be rendered. NOTE: If no personalisation of the global search tables should be done, this commit can be reverted. --- netbox/netbox/constants.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/netbox/netbox/constants.py b/netbox/netbox/constants.py index 8ca0d98c1..cc04e9aa8 100644 --- a/netbox/netbox/constants.py +++ b/netbox/netbox/constants.py @@ -34,7 +34,7 @@ CIRCUIT_TYPES = OrderedDict( }), ('circuit', { 'queryset': Circuit.objects.prefetch_related( - 'type', 'provider', 'tenant', 'terminations__site' + 'type', 'provider', 'tenant', 'tenant__group', 'terminations__site' ), 'filterset': circuits.filtersets.CircuitFilterSet, 'table': circuits.tables.CircuitTable, @@ -53,13 +53,13 @@ CIRCUIT_TYPES = OrderedDict( DCIM_TYPES = OrderedDict( ( ('site', { - 'queryset': Site.objects.prefetch_related('region', 'tenant'), + 'queryset': Site.objects.prefetch_related('region', 'tenant', 'tenant__group'), 'filterset': dcim.filtersets.SiteFilterSet, 'table': dcim.tables.SiteTable, 'url': 'dcim:site_list', }), ('rack', { - 'queryset': Rack.objects.prefetch_related('site', 'location', 'tenant', 'role').annotate( + 'queryset': Rack.objects.prefetch_related('site', 'location', 'tenant', 'tenant__group', 'role').annotate( device_count=count_related(Device, 'rack') ), 'filterset': dcim.filtersets.RackFilterSet, @@ -100,7 +100,7 @@ DCIM_TYPES = OrderedDict( }), ('device', { 'queryset': Device.objects.prefetch_related( - 'device_type__manufacturer', 'device_role', 'tenant', 'site', 'rack', 'primary_ip4', 'primary_ip6', + 'device_type__manufacturer', 'device_role', 'tenant', 'tenant__group', 'site', 'rack', 'primary_ip4', 'primary_ip6', ), 'filterset': dcim.filtersets.DeviceFilterSet, 'table': dcim.tables.DeviceTable, @@ -148,7 +148,7 @@ DCIM_TYPES = OrderedDict( IPAM_TYPES = OrderedDict( ( ('vrf', { - 'queryset': VRF.objects.prefetch_related('tenant'), + 'queryset': VRF.objects.prefetch_related('tenant', 'tenant__group'), 'filterset': ipam.filtersets.VRFFilterSet, 'table': ipam.tables.VRFTable, 'url': 'ipam:vrf_list', @@ -160,25 +160,25 @@ IPAM_TYPES = OrderedDict( 'url': 'ipam:aggregate_list', }), ('prefix', { - 'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role'), + 'queryset': Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'tenant__group', 'vlan', 'role'), 'filterset': ipam.filtersets.PrefixFilterSet, 'table': ipam.tables.PrefixTable, 'url': 'ipam:prefix_list', }), ('ipaddress', { - 'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant'), + 'queryset': IPAddress.objects.prefetch_related('vrf__tenant', 'tenant', 'tenant__group'), 'filterset': ipam.filtersets.IPAddressFilterSet, 'table': ipam.tables.IPAddressTable, 'url': 'ipam:ipaddress_list', }), ('vlan', { - 'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role'), + 'queryset': VLAN.objects.prefetch_related('site', 'group', 'tenant', 'tenant__group', 'role'), 'filterset': ipam.filtersets.VLANFilterSet, 'table': ipam.tables.VLANTable, 'url': 'ipam:vlan_list', }), ('asn', { - 'queryset': ASN.objects.prefetch_related('rir', 'tenant'), + 'queryset': ASN.objects.prefetch_related('rir', 'tenant', 'tenant__group'), 'filterset': ipam.filtersets.ASNFilterSet, 'table': ipam.tables.ASNTable, 'url': 'ipam:asn_list', @@ -223,7 +223,7 @@ VIRTUALIZATION_TYPES = OrderedDict( }), ('virtualmachine', { 'queryset': VirtualMachine.objects.prefetch_related( - 'cluster', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', + 'cluster', 'tenant', 'tenant__group', 'platform', 'primary_ip4', 'primary_ip6', ), 'filterset': virtualization.filtersets.VirtualMachineFilterSet, 'table': virtualization.tables.VirtualMachineTable, From c7ece43a1887bdc1bb3daf894c0929b9babd0505 Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 17:16:12 +0200 Subject: [PATCH 06/17] Remove Tenant Group from child tables Removes the Tenant Group column from tables which aren't configurable by the user. --- netbox/ipam/tables/ip.py | 7 ++++--- netbox/ipam/tables/vlans.py | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index e61d99fd8..bec05eeff 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -4,7 +4,7 @@ from django_tables2.utils import Accessor from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenancyColumnsMixin +from tenancy.tables import TenancyColumnsMixin, TenantColumn __all__ = ( 'AggregateTable', @@ -409,7 +409,7 @@ class IPAddressAssignTable(NetBoxTable): orderable = False -class AssignedIPAddressesTable(TenancyColumnsMixin, NetBoxTable): +class AssignedIPAddressesTable(NetBoxTable): """ List IP addresses assigned to an object. """ @@ -422,8 +422,9 @@ class AssignedIPAddressesTable(TenancyColumnsMixin, NetBoxTable): verbose_name='VRF' ) status = columns.ChoiceFieldColumn() + tenant = TenantColumn() class Meta(NetBoxTable.Meta): model = IPAddress - fields = ('address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description') + fields = ('address', 'vrf', 'status', 'role', 'tenant', 'description') exclude = ('id', ) diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index 4329177eb..7878de507 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -5,7 +5,7 @@ from django_tables2.utils import Accessor from dcim.models import Interface from ipam.models import * from netbox.tables import NetBoxTable, columns -from tenancy.tables import TenancyColumnsMixin +from tenancy.tables import TenancyColumnsMixin, TenantColumn from virtualization.models import VMInterface __all__ = ( @@ -173,7 +173,7 @@ class VLANVirtualMachinesTable(VLANMembersTable): exclude = ('id', ) -class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): +class InterfaceVLANTable(NetBoxTable): """ List VLANs assigned to a specific Interface. """ @@ -189,6 +189,7 @@ class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): accessor=Accessor('group__name'), verbose_name='Group' ) + tenant = TenantColumn() status = columns.ChoiceFieldColumn() role = tables.Column( linkify=True @@ -196,7 +197,7 @@ class InterfaceVLANTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = VLAN - fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'tenant_group', 'status', 'role', 'description') + fields = ('vid', 'tagged', 'site', 'group', 'name', 'tenant', 'status', 'role', 'description') exclude = ('id', ) def __init__(self, interface, *args, **kwargs): From 1539769c08e200c8586de43700f8d152e7b3cc0d Mon Sep 17 00:00:00 2001 From: Kim Johansson Date: Sun, 10 Jul 2022 17:17:56 +0200 Subject: [PATCH 07/17] Prefetch Tenant Group on user configurable tables Prefetch the Tenant Group in views which allows its table to be configured by the user. This decreases the amount of database queries that are required to fetch the data. --- netbox/circuits/views.py | 6 +++--- netbox/dcim/views.py | 2 +- netbox/ipam/views.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index f3b1269f9..11f211b27 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -30,7 +30,7 @@ class ProviderView(generic.ObjectView): circuits = Circuit.objects.restrict(request.user, 'view').filter( provider=instance ).prefetch_related( - 'type', 'tenant', 'terminations__site' + 'type', 'tenant', 'tenant__group', 'terminations__site' ) circuits_table = tables.CircuitTable(circuits, user=request.user, exclude=('provider',)) circuits_table.configure(request) @@ -91,7 +91,7 @@ class ProviderNetworkView(generic.ObjectView): Q(termination_a__provider_network=instance.pk) | Q(termination_z__provider_network=instance.pk) ).prefetch_related( - 'type', 'tenant', 'terminations__site' + 'type', 'tenant', 'tenant__group', 'terminations__site' ) circuits_table = tables.CircuitTable(circuits, user=request.user) circuits_table.configure(request) @@ -192,7 +192,7 @@ class CircuitTypeBulkDeleteView(generic.BulkDeleteView): class CircuitListView(generic.ObjectListView): queryset = Circuit.objects.prefetch_related( - 'provider', 'type', 'tenant', 'termination_a', 'termination_z' + 'provider', 'type', 'tenant', 'tenant__group', 'termination_a', 'termination_z' ) filterset = filtersets.CircuitFilterSet filterset_form = forms.CircuitFilterForm diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 35a1056b2..a466246f5 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -561,7 +561,7 @@ class RackRoleBulkDeleteView(generic.BulkDeleteView): class RackListView(generic.ObjectListView): queryset = Rack.objects.prefetch_related( - 'site', 'location', 'tenant', 'role', 'devices__device_type' + 'site', 'location', 'tenant', 'tenant_group', 'role', 'devices__device_type' ).annotate( device_count=count_related(Device, 'rack') ) diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 6bcdc4c64..e6b11c427 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -298,7 +298,7 @@ class AggregatePrefixesView(generic.ObjectChildrenView): def get_children(self, request, parent): return Prefix.objects.restrict(request.user, 'view').filter( prefix__net_contained_or_equal=str(parent.prefix) - ).prefetch_related('site', 'role', 'tenant', 'vlan') + ).prefetch_related('site', 'role', 'tenant', 'tenant__group', 'vlan') def prep_table_data(self, request, queryset, parent): # Determine whether to show assigned prefixes, available prefixes, or both @@ -470,7 +470,7 @@ class PrefixPrefixesView(generic.ObjectChildrenView): def get_children(self, request, parent): return parent.get_child_prefixes().restrict(request.user, 'view').prefetch_related( - 'site', 'vrf', 'vlan', 'role', 'tenant', + 'site', 'vrf', 'vlan', 'role', 'tenant', 'tenant__group' ) def prep_table_data(self, request, queryset, parent): @@ -499,7 +499,7 @@ class PrefixIPRangesView(generic.ObjectChildrenView): def get_children(self, request, parent): return parent.get_child_ranges().restrict(request.user, 'view').prefetch_related( - 'vrf', 'role', 'tenant', + 'vrf', 'role', 'tenant', 'tenant__group', ) def get_extra_context(self, request, instance): @@ -587,7 +587,7 @@ class IPRangeIPAddressesView(generic.ObjectChildrenView): def get_children(self, request, parent): return parent.get_child_ips().restrict(request.user, 'view').prefetch_related( - 'vrf', 'role', 'tenant', + 'vrf', 'role', 'tenant', 'tenant__group', ) def get_extra_context(self, request, instance): From 93c30c94b3b25642af2e74c536a16d18c8a3d102 Mon Sep 17 00:00:00 2001 From: kkthxbye-code Date: Sun, 10 Jul 2022 19:16:16 +0200 Subject: [PATCH 08/17] Focus on select field after populating data --- netbox/project-static/dist/netbox.js | Bin 376144 -> 376180 bytes netbox/project-static/dist/netbox.js.map | Bin 345564 -> 345595 bytes .../src/select/api/apiSelect.ts | 1 + 3 files changed, 1 insertion(+) diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index bc0cabef08f2cab679e475fe18741c4e97ee187e..b611079e17d534b7e0aea1ed07b5e33c124129f5 100644 GIT binary patch delta 42 ycmcccOYF-pv4$4L7N!>F7M3lnH-o0T<+2KLXXX`@mguGBCzlp)zZk??p9KJbz!4Mx delta 30 mcmezJOYFigv4$4L7N!>F7M3lnH-n~sk7ZTft`N)`k_7cxt0K_2NW&< delta 47 zcmey}EqbS0w4sHug{g&k3(JLX+uwgc`G#zP*o!HP;dV D&I=I5 diff --git a/netbox/project-static/src/select/api/apiSelect.ts b/netbox/project-static/src/select/api/apiSelect.ts index f5b605d58..798694f0e 100644 --- a/netbox/project-static/src/select/api/apiSelect.ts +++ b/netbox/project-static/src/select/api/apiSelect.ts @@ -411,6 +411,7 @@ export class APISelect { } finally { this.setOptionStyles(); this.enable(); + this.slim.slim.search.input.focus(); this.base.dispatchEvent(this.loadEvent); } } From d3f91ce0a6140f4e2ecfdbaf7287ec4527de265a Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 09:57:12 -0400 Subject: [PATCH 09/17] Changelog for #9632, #9686 --- docs/release-notes/version-3.2.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/release-notes/version-3.2.md b/docs/release-notes/version-3.2.md index 9b4dc800d..7c62f85ad 100644 --- a/docs/release-notes/version-3.2.md +++ b/docs/release-notes/version-3.2.md @@ -8,12 +8,14 @@ * [#9396](https://github.com/netbox-community/netbox/issues/9396) - Allow filtering modules by bay ID * [#9403](https://github.com/netbox-community/netbox/issues/9403) - Enable modifying virtual chassis properties when creating/editing a device * [#9540](https://github.com/netbox-community/netbox/issues/9540) - Add filters for assigned device & VM to IP addresses list +* [#9686](https://github.com/netbox-community/netbox/issues/9686) - Add tenant group column for all object tables with tenant assignments ### Bug Fixes * [#8854](https://github.com/netbox-community/netbox/issues/8854) - Fix `REMOTE_AUTH_DEFAULT_GROUPS` for social-auth backends * [#9575](https://github.com/netbox-community/netbox/issues/9575) - Fix AttributeError exception for FHRP group with an IP address assigned * [#9597](https://github.com/netbox-community/netbox/issues/9597) - Include `installed_module` in module bay REST API serializer +* [#9632](https://github.com/netbox-community/netbox/issues/9632) - Automatically focus on search box when expanding dropdowns * [#9657](https://github.com/netbox-community/netbox/issues/9657) - Fix filtering for custom fields and webhooks in the UI * [#9682](https://github.com/netbox-community/netbox/issues/9682) - Fix bulk assignment of ASNs to sites From e2af716a81b84972ce2f310d1f9f11d2a54f5367 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 10:03:45 -0400 Subject: [PATCH 10/17] #9686: Add default accessor to TenantGroupColumn --- netbox/tenancy/tables/columns.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/tenancy/tables/columns.py b/netbox/tenancy/tables/columns.py index 2d25590aa..21622f18b 100644 --- a/netbox/tenancy/tables/columns.py +++ b/netbox/tenancy/tables/columns.py @@ -42,11 +42,11 @@ class TenantGroupColumn(tables.TemplateColumn): {% endif %} """ - def __init__(self, *args, **kwargs): + def __init__(self, accessor=tables.A('tenant__group'), *args, **kwargs): if 'verbose_name' not in kwargs: kwargs['verbose_name'] = 'Tenant Group' - super().__init__(template_code=self.template_code, *args, **kwargs) + super().__init__(template_code=self.template_code, accessor=accessor, *args, **kwargs) def value(self, value): return str(value) if value else None From ed7f42a803c5a2d2af28a817b45d672ef417c728 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 10:28:37 -0400 Subject: [PATCH 11/17] Fixes #9704: Include last_updated field on JournalEntry REST API serializer --- docs/release-notes/version-3.2.md | 1 + netbox/extras/api/serializers.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.2.md b/docs/release-notes/version-3.2.md index 7c62f85ad..83c0765c3 100644 --- a/docs/release-notes/version-3.2.md +++ b/docs/release-notes/version-3.2.md @@ -18,6 +18,7 @@ * [#9632](https://github.com/netbox-community/netbox/issues/9632) - Automatically focus on search box when expanding dropdowns * [#9657](https://github.com/netbox-community/netbox/issues/9657) - Fix filtering for custom fields and webhooks in the UI * [#9682](https://github.com/netbox-community/netbox/issues/9682) - Fix bulk assignment of ASNs to sites +* [#9704](https://github.com/netbox-community/netbox/issues/9704) - Include `last_updated` field on JournalEntry REST API serializer --- diff --git a/netbox/extras/api/serializers.py b/netbox/extras/api/serializers.py index e05d4083c..bdb54067a 100644 --- a/netbox/extras/api/serializers.py +++ b/netbox/extras/api/serializers.py @@ -221,7 +221,7 @@ class JournalEntrySerializer(NetBoxModelSerializer): model = JournalEntry fields = [ 'id', 'url', 'display', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'created', - 'created_by', 'kind', 'comments', 'tags', 'custom_fields', + 'created_by', 'kind', 'comments', 'tags', 'custom_fields', 'last_updated', ] def validate(self, data): From 6415661b61d85a12a0b8002719623d19477574f2 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 10:33:14 -0400 Subject: [PATCH 12/17] Remove extraneous argument to GenericRelation --- netbox/dcim/models/device_components.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 9a0609c12..714ee3ff5 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -95,8 +95,7 @@ class ModularComponentModel(ComponentModel): inventory_items = GenericRelation( to='dcim.InventoryItem', content_type_field='component_type', - object_id_field='component_id', - related_name='%(class)ss', + object_id_field='component_id' ) class Meta: From 7c109ffd8cb6e9c76c440263568fb7194519e491 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 11:02:18 -0400 Subject: [PATCH 13/17] Fixes #9697: Fix device role link under device view --- netbox/templates/dcim/device.html | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index d3d6f03dc..68af0c08f 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -46,13 +46,7 @@ Rack - - {% if object.rack %} - {{ object.rack }} - {% else %} - {{ ''|placeholder }} - {% endif %} - + {{ object.rack|linkify|placeholder }} Position @@ -161,9 +155,7 @@ Role - - {{ object.device_role }} - + {{ object.device_role|linkify }} Platform @@ -173,7 +165,7 @@ Primary IPv4 {% if object.primary_ip4 %} - {{ object.primary_ip4.address.ip }} + {{ object.primary_ip4.address.ip }} {% if object.primary_ip4.nat_inside %} (NAT for {{ object.primary_ip4.nat_inside.address.ip|linkify }}) {% elif object.primary_ip4.nat_outside %} @@ -188,7 +180,7 @@ Primary IPv6 {% if object.primary_ip6 %} - {{ object.primary_ip6.address.ip }} + {{ object.primary_ip6.address.ip }} {% if object.primary_ip6.nat_inside %} (NAT for {{ object.primary_ip6.nat_inside.address.ip|linkify }}) {% elif object.primary_ip6.nat_outside %} From 5a4467a4a8cc92b83606a8bbc661873b5fd294cd Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 11:12:06 -0400 Subject: [PATCH 14/17] Fixes #9687: Don't restrict custom text field lengths when entering via UI form --- docs/models/extras/customfield.md | 2 +- docs/release-notes/version-3.2.md | 1 + netbox/extras/models/customfields.py | 9 ++------- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/models/extras/customfield.md b/docs/models/extras/customfield.md index da73816b6..e0c01688d 100644 --- a/docs/models/extras/customfield.md +++ b/docs/models/extras/customfield.md @@ -10,7 +10,7 @@ Within the database, custom fields are stored as JSON data directly alongside ea Custom fields may be created by navigating to Customization > Custom Fields. NetBox supports six types of custom field: -* Text: Free-form text (up to 255 characters) +* Text: Free-form text (intended for single-line use) * Long text: Free-form of any length; supports Markdown rendering * Integer: A whole number (positive or negative) * Boolean: True or false diff --git a/docs/release-notes/version-3.2.md b/docs/release-notes/version-3.2.md index 83c0765c3..86a352215 100644 --- a/docs/release-notes/version-3.2.md +++ b/docs/release-notes/version-3.2.md @@ -18,6 +18,7 @@ * [#9632](https://github.com/netbox-community/netbox/issues/9632) - Automatically focus on search box when expanding dropdowns * [#9657](https://github.com/netbox-community/netbox/issues/9657) - Fix filtering for custom fields and webhooks in the UI * [#9682](https://github.com/netbox-community/netbox/issues/9682) - Fix bulk assignment of ASNs to sites +* [#9687](https://github.com/netbox-community/netbox/issues/9687) - Don't restrict custom text field lengths when entering via UI form * [#9704](https://github.com/netbox-community/netbox/issues/9704) - Include `last_updated` field on JournalEntry REST API serializer --- diff --git a/netbox/extras/models/customfields.py b/netbox/extras/models/customfields.py index 49afe1bba..6a8c1dacf 100644 --- a/netbox/extras/models/customfields.py +++ b/netbox/extras/models/customfields.py @@ -365,13 +365,8 @@ class CustomField(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): # Text else: - if self.type == CustomFieldTypeChoices.TYPE_LONGTEXT: - max_length = None - widget = forms.Textarea - else: - max_length = 255 - widget = None - field = forms.CharField(max_length=max_length, required=required, initial=initial, widget=widget) + widget = forms.Textarea if self.type == CustomFieldTypeChoices.TYPE_LONGTEXT else None + field = forms.CharField(required=required, initial=initial, widget=widget) if self.validation_regex: field.validators = [ RegexValidator( From 68f24755aa4d8464111dd3eda320eee1cb99d53f Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 11:40:10 -0400 Subject: [PATCH 15/17] Release v3.2.6 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- base_requirements.txt | 8 ++++---- docs/release-notes/version-3.2.md | 2 +- netbox/netbox/settings.py | 2 +- requirements.txt | 12 ++++++------ 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 3b87a49e4..78231890b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.2.5 + placeholder: v3.2.6 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 1fc0268ab..71d45092c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.2.5 + placeholder: v3.2.6 validations: required: true - type: dropdown diff --git a/base_requirements.txt b/base_requirements.txt index 98d3f78c2..9dc85231b 100644 --- a/base_requirements.txt +++ b/base_requirements.txt @@ -1,3 +1,7 @@ +# HTML sanitizer +# https://github.com/mozilla/bleach +bleach + # The Python web framework on which NetBox is built # https://github.com/django/django Django @@ -126,7 +130,3 @@ tablib # Timezone data (required by django-timezone-field on Python 3.9+) # https://github.com/python/tzdata tzdata - -# HTML sanitizer -# https://github.com/mozilla/bleach -bleach \ No newline at end of file diff --git a/docs/release-notes/version-3.2.md b/docs/release-notes/version-3.2.md index 86a352215..8775da01f 100644 --- a/docs/release-notes/version-3.2.md +++ b/docs/release-notes/version-3.2.md @@ -1,6 +1,6 @@ # NetBox v3.2 -## v3.2.6 (FUTURE) +## v3.2.6 (2022-07-11) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index c0df42a2b..b9d7e20b9 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -29,7 +29,7 @@ django.utils.encoding.force_text = force_str # Environment setup # -VERSION = '3.2.6-dev' +VERSION = '3.2.6' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index 1fdace4f0..f987ad7ba 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ -bleach==5.0.0 -Django==4.0.5 +bleach==5.0.1 +Django==4.0.6 django-cors-headers==3.13.0 -django-debug-toolbar==3.4.0 +django-debug-toolbar==3.5.0 django-filter==22.1 django-graphiql-debug-toolbar==0.2.0 django-mptt==0.13.4 @@ -19,13 +19,13 @@ gunicorn==20.1.0 Jinja2==3.1.2 Markdown==3.3.7 markdown-include==0.6.0 -mkdocs-material==8.3.6 +mkdocs-material==8.3.9 mkdocstrings[python-legacy]==0.19.0 netaddr==0.8.0 -Pillow==9.1.1 +Pillow==9.2.0 psycopg2-binary==2.9.3 PyYAML==6.0 -sentry-sdk==1.5.12 +sentry-sdk==1.7.0 social-auth-app-django==5.0.0 social-auth-core==4.3.0 svgwrite==1.4.2 From e106d7ac3a2a2f30b92bf2e8bd9df8f40e1e23c5 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 12:11:50 -0400 Subject: [PATCH 16/17] PRVB --- docs/release-notes/version-3.2.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.2.md b/docs/release-notes/version-3.2.md index 8775da01f..1ba6235b8 100644 --- a/docs/release-notes/version-3.2.md +++ b/docs/release-notes/version-3.2.md @@ -1,5 +1,9 @@ # NetBox v3.2 +## v3.2.7 (FUTURE) + +--- + ## v3.2.6 (2022-07-11) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index b9d7e20b9..736290380 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -29,7 +29,7 @@ django.utils.encoding.force_text = force_str # Environment setup # -VERSION = '3.2.6' +VERSION = '3.2.7-dev' # Hostname HOSTNAME = platform.node() From 57397570c08f27148c10a65a00d245147647a33f Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 11 Jul 2022 12:45:53 -0400 Subject: [PATCH 17/17] Drop extraneous/invalid prefetches --- netbox/dcim/views.py | 4 +--- netbox/ipam/views.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index a466246f5..ec3e9152e 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -560,9 +560,7 @@ class RackRoleBulkDeleteView(generic.BulkDeleteView): # class RackListView(generic.ObjectListView): - queryset = Rack.objects.prefetch_related( - 'site', 'location', 'tenant', 'tenant_group', 'role', 'devices__device_type' - ).annotate( + queryset = Rack.objects.prefetch_related('devices__device_type').annotate( device_count=count_related(Device, 'rack') ) filterset = filtersets.RackFilterSet diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index e6b11c427..706670cad 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -586,9 +586,7 @@ class IPRangeIPAddressesView(generic.ObjectChildrenView): template_name = 'ipam/iprange/ip_addresses.html' def get_children(self, request, parent): - return parent.get_child_ips().restrict(request.user, 'view').prefetch_related( - 'vrf', 'role', 'tenant', 'tenant__group', - ) + return parent.get_child_ips().restrict(request.user, 'view') def get_extra_context(self, request, instance): return {