From 4eb5e90ccc1af8b42cc2973896529a3c81de2bce Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Fri, 12 May 2023 19:56:26 +0530 Subject: [PATCH] Adds contact tabs (#12460) * adds contact tabs #11599 * fixed lint issues * changes as per review * changes as per review * replaces generic object template with base template --- netbox/circuits/views.py | 17 ++++- netbox/dcim/views.py | 41 ++++++++++++ netbox/ipam/views.py | 6 ++ netbox/templates/circuits/circuit.html | 1 - netbox/templates/circuits/provider.html | 1 - .../templates/circuits/provideraccount.html | 1 - netbox/templates/dcim/device.html | 1 - netbox/templates/dcim/location.html | 1 - netbox/templates/dcim/manufacturer.html | 1 - netbox/templates/dcim/powerpanel.html | 1 - netbox/templates/dcim/rack.html | 1 - netbox/templates/dcim/region.html | 1 - netbox/templates/dcim/site.html | 1 - netbox/templates/dcim/sitegroup.html | 1 - netbox/templates/inc/panels/contacts.html | 63 ------------------- netbox/templates/ipam/l2vpn.html | 1 - netbox/templates/tenancy/object_contacts.html | 27 ++++++++ netbox/templates/tenancy/tenant.html | 1 - netbox/templates/virtualization/cluster.html | 1 - .../virtualization/clustergroup.html | 1 - .../virtualization/virtualmachine.html | 1 - netbox/tenancy/views.py | 32 +++++++++- netbox/virtualization/views.py | 18 +++++- 23 files changed, 137 insertions(+), 83 deletions(-) delete mode 100644 netbox/templates/inc/panels/contacts.html create mode 100644 netbox/templates/tenancy/object_contacts.html diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index e5f4faee1..f1cfdd1d5 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -1,10 +1,10 @@ from django.contrib import messages from django.db import transaction -from django.db.models import Q from django.shortcuts import get_object_or_404, redirect, render from dcim.views import PathTraceView from netbox.views import generic +from tenancy.views import ObjectContactsView from utilities.forms import ConfirmationForm from utilities.utils import count_related from utilities.views import register_model_view @@ -73,6 +73,11 @@ class ProviderBulkDeleteView(generic.BulkDeleteView): table = tables.ProviderTable +@register_model_view(Provider, 'contacts') +class ProviderContactsView(ObjectContactsView): + queryset = Provider.objects.all() + + # # ProviderAccounts # @@ -134,6 +139,11 @@ class ProviderAccountBulkDeleteView(generic.BulkDeleteView): table = tables.ProviderAccountTable +@register_model_view(ProviderAccount, 'contacts') +class ProviderAccountContactsView(ObjectContactsView): + queryset = ProviderAccount.objects.all() + + # # Provider networks # @@ -389,6 +399,11 @@ class CircuitSwapTerminations(generic.ObjectEditView): }) +@register_model_view(Circuit, 'contacts') +class CircuitContactsView(ObjectContactsView): + queryset = Circuit.objects.all() + + # # Circuit terminations # diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index bcbbf1739..0def4f4a8 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -20,6 +20,7 @@ from extras.views import ObjectConfigContextView from ipam.models import ASN, IPAddress, Prefix, VLAN, VLANGroup from ipam.tables import InterfaceVLANTable from netbox.views import generic +from tenancy.views import ObjectContactsView from utilities.forms import ConfirmationForm from utilities.paginator import EnhancedPaginator, get_paginate_count from utilities.permissions import get_permission_for_model @@ -267,6 +268,11 @@ class RegionBulkDeleteView(generic.BulkDeleteView): table = tables.RegionTable +@register_model_view(Region, 'contacts') +class RegionContactsView(ObjectContactsView): + queryset = Region.objects.all() + + # # Site groups # @@ -342,6 +348,11 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView): table = tables.SiteGroupTable +@register_model_view(SiteGroup, 'contacts') +class SiteGroupContactsView(ObjectContactsView): + queryset = SiteGroup.objects.all() + + # # Sites # @@ -435,6 +446,11 @@ class SiteBulkDeleteView(generic.BulkDeleteView): table = tables.SiteTable +@register_model_view(Site, 'contacts') +class SiteContactsView(ObjectContactsView): + queryset = Site.objects.all() + + # # Locations # @@ -523,6 +539,11 @@ class LocationBulkDeleteView(generic.BulkDeleteView): table = tables.LocationTable +@register_model_view(Location, 'contacts') +class LocationContactsView(ObjectContactsView): + queryset = Location.objects.all() + + # # Rack roles # @@ -740,6 +761,11 @@ class RackBulkDeleteView(generic.BulkDeleteView): table = tables.RackTable +@register_model_view(Rack, 'contacts') +class RackContactsView(ObjectContactsView): + queryset = Rack.objects.all() + + # # Rack reservations # @@ -874,6 +900,11 @@ class ManufacturerBulkDeleteView(generic.BulkDeleteView): table = tables.ManufacturerTable +@register_model_view(Manufacturer, 'contacts') +class ManufacturerContactsView(ObjectContactsView): + queryset = Manufacturer.objects.all() + + # # Device types # @@ -2088,6 +2119,11 @@ class DeviceBulkRenameView(generic.BulkRenameView): table = tables.DeviceTable +@register_model_view(Device, 'contacts') +class DeviceContactsView(ObjectContactsView): + queryset = Device.objects.all() + + # # Modules # @@ -3469,6 +3505,11 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView): table = tables.PowerPanelTable +@register_model_view(PowerPanel, 'contacts') +class PowerPanelContactsView(ObjectContactsView): + queryset = PowerPanel.objects.all() + + # # Power feeds # diff --git a/netbox/ipam/views.py b/netbox/ipam/views.py index 6b19b502d..6b73a061b 100644 --- a/netbox/ipam/views.py +++ b/netbox/ipam/views.py @@ -9,6 +9,7 @@ from circuits.models import Provider from dcim.filtersets import InterfaceFilterSet from dcim.models import Interface, Site from netbox.views import generic +from tenancy.views import ObjectContactsView from utilities.utils import count_related from utilities.views import ViewTab, register_model_view from virtualization.filtersets import VMInterfaceFilterSet @@ -1300,6 +1301,11 @@ class L2VPNBulkDeleteView(generic.BulkDeleteView): table = tables.L2VPNTable +@register_model_view(L2VPN, 'contacts') +class L2VPNContactsView(ObjectContactsView): + queryset = L2VPN.objects.all() + + # # L2VPN terminations # diff --git a/netbox/templates/circuits/circuit.html b/netbox/templates/circuits/circuit.html index ee994e959..a5913e2ad 100644 --- a/netbox/templates/circuits/circuit.html +++ b/netbox/templates/circuits/circuit.html @@ -70,7 +70,6 @@
{% include 'circuits/inc/circuit_termination.html' with termination=object.termination_a side='A' %} {% include 'circuits/inc/circuit_termination.html' with termination=object.termination_z side='Z' %} - {% include 'inc/panels/contacts.html' %} {% include 'inc/panels/image_attachments.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/circuits/provider.html b/netbox/templates/circuits/provider.html index 5a565ea29..c721d5a58 100644 --- a/netbox/templates/circuits/provider.html +++ b/netbox/templates/circuits/provider.html @@ -43,7 +43,6 @@
{% include 'inc/panels/related_objects.html' %} {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/circuits/provideraccount.html b/netbox/templates/circuits/provideraccount.html index 63344ada1..c55663b4a 100644 --- a/netbox/templates/circuits/provideraccount.html +++ b/netbox/templates/circuits/provideraccount.html @@ -38,7 +38,6 @@ {% include 'inc/panels/related_objects.html' %} {% include 'inc/panels/comments.html' %} {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index aa1b80cf7..b0e67269c 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -298,7 +298,6 @@
{% endif %} - {% include 'inc/panels/contacts.html' %} {% include 'inc/panels/image_attachments.html' %}
Dimensions
diff --git a/netbox/templates/dcim/location.html b/netbox/templates/dcim/location.html index 193d93f9a..795aeb35f 100644 --- a/netbox/templates/dcim/location.html +++ b/netbox/templates/dcim/location.html @@ -65,7 +65,6 @@
{% include 'inc/panels/related_objects.html' %} - {% include 'inc/panels/contacts.html' %} {% include 'dcim/inc/nonracked_devices.html' %} {% include 'inc/panels/image_attachments.html' %} {% plugin_right_page object %} diff --git a/netbox/templates/dcim/manufacturer.html b/netbox/templates/dcim/manufacturer.html index a60b3503c..8233b6fc8 100644 --- a/netbox/templates/dcim/manufacturer.html +++ b/netbox/templates/dcim/manufacturer.html @@ -51,7 +51,6 @@
{% include 'inc/panels/related_objects.html' %} {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/powerpanel.html b/netbox/templates/dcim/powerpanel.html index af08f3023..ea9210ba7 100644 --- a/netbox/templates/dcim/powerpanel.html +++ b/netbox/templates/dcim/powerpanel.html @@ -40,7 +40,6 @@
{% include 'inc/panels/related_objects.html' %} {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/contacts.html' %} {% include 'inc/panels/image_attachments.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 9cb046b4e..52b5d4bfe 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -191,7 +191,6 @@ {% include 'inc/panels/related_objects.html' %} {% include 'dcim/inc/nonracked_devices.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %} diff --git a/netbox/templates/dcim/region.html b/netbox/templates/dcim/region.html index 85587e4b5..05cc424d7 100644 --- a/netbox/templates/dcim/region.html +++ b/netbox/templates/dcim/region.html @@ -46,7 +46,6 @@
{% include 'inc/panels/related_objects.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/dcim/site.html b/netbox/templates/dcim/site.html index 91fdba7be..697737ceb 100644 --- a/netbox/templates/dcim/site.html +++ b/netbox/templates/dcim/site.html @@ -131,7 +131,6 @@
{% include 'inc/panels/related_objects.html' with filter_name='site_id' %} - {% include 'inc/panels/contacts.html' %}
Locations
diff --git a/netbox/templates/dcim/sitegroup.html b/netbox/templates/dcim/sitegroup.html index 2cf8e7168..819022a34 100644 --- a/netbox/templates/dcim/sitegroup.html +++ b/netbox/templates/dcim/sitegroup.html @@ -42,7 +42,6 @@
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/inc/panels/contacts.html b/netbox/templates/inc/panels/contacts.html deleted file mode 100644 index 359ad8d7e..000000000 --- a/netbox/templates/inc/panels/contacts.html +++ /dev/null @@ -1,63 +0,0 @@ -{% load helpers %} - -
-
Contacts
-
- {% with contacts=object.contacts.all %} - {% if contacts.exists %} - - - - - - - - - - {% for contact in contacts %} - - - - - - - - - {% endfor %} -
NameRolePriorityPhoneEmail
{{ contact.contact|linkify }}{{ contact.role|placeholder }}{{ contact.get_priority_display|placeholder }} - {% if contact.contact.phone %} - {{ contact.contact.phone }} - {% else %} - {{ ''|placeholder }} - {% endif %} - - {% if contact.contact.email %} - {{ contact.contact.email }} - {% else %} - {{ ''|placeholder }} - {% endif %} - - {% if perms.tenancy.change_contactassignment %} - - - - {% endif %} - {% if perms.tenancy.delete_contactassignment %} - - - - {% endif %} -
- {% else %} -
None
- {% endif %} - {% endwith %} -
- {% if perms.tenancy.add_contactassignment %} - - {% endif %} -
diff --git a/netbox/templates/ipam/l2vpn.html b/netbox/templates/ipam/l2vpn.html index 87050eb26..8896dd6c2 100644 --- a/netbox/templates/ipam/l2vpn.html +++ b/netbox/templates/ipam/l2vpn.html @@ -37,7 +37,6 @@ {% plugin_left_page object %}
- {% include 'inc/panels/contacts.html' %} {% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/comments.html' %} {% plugin_right_page object %} diff --git a/netbox/templates/tenancy/object_contacts.html b/netbox/templates/tenancy/object_contacts.html new file mode 100644 index 000000000..aca63a379 --- /dev/null +++ b/netbox/templates/tenancy/object_contacts.html @@ -0,0 +1,27 @@ +{% extends base_template %} +{% load helpers %} + +{% block extra_controls %} + {% if perms.tenancy.add_contactassignment %} + + Add a contact + + {% endif %} +{% endblock %} + +{% block content %} + {% include 'inc/table_controls_htmx.html' with table_modal="ContactTable_config" %} +
+ {% csrf_token %} +
+
+ {% include 'htmx/table.html' %} +
+
+
+{% endblock content %} + +{% block modals %} + {{ block.super }} + {% table_config_form table %} +{% endblock modals %} diff --git a/netbox/templates/tenancy/tenant.html b/netbox/templates/tenancy/tenant.html index da48f1ef5..34abe5c01 100644 --- a/netbox/templates/tenancy/tenant.html +++ b/netbox/templates/tenancy/tenant.html @@ -30,7 +30,6 @@ {% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} {% include 'inc/panels/comments.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/virtualization/cluster.html b/netbox/templates/virtualization/cluster.html index 3dfef108b..508bca547 100644 --- a/netbox/templates/virtualization/cluster.html +++ b/netbox/templates/virtualization/cluster.html @@ -84,7 +84,6 @@
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/virtualization/clustergroup.html b/netbox/templates/virtualization/clustergroup.html index 510433068..2496ad085 100644 --- a/netbox/templates/virtualization/clustergroup.html +++ b/netbox/templates/virtualization/clustergroup.html @@ -37,7 +37,6 @@
{% include 'inc/panels/related_objects.html' %} {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html index 5098a2f8f..51fd8aa80 100644 --- a/netbox/templates/virtualization/virtualmachine.html +++ b/netbox/templates/virtualization/virtualmachine.html @@ -158,7 +158,6 @@ {% endif %} - {% include 'inc/panels/contacts.html' %} {% plugin_right_page object %} diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index b9ada8640..5f8a7e314 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -7,17 +7,40 @@ from dcim.models import Cable, Device, Location, Rack, RackReservation, Site, Vi from ipam.models import Aggregate, ASN, IPAddress, IPRange, L2VPN, Prefix, VLAN, VRF from netbox.views import generic from utilities.utils import count_related -from utilities.views import register_model_view +from utilities.views import register_model_view, ViewTab from virtualization.models import VirtualMachine, Cluster from wireless.models import WirelessLAN, WirelessLink from . import filtersets, forms, tables from .models import * +class ObjectContactsView(generic.ObjectChildrenView): + child_model = Contact + table = tables.ContactTable + filterset = filtersets.ContactFilterSet + template_name = 'tenancy/object_contacts.html' + tab = ViewTab( + label=_('Contacts'), + badge=lambda obj: obj.contacts.count(), + permission='tenancy.view_contact', + weight=5000 + ) + + def get_children(self, request, parent): + return Contact.objects.annotate( + assignment_count=count_related(ContactAssignment, 'contact') + ).restrict(request.user, 'view').filter(assignments__object_id=parent.pk) + + def get_extra_context(self, request, instance): + return { + 'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html', + } + # # Tenant groups # + class TenantGroupListView(generic.ObjectListView): queryset = TenantGroup.objects.add_related_count( TenantGroup.objects.all(), @@ -165,6 +188,11 @@ class TenantBulkDeleteView(generic.BulkDeleteView): table = tables.TenantTable +@register_model_view(Tenant, 'contacts') +class TenantContactsView(ObjectContactsView): + queryset = Tenant.objects.all() + + # # Contact groups # @@ -342,11 +370,11 @@ class ContactBulkDeleteView(generic.BulkDeleteView): filterset = filtersets.ContactFilterSet table = tables.ContactTable - # # Contact assignments # + class ContactAssignmentListView(generic.ObjectListView): queryset = ContactAssignment.objects.all() filterset = filtersets.ContactAssignmentFilterSet diff --git a/netbox/virtualization/views.py b/netbox/virtualization/views.py index 9014aa9dd..4a501e14e 100644 --- a/netbox/virtualization/views.py +++ b/netbox/virtualization/views.py @@ -9,9 +9,10 @@ from dcim.filtersets import DeviceFilterSet from dcim.models import Device from dcim.tables import DeviceTable from extras.views import ObjectConfigContextView -from ipam.models import IPAddress, Service +from ipam.models import IPAddress from ipam.tables import InterfaceVLANTable from netbox.views import generic +from tenancy.views import ObjectContactsView from utilities.utils import count_related from utilities.views import ViewTab, register_model_view from . import filtersets, forms, tables @@ -140,6 +141,11 @@ class ClusterGroupBulkDeleteView(generic.BulkDeleteView): table = tables.ClusterGroupTable +@register_model_view(ClusterGroup, 'contacts') +class ClusterGroupContactsView(ObjectContactsView): + queryset = ClusterGroup.objects.all() + + # # Clusters # @@ -312,6 +318,11 @@ class ClusterRemoveDevicesView(generic.ObjectEditView): }) +@register_model_view(Cluster, 'contacts') +class ClusterContactsView(ObjectContactsView): + queryset = Cluster.objects.all() + + # # Virtual machines # @@ -390,6 +401,11 @@ class VirtualMachineBulkDeleteView(generic.BulkDeleteView): table = tables.VirtualMachineTable +@register_model_view(VirtualMachine, 'contacts') +class VirtualMachineContactsView(ObjectContactsView): + queryset = VirtualMachine.objects.all() + + # # VM interfaces #