diff --git a/netbox/dcim/models/sites.py b/netbox/dcim/models/sites.py index 51cb63d08..3f2c209c3 100644 --- a/netbox/dcim/models/sites.py +++ b/netbox/dcim/models/sites.py @@ -56,7 +56,7 @@ class Region(NestedGroupModel): csv_headers = ['name', 'slug', 'parent', 'description'] def get_absolute_url(self): - return "{}?region={}".format(reverse('dcim:site_list'), self.slug) + return reverse('dcim:region', args=[self.pk]) def to_csv(self): return ( @@ -108,7 +108,7 @@ class SiteGroup(NestedGroupModel): csv_headers = ['name', 'slug', 'parent', 'description'] def get_absolute_url(self): - return "{}?group={}".format(reverse('dcim:site_list'), self.slug) + return reverse('dcim:sitegroup', args=[self.pk]) def to_csv(self): return ( @@ -324,7 +324,7 @@ class Location(NestedGroupModel): ] def get_absolute_url(self): - return "{}?location_id={}".format(reverse('dcim:rack_list'), self.pk) + return reverse('dcim:location', args=[self.pk]) def to_csv(self): return ( diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index eb4b28710..b56e3bbc4 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -19,12 +19,14 @@ __all__ = ( # -# Rack groups +# Locations # class LocationTable(BaseTable): pk = ToggleColumn() - name = MPTTColumn() + name = MPTTColumn( + linkify=True + ) site = tables.Column( linkify=True ) diff --git a/netbox/dcim/tables/sites.py b/netbox/dcim/tables/sites.py index e22037255..b8d06beb6 100644 --- a/netbox/dcim/tables/sites.py +++ b/netbox/dcim/tables/sites.py @@ -17,7 +17,9 @@ __all__ = ( class RegionTable(BaseTable): pk = ToggleColumn() - name = MPTTColumn() + name = MPTTColumn( + linkify=True + ) site_count = tables.Column( verbose_name='Sites' ) @@ -35,7 +37,9 @@ class RegionTable(BaseTable): class SiteGroupTable(BaseTable): pk = ToggleColumn() - name = MPTTColumn() + name = MPTTColumn( + linkify=True + ) site_count = tables.Column( verbose_name='Sites' ) diff --git a/netbox/dcim/urls.py b/netbox/dcim/urls.py index f07e1911a..b23603c97 100644 --- a/netbox/dcim/urls.py +++ b/netbox/dcim/urls.py @@ -14,6 +14,7 @@ urlpatterns = [ path('regions/import/', views.RegionBulkImportView.as_view(), name='region_import'), path('regions/edit/', views.RegionBulkEditView.as_view(), name='region_bulk_edit'), path('regions/delete/', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'), + path('regions//', views.RegionView.as_view(), name='region'), path('regions//edit/', views.RegionEditView.as_view(), name='region_edit'), path('regions//delete/', views.RegionDeleteView.as_view(), name='region_delete'), path('regions//changelog/', ObjectChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}), @@ -24,6 +25,7 @@ urlpatterns = [ path('site-groups/import/', views.SiteGroupBulkImportView.as_view(), name='sitegroup_import'), path('site-groups/edit/', views.SiteGroupBulkEditView.as_view(), name='sitegroup_bulk_edit'), path('site-groups/delete/', views.SiteGroupBulkDeleteView.as_view(), name='sitegroup_bulk_delete'), + path('site-groups//', views.SiteGroupView.as_view(), name='sitegroup'), path('site-groups//edit/', views.SiteGroupEditView.as_view(), name='sitegroup_edit'), path('site-groups//delete/', views.SiteGroupDeleteView.as_view(), name='sitegroup_delete'), path('site-groups//changelog/', ObjectChangeLogView.as_view(), name='sitegroup_changelog', kwargs={'model': SiteGroup}), @@ -47,6 +49,7 @@ urlpatterns = [ path('locations/import/', views.LocationBulkImportView.as_view(), name='location_import'), path('locations/edit/', views.LocationBulkEditView.as_view(), name='location_bulk_edit'), path('locations/delete/', views.LocationBulkDeleteView.as_view(), name='location_bulk_delete'), + path('locations//', views.LocationView.as_view(), name='location'), path('locations//edit/', views.LocationEditView.as_view(), name='location_edit'), path('locations//delete/', views.LocationDeleteView.as_view(), name='location_delete'), path('locations//changelog/', ObjectChangeLogView.as_view(), name='location_changelog', kwargs={'model': Location}), diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index e1f24df25..3bd456bcc 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -112,6 +112,23 @@ class RegionListView(generic.ObjectListView): table = tables.RegionTable +class RegionView(generic.ObjectView): + queryset = Region.objects.all() + + def get_extra_context(self, request, instance): + sites = Site.objects.restrict(request.user, 'view').filter( + region=instance + ) + + sites_table = tables.SiteTable(sites) + sites_table.columns.hide('region') + paginate_table(sites_table, request) + + return { + 'sites_table': sites_table, + } + + class RegionEditView(generic.ObjectEditView): queryset = Region.objects.all() model_form = forms.RegionForm @@ -169,6 +186,23 @@ class SiteGroupListView(generic.ObjectListView): table = tables.SiteGroupTable +class SiteGroupView(generic.ObjectView): + queryset = SiteGroup.objects.all() + + def get_extra_context(self, request, instance): + sites = Site.objects.restrict(request.user, 'view').filter( + group=instance + ) + + sites_table = tables.SiteTable(sites) + sites_table.columns.hide('group') + paginate_table(sites_table, request) + + return { + 'sites_table': sites_table, + } + + class SiteGroupEditView(generic.ObjectEditView): queryset = SiteGroup.objects.all() model_form = forms.SiteGroupForm @@ -291,6 +325,23 @@ class LocationListView(generic.ObjectListView): table = tables.LocationTable +class LocationView(generic.ObjectView): + queryset = Location.objects.all() + + def get_extra_context(self, request, instance): + devices = Device.objects.restrict(request.user, 'view').filter( + location=instance + ) + + devices_table = tables.DeviceTable(devices) + devices_table.columns.hide('location') + paginate_table(devices_table, request) + + return { + 'devices_table': devices_table, + } + + class LocationEditView(generic.ObjectEditView): queryset = Location.objects.all() model_form = forms.LocationForm diff --git a/netbox/templates/dcim/location.html b/netbox/templates/dcim/location.html new file mode 100644 index 000000000..c12c9f533 --- /dev/null +++ b/netbox/templates/dcim/location.html @@ -0,0 +1,73 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} + +{% block breadcrumbs %} +
  • Location
  • + {% for location in object.get_ancestors %} +
  • {{ location }}
  • + {% endfor %} +
  • {{ object }}
  • +{% endblock %} + +{% block content %} +
    +
    +
    +
    + Location +
    + + + + + + + + + + + + + + + + + +
    Name{{ object.name }}
    Description{{ object.description|placeholder }}
    Parent + {% if object.parent %} + {{ object.parent }} + {% else %} + + {% endif %} +
    Devices + {{ devices_table.rows|length }} +
    +
    + {% plugin_left_page object %} +
    +
    + {% include 'inc/custom_fields_panel.html' %} + {% plugin_right_page object %} +
    +
    +
    +
    +
    +
    + Devices +
    + {% include 'inc/table.html' with table=devices_table %} + {% if perms.dcim.add_device %} + + {% endif %} +
    + {% include 'inc/paginator.html' with paginator=devices_table.paginator page=devices_table.page %} + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/templates/dcim/region.html b/netbox/templates/dcim/region.html new file mode 100644 index 000000000..c79336962 --- /dev/null +++ b/netbox/templates/dcim/region.html @@ -0,0 +1,73 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} + +{% block breadcrumbs %} +
  • Region
  • + {% for region in object.get_ancestors %} +
  • {{ region }}
  • + {% endfor %} +
  • {{ object }}
  • +{% endblock %} + +{% block content %} +
    +
    +
    +
    + Region +
    + + + + + + + + + + + + + + + + + +
    Name{{ object.name }}
    Description{{ object.description|placeholder }}
    Parent + {% if object.parent %} + {{ object.parent }} + {% else %} + + {% endif %} +
    Sites + {{ sites_table.rows|length }} +
    +
    + {% plugin_left_page object %} +
    +
    + {% include 'inc/custom_fields_panel.html' %} + {% plugin_right_page object %} +
    +
    +
    +
    +
    +
    + Sites +
    + {% include 'inc/table.html' with table=sites_table %} + {% if perms.dcim.add_site %} + + {% endif %} +
    + {% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %} + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/templates/dcim/sitegroup.html b/netbox/templates/dcim/sitegroup.html new file mode 100644 index 000000000..95cba7aeb --- /dev/null +++ b/netbox/templates/dcim/sitegroup.html @@ -0,0 +1,73 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} + +{% block breadcrumbs %} +
  • Site Groups
  • + {% for sitegroup in object.get_ancestors %} +
  • {{ sitegroup }}
  • + {% endfor %} +
  • {{ object }}
  • +{% endblock %} + +{% block content %} +
    +
    +
    +
    + Site Group +
    + + + + + + + + + + + + + + + + + +
    Name{{ object.name }}
    Description{{ object.description|placeholder }}
    Parent + {% if object.parent %} + {{ object.parent }} + {% else %} + + {% endif %} +
    Sites + {{ sites_table.rows|length }} +
    +
    + {% plugin_left_page object %} +
    +
    + {% include 'inc/custom_fields_panel.html' %} + {% plugin_right_page object %} +
    +
    +
    +
    +
    +
    + Sites +
    + {% include 'inc/table.html' with table=sites_table %} + {% if perms.dcim.add_site %} + + {% endif %} +
    + {% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %} + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/templates/tenancy/tenantgroup.html b/netbox/templates/tenancy/tenantgroup.html new file mode 100644 index 000000000..4f65ef21a --- /dev/null +++ b/netbox/templates/tenancy/tenantgroup.html @@ -0,0 +1,73 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} + +{% block breadcrumbs %} +
  • Tenant Groups
  • + {% for tenantgroup in object.get_ancestors %} +
  • {{ tenantgroup }}
  • + {% endfor %} +
  • {{ object }}
  • +{% endblock %} + +{% block content %} +
    +
    +
    +
    + Tenant Group +
    + + + + + + + + + + + + + + + + + +
    Name{{ object.name }}
    Description{{ object.description|placeholder }}
    Parent + {% if object.parent %} + {{ object.parent }} + {% else %} + + {% endif %} +
    Sites + {{ tenants_table.rows|length }} +
    +
    + {% plugin_left_page object %} +
    +
    + {% include 'inc/custom_fields_panel.html' %} + {% plugin_right_page object %} +
    +
    +
    +
    +
    +
    + Tenants +
    + {% include 'inc/table.html' with table=tenants_table %} + {% if perms.tenancy.add_tenant %} + + {% endif %} +
    + {% include 'inc/paginator.html' with paginator=tenants_table.paginator page=tenants_table.page %} + {% plugin_full_width_page object %} +
    +
    +{% endblock %} diff --git a/netbox/tenancy/models.py b/netbox/tenancy/models.py index e5ecec639..aa26a60e3 100644 --- a/netbox/tenancy/models.py +++ b/netbox/tenancy/models.py @@ -45,7 +45,7 @@ class TenantGroup(NestedGroupModel): ordering = ['name'] def get_absolute_url(self): - return "{}?group={}".format(reverse('tenancy:tenant_list'), self.slug) + return reverse('tenancy:tenantgroup', args=[self.pk]) def to_csv(self): return ( diff --git a/netbox/tenancy/tables.py b/netbox/tenancy/tables.py index 5b5bc6d73..a826fe5a0 100644 --- a/netbox/tenancy/tables.py +++ b/netbox/tenancy/tables.py @@ -35,7 +35,9 @@ class TenantColumn(tables.TemplateColumn): class TenantGroupTable(BaseTable): pk = ToggleColumn() - name = MPTTColumn() + name = MPTTColumn( + linkify=True + ) tenant_count = LinkedCountColumn( viewname='tenancy:tenant_list', url_params={'group': 'slug'}, diff --git a/netbox/tenancy/urls.py b/netbox/tenancy/urls.py index 1b9dcbe26..a3db431da 100644 --- a/netbox/tenancy/urls.py +++ b/netbox/tenancy/urls.py @@ -13,6 +13,7 @@ urlpatterns = [ path('tenant-groups/import/', views.TenantGroupBulkImportView.as_view(), name='tenantgroup_import'), path('tenant-groups/edit/', views.TenantGroupBulkEditView.as_view(), name='tenantgroup_bulk_edit'), path('tenant-groups/delete/', views.TenantGroupBulkDeleteView.as_view(), name='tenantgroup_bulk_delete'), + path('tenant-groups//', views.TenantGroupView.as_view(), name='tenantgroup'), path('tenant-groups//edit/', views.TenantGroupEditView.as_view(), name='tenantgroup_edit'), path('tenant-groups//delete/', views.TenantGroupDeleteView.as_view(), name='tenantgroup_delete'), path('tenant-groups//changelog/', ObjectChangeLogView.as_view(), name='tenantgroup_changelog', kwargs={'model': TenantGroup}), diff --git a/netbox/tenancy/views.py b/netbox/tenancy/views.py index 11f5ead00..206ff6c7a 100644 --- a/netbox/tenancy/views.py +++ b/netbox/tenancy/views.py @@ -1,9 +1,8 @@ -from django.shortcuts import get_object_or_404, render - from circuits.models import Circuit from dcim.models import Site, Rack, Device, RackReservation from ipam.models import IPAddress, Prefix, VLAN, VRF from netbox.views import generic +from utilities.tables import paginate_table from virtualization.models import VirtualMachine, Cluster from . import filters, forms, tables from .models import Tenant, TenantGroup @@ -24,6 +23,23 @@ class TenantGroupListView(generic.ObjectListView): table = tables.TenantGroupTable +class TenantGroupView(generic.ObjectView): + queryset = TenantGroup.objects.all() + + def get_extra_context(self, request, instance): + tenants = Tenant.objects.restrict(request.user, 'view').filter( + group=instance + ) + + tenants_table = tables.TenantTable(tenants) + tenants_table.columns.hide('group') + paginate_table(tenants_table, request) + + return { + 'tenants_table': tenants_table, + } + + class TenantGroupEditView(generic.ObjectEditView): queryset = TenantGroup.objects.all() model_form = forms.TenantGroupForm