mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
* Enable HTMX rendering for embedded tables * Start converting embedded tables to use HTMX (WIP) * Additional table conversions (WIP) * Standardize HTMX usage for nested group models * Enable HTMX for additional emebedded tables * Fix HTMX table rendering for ObjectChildrenView * Standardize usage of inc/panel_table.html * Hide selection boxes in embedded tables
This commit is contained in:
parent
f74a2536f1
commit
1a2dae3471
@ -29,20 +29,6 @@ class ProviderListView(generic.ObjectListView):
|
||||
class ProviderView(generic.ObjectView):
|
||||
queryset = Provider.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
circuits = Circuit.objects.restrict(request.user, 'view').filter(
|
||||
provider=instance
|
||||
).prefetch_related(
|
||||
'tenant__group', 'termination_a__site', 'termination_z__site',
|
||||
'termination_a__provider_network', 'termination_z__provider_network',
|
||||
)
|
||||
circuits_table = tables.CircuitTable(circuits, user=request.user, exclude=('provider',))
|
||||
circuits_table.configure(request)
|
||||
|
||||
return {
|
||||
'circuits_table': circuits_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(Provider, 'edit')
|
||||
class ProviderEditView(generic.ObjectEditView):
|
||||
@ -93,21 +79,6 @@ class ProviderNetworkListView(generic.ObjectListView):
|
||||
class ProviderNetworkView(generic.ObjectView):
|
||||
queryset = ProviderNetwork.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
circuits = Circuit.objects.restrict(request.user, 'view').filter(
|
||||
Q(termination_a__provider_network=instance.pk) |
|
||||
Q(termination_z__provider_network=instance.pk)
|
||||
).prefetch_related(
|
||||
'tenant__group', 'termination_a__site', 'termination_z__site',
|
||||
'termination_a__provider_network', 'termination_z__provider_network',
|
||||
)
|
||||
circuits_table = tables.CircuitTable(circuits, user=request.user)
|
||||
circuits_table.configure(request)
|
||||
|
||||
return {
|
||||
'circuits_table': circuits_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(ProviderNetwork, 'edit')
|
||||
class ProviderNetworkEditView(generic.ObjectEditView):
|
||||
@ -156,15 +127,6 @@ class CircuitTypeListView(generic.ObjectListView):
|
||||
class CircuitTypeView(generic.ObjectView):
|
||||
queryset = CircuitType.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
circuits = Circuit.objects.restrict(request.user, 'view').filter(type=instance)
|
||||
circuits_table = tables.CircuitTable(circuits, user=request.user, exclude=('type',))
|
||||
circuits_table.configure(request)
|
||||
|
||||
return {
|
||||
'circuits_table': circuits_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(CircuitType, 'edit')
|
||||
class CircuitTypeEditView(generic.ObjectEditView):
|
||||
|
@ -14,7 +14,7 @@ from django.views.generic import View
|
||||
from circuits.models import Circuit, CircuitTermination
|
||||
from extras.views import ObjectConfigContextView
|
||||
from ipam.models import ASN, IPAddress, Prefix, Service, VLAN, VLANGroup
|
||||
from ipam.tables import AssignedIPAddressesTable, InterfaceVLANTable
|
||||
from ipam.tables import InterfaceVLANTable
|
||||
from netbox.views import generic
|
||||
from utilities.forms import ConfirmationForm
|
||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||
@ -212,30 +212,6 @@ class RegionListView(generic.ObjectListView):
|
||||
class RegionView(generic.ObjectView):
|
||||
queryset = Region.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
child_regions = Region.objects.add_related_count(
|
||||
Region.objects.all(),
|
||||
Site,
|
||||
'region',
|
||||
'site_count',
|
||||
cumulative=True
|
||||
).restrict(request.user, 'view').filter(
|
||||
parent__in=instance.get_descendants(include_self=True)
|
||||
)
|
||||
child_regions_table = tables.RegionTable(child_regions)
|
||||
child_regions_table.columns.hide('actions')
|
||||
|
||||
sites = Site.objects.restrict(request.user, 'view').filter(
|
||||
region=instance
|
||||
)
|
||||
sites_table = tables.SiteTable(sites, user=request.user, exclude=('region',))
|
||||
sites_table.configure(request)
|
||||
|
||||
return {
|
||||
'child_regions_table': child_regions_table,
|
||||
'sites_table': sites_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(Region, 'edit')
|
||||
class RegionEditView(generic.ObjectEditView):
|
||||
@ -300,30 +276,6 @@ class SiteGroupListView(generic.ObjectListView):
|
||||
class SiteGroupView(generic.ObjectView):
|
||||
queryset = SiteGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
child_groups = SiteGroup.objects.add_related_count(
|
||||
SiteGroup.objects.all(),
|
||||
Site,
|
||||
'group',
|
||||
'site_count',
|
||||
cumulative=True
|
||||
).restrict(request.user, 'view').filter(
|
||||
parent__in=instance.get_descendants(include_self=True)
|
||||
)
|
||||
child_groups_table = tables.SiteGroupTable(child_groups)
|
||||
child_groups_table.columns.hide('actions')
|
||||
|
||||
sites = Site.objects.restrict(request.user, 'view').filter(
|
||||
group=instance
|
||||
)
|
||||
sites_table = tables.SiteTable(sites, user=request.user, exclude=('group',))
|
||||
sites_table.configure(request)
|
||||
|
||||
return {
|
||||
'child_groups_table': child_groups_table,
|
||||
'sites_table': sites_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(SiteGroup, 'edit')
|
||||
class SiteGroupEditView(generic.ObjectEditView):
|
||||
@ -493,22 +445,6 @@ class LocationView(generic.ObjectView):
|
||||
rack_count = Rack.objects.filter(location__in=location_ids).count()
|
||||
device_count = Device.objects.filter(location__in=location_ids).count()
|
||||
|
||||
child_locations = Location.objects.add_related_count(
|
||||
Location.objects.add_related_count(
|
||||
Location.objects.all(),
|
||||
Device,
|
||||
'location',
|
||||
'device_count',
|
||||
cumulative=True
|
||||
),
|
||||
Rack,
|
||||
'location',
|
||||
'rack_count',
|
||||
cumulative=True
|
||||
).filter(pk__in=location_ids).exclude(pk=instance.pk)
|
||||
child_locations_table = tables.LocationTable(child_locations, user=request.user)
|
||||
child_locations_table.configure(request)
|
||||
|
||||
nonracked_devices = Device.objects.filter(
|
||||
location=instance,
|
||||
rack__isnull=True,
|
||||
@ -518,7 +454,6 @@ class LocationView(generic.ObjectView):
|
||||
return {
|
||||
'rack_count': rack_count,
|
||||
'device_count': device_count,
|
||||
'child_locations_table': child_locations_table,
|
||||
'nonracked_devices': nonracked_devices.order_by('-pk')[:10],
|
||||
'total_nonracked_devices_count': nonracked_devices.count(),
|
||||
}
|
||||
@ -583,20 +518,6 @@ class RackRoleListView(generic.ObjectListView):
|
||||
class RackRoleView(generic.ObjectView):
|
||||
queryset = RackRole.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
racks = Rack.objects.restrict(request.user, 'view').filter(role=instance).annotate(
|
||||
device_count=count_related(Device, 'rack')
|
||||
)
|
||||
|
||||
racks_table = tables.RackTable(racks, user=request.user, exclude=(
|
||||
'role', 'get_utilization', 'get_power_utilization',
|
||||
))
|
||||
racks_table.configure(request)
|
||||
|
||||
return {
|
||||
'racks_table': racks_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(RackRole, 'edit')
|
||||
class RackRoleEditView(generic.ObjectEditView):
|
||||
@ -859,8 +780,6 @@ class ManufacturerView(generic.ObjectView):
|
||||
def get_extra_context(self, request, instance):
|
||||
device_types = DeviceType.objects.restrict(request.user, 'view').filter(
|
||||
manufacturer=instance
|
||||
).annotate(
|
||||
instance_count=count_related(Device, 'device_type')
|
||||
)
|
||||
module_types = ModuleType.objects.restrict(request.user, 'view').filter(
|
||||
manufacturer=instance
|
||||
@ -869,13 +788,10 @@ class ManufacturerView(generic.ObjectView):
|
||||
manufacturer=instance
|
||||
)
|
||||
|
||||
devicetypes_table = tables.DeviceTypeTable(device_types, user=request.user, exclude=('manufacturer',))
|
||||
devicetypes_table.configure(request)
|
||||
|
||||
return {
|
||||
'devicetypes_table': devicetypes_table,
|
||||
'inventory_item_count': inventory_items.count(),
|
||||
'module_type_count': module_types.count(),
|
||||
'devicetype_count': device_types.count(),
|
||||
'inventoryitem_count': inventory_items.count(),
|
||||
'moduletype_count': module_types.count(),
|
||||
}
|
||||
|
||||
|
||||
@ -1726,19 +1642,6 @@ class DeviceRoleListView(generic.ObjectListView):
|
||||
class DeviceRoleView(generic.ObjectView):
|
||||
queryset = DeviceRole.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
devices = Device.objects.restrict(request.user, 'view').filter(
|
||||
device_role=instance
|
||||
)
|
||||
devices_table = tables.DeviceTable(devices, user=request.user, exclude=('device_role',))
|
||||
devices_table.configure(request)
|
||||
|
||||
return {
|
||||
'devices_table': devices_table,
|
||||
'device_count': Device.objects.filter(device_role=instance).count(),
|
||||
'virtualmachine_count': VirtualMachine.objects.filter(role=instance).count(),
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(DeviceRole, 'devices', path='devices')
|
||||
class DeviceRoleDevicesView(generic.ObjectChildrenView):
|
||||
@ -1833,12 +1736,13 @@ class PlatformView(generic.ObjectView):
|
||||
devices = Device.objects.restrict(request.user, 'view').filter(
|
||||
platform=instance
|
||||
)
|
||||
devices_table = tables.DeviceTable(devices, user=request.user, exclude=('platform',))
|
||||
devices_table.configure(request)
|
||||
virtual_machines = VirtualMachine.objects.restrict(request.user, 'view').filter(
|
||||
platform=instance
|
||||
)
|
||||
|
||||
return {
|
||||
'devices_table': devices_table,
|
||||
'virtualmachine_count': VirtualMachine.objects.filter(platform=instance).count()
|
||||
'device_count': devices.count(),
|
||||
'virtualmachine_count': virtual_machines.count()
|
||||
}
|
||||
|
||||
|
||||
@ -2520,12 +2424,6 @@ class InterfaceView(generic.ObjectView):
|
||||
orderable=False
|
||||
)
|
||||
|
||||
# Get assigned IP addresses
|
||||
ipaddress_table = AssignedIPAddressesTable(
|
||||
data=instance.ip_addresses.restrict(request.user, 'view').prefetch_related('vrf', 'tenant'),
|
||||
orderable=False
|
||||
)
|
||||
|
||||
# Get bridge interfaces
|
||||
bridge_interfaces = Interface.objects.restrict(request.user, 'view').filter(bridge=instance)
|
||||
bridge_interfaces_tables = tables.InterfaceTable(
|
||||
@ -2558,7 +2456,6 @@ class InterfaceView(generic.ObjectView):
|
||||
|
||||
return {
|
||||
'vdc_table': vdc_table,
|
||||
'ipaddress_table': ipaddress_table,
|
||||
'bridge_interfaces_table': bridge_interfaces_tables,
|
||||
'child_interfaces_table': child_interfaces_tables,
|
||||
'vlan_table': vlan_table,
|
||||
@ -3533,20 +3430,6 @@ class PowerPanelListView(generic.ObjectListView):
|
||||
class PowerPanelView(generic.ObjectView):
|
||||
queryset = PowerPanel.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
power_feeds = PowerFeed.objects.restrict(request.user).filter(power_panel=instance)
|
||||
powerfeed_table = tables.PowerFeedTable(
|
||||
data=power_feeds,
|
||||
orderable=False
|
||||
)
|
||||
if request.user.has_perm('dcim.delete_cable'):
|
||||
powerfeed_table.columns.show('pk')
|
||||
powerfeed_table.exclude = ['power_panel']
|
||||
|
||||
return {
|
||||
'powerfeed_table': powerfeed_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(PowerPanel, 'edit')
|
||||
class PowerPanelEditView(generic.ObjectEditView):
|
||||
@ -3648,16 +3531,6 @@ class VirtualDeviceContextListView(generic.ObjectListView):
|
||||
class VirtualDeviceContextView(generic.ObjectView):
|
||||
queryset = VirtualDeviceContext.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
interfaces_table = tables.InterfaceTable(instance.interfaces, user=request.user)
|
||||
interfaces_table.configure(request)
|
||||
interfaces_table.columns.hide('device')
|
||||
|
||||
return {
|
||||
'interfaces_table': interfaces_table,
|
||||
'interface_count': instance.interfaces.count(),
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(VirtualDeviceContext, 'edit')
|
||||
class VirtualDeviceContextEditView(generic.ObjectEditView):
|
||||
|
@ -5,11 +5,9 @@ from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from circuits.models import Provider, Circuit
|
||||
from circuits.tables import ProviderTable
|
||||
from circuits.models import Provider
|
||||
from dcim.filtersets import InterfaceFilterSet
|
||||
from dcim.models import Interface, Site, Device
|
||||
from dcim.tables import SiteTable
|
||||
from netbox.views import generic
|
||||
from utilities.utils import count_related
|
||||
from utilities.views import ViewTab, register_model_view
|
||||
@ -167,17 +165,6 @@ class RIRListView(generic.ObjectListView):
|
||||
class RIRView(generic.ObjectView):
|
||||
queryset = RIR.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
aggregates = Aggregate.objects.restrict(request.user, 'view').filter(rir=instance).annotate(
|
||||
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
|
||||
)
|
||||
aggregates_table = tables.AggregateTable(aggregates, user=request.user, exclude=('rir', 'utilization'))
|
||||
aggregates_table.configure(request)
|
||||
|
||||
return {
|
||||
'aggregates_table': aggregates_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(RIR, 'edit')
|
||||
class RIREditView(generic.ObjectEditView):
|
||||
@ -232,22 +219,11 @@ class ASNView(generic.ObjectView):
|
||||
queryset = ASN.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
# Gather assigned Sites
|
||||
sites = instance.sites.restrict(request.user, 'view')
|
||||
sites_table = SiteTable(sites, user=request.user)
|
||||
sites_table.configure(request)
|
||||
|
||||
# Gather assigned Providers
|
||||
providers = instance.providers.restrict(request.user, 'view').annotate(
|
||||
count_circuits=count_related(Circuit, 'provider')
|
||||
)
|
||||
providers_table = ProviderTable(providers, user=request.user)
|
||||
providers_table.configure(request)
|
||||
providers = instance.providers.restrict(request.user, 'view')
|
||||
|
||||
return {
|
||||
'sites_table': sites_table,
|
||||
'sites_count': sites.count(),
|
||||
'providers_table': providers_table,
|
||||
'providers_count': providers.count(),
|
||||
}
|
||||
|
||||
@ -392,18 +368,6 @@ class RoleListView(generic.ObjectListView):
|
||||
class RoleView(generic.ObjectView):
|
||||
queryset = Role.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
prefixes = Prefix.objects.restrict(request.user, 'view').filter(
|
||||
role=instance
|
||||
)
|
||||
|
||||
prefixes_table = tables.PrefixTable(prefixes, user=request.user, exclude=('role', 'utilization'))
|
||||
prefixes_table.configure(request)
|
||||
|
||||
return {
|
||||
'prefixes_table': prefixes_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(Role, 'edit')
|
||||
class RoleEditView(generic.ObjectEditView):
|
||||
@ -750,7 +714,6 @@ class IPAddressView(generic.ObjectView):
|
||||
return {
|
||||
'parent_prefixes_table': parent_prefixes_table,
|
||||
'duplicate_ips_table': duplicate_ips_table,
|
||||
'more_duplicate_ips': duplicate_ips.count() > 10,
|
||||
'related_ips_table': related_ips_table,
|
||||
'services': services,
|
||||
}
|
||||
@ -888,17 +851,9 @@ class VLANGroupView(generic.ObjectView):
|
||||
vlans_table.columns.show('pk')
|
||||
vlans_table.configure(request)
|
||||
|
||||
# Compile permissions list for rendering the object table
|
||||
permissions = {
|
||||
'add': request.user.has_perm('ipam.add_vlan'),
|
||||
'change': request.user.has_perm('ipam.change_vlan'),
|
||||
'delete': request.user.has_perm('ipam.delete_vlan'),
|
||||
}
|
||||
|
||||
return {
|
||||
'vlans_count': vlans_count,
|
||||
'vlans_table': vlans_table,
|
||||
'permissions': permissions,
|
||||
}
|
||||
|
||||
|
||||
@ -954,11 +909,6 @@ class FHRPGroupView(generic.ObjectView):
|
||||
queryset = FHRPGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
# Get assigned IP addresses
|
||||
ipaddress_table = tables.AssignedIPAddressesTable(
|
||||
data=instance.ip_addresses.restrict(request.user, 'view'),
|
||||
orderable=False
|
||||
)
|
||||
|
||||
# Get assigned interfaces
|
||||
members_table = tables.FHRPGroupAssignmentTable(
|
||||
@ -968,7 +918,6 @@ class FHRPGroupView(generic.ObjectView):
|
||||
members_table.columns.hide('group')
|
||||
|
||||
return {
|
||||
'ipaddress_table': ipaddress_table,
|
||||
'members_table': members_table,
|
||||
'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
|
||||
}
|
||||
@ -1250,10 +1199,6 @@ class L2VPNView(generic.ObjectView):
|
||||
queryset = L2VPN.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
terminations = L2VPNTermination.objects.restrict(request.user, 'view').filter(l2vpn=instance)
|
||||
terminations_table = tables.L2VPNTerminationTable(terminations, user=request.user, exclude=('l2vpn', ))
|
||||
terminations_table.configure(request)
|
||||
|
||||
import_targets_table = tables.RouteTargetTable(
|
||||
instance.import_targets.prefetch_related('tenant'),
|
||||
orderable=False
|
||||
@ -1264,7 +1209,6 @@ class L2VPNView(generic.ObjectView):
|
||||
)
|
||||
|
||||
return {
|
||||
'terminations_table': terminations_table,
|
||||
'import_targets_table': import_targets_table,
|
||||
'export_targets_table': export_targets_table,
|
||||
}
|
||||
|
@ -4,6 +4,8 @@ from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models.fields.related import RelatedField
|
||||
from django.urls import reverse
|
||||
from django.urls.exceptions import NoReverseMatch
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import gettext as _
|
||||
from django_tables2.data import TableQuerysetData
|
||||
@ -12,7 +14,7 @@ from extras.models import CustomField, CustomLink
|
||||
from extras.choices import CustomFieldVisibilityChoices
|
||||
from netbox.tables import columns
|
||||
from utilities.paginator import EnhancedPaginator, get_paginate_count
|
||||
from utilities.utils import highlight_string, title
|
||||
from utilities.utils import get_viewname, highlight_string, title
|
||||
|
||||
__all__ = (
|
||||
'BaseTable',
|
||||
@ -197,6 +199,19 @@ class NetBoxTable(BaseTable):
|
||||
|
||||
super().__init__(*args, extra_columns=extra_columns, **kwargs)
|
||||
|
||||
@property
|
||||
def htmx_url(self):
|
||||
"""
|
||||
Return the base HTML request URL for embedded tables.
|
||||
"""
|
||||
if getattr(self, 'embedded', False):
|
||||
viewname = get_viewname(self._meta.model, action='list')
|
||||
try:
|
||||
return reverse(viewname)
|
||||
except NoReverseMatch:
|
||||
pass
|
||||
return ''
|
||||
|
||||
|
||||
class SearchTable(tables.Table):
|
||||
object_type = columns.ContentTypeColumn(
|
||||
|
@ -20,7 +20,7 @@ from utilities.choices import ImportFormatChoices
|
||||
from utilities.error_handlers import handle_protectederror
|
||||
from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
|
||||
from utilities.forms import BulkRenameForm, ConfirmationForm, ImportForm, restrict_form_fields
|
||||
from utilities.htmx import is_htmx
|
||||
from utilities.htmx import is_embedded, is_htmx
|
||||
from utilities.permissions import get_permission_for_model
|
||||
from utilities.views import GetReturnURLMixin
|
||||
from .base import BaseMultiObjectView
|
||||
@ -161,6 +161,11 @@ class ObjectListView(BaseMultiObjectView, ActionsMixin, TableMixin):
|
||||
|
||||
# If this is an HTMX request, return only the rendered table HTML
|
||||
if is_htmx(request):
|
||||
if is_embedded(request):
|
||||
table.embedded = True
|
||||
# Hide selection checkboxes
|
||||
if 'pk' in table.base_columns:
|
||||
table.columns.hide('pk')
|
||||
return render(request, 'htmx/table.html', {
|
||||
'table': table,
|
||||
})
|
||||
|
@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<th scope="row">Circuits</th>
|
||||
<td>
|
||||
<a href="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}">{{ circuits_table.rows|length }}</a>
|
||||
<a href="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}">{{ object.circuits.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -49,10 +49,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Circuits</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table circuits_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=circuits_table.paginator page=circuits_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'circuits:circuit_list' %}?type_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -40,7 +40,7 @@
|
||||
<tr>
|
||||
<th scope="row">Circuits</th>
|
||||
<td>
|
||||
<a href="{% url 'circuits:circuit_list' %}?provider={{ object.slug }}">{{ circuits_table.rows|length }}</a>
|
||||
<a href="{% url 'circuits:circuit_list' %}?provider={{ object.slug }}">{{ object.circuits.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -60,10 +60,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Circuits</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table circuits_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=circuits_table.paginator page=circuits_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'circuits:circuit_list' %}?provider_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -50,10 +50,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Circuits</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table circuits_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=circuits_table.paginator page=circuits_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'circuits:circuit_list' %}?provider_network_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@
|
||||
<div class="tab-pane show active" id="object-list" role="tabpanel" aria-labelledby="object-list-tab">
|
||||
{% include 'inc/table_controls_htmx.html' %}
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -10,7 +10,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -45,14 +45,14 @@
|
||||
<tr>
|
||||
<th scope="row">Devices</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:device_list' %}?role_id={{ object.pk }}">{{ device_count }}</a>
|
||||
<a href="{% url 'dcim:device_list' %}?role_id={{ object.pk }}">{{ object.devices.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Virtual Machines</th>
|
||||
<td>
|
||||
{% if object.vm_role %}
|
||||
<a href="{% url 'virtualization:virtualmachine_list' %}?role_id={{ object.pk }}">{{ virtualmachine_count }}</a>
|
||||
<a href="{% url 'virtualization:virtualmachine_list' %}?role_id={{ object.pk }}">{{ object.virtual_machines.count }}</a>
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
|
@ -8,7 +8,7 @@
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">{{ title }}</h5>
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
<div class="card-footer noprint">
|
||||
@ -36,7 +36,7 @@
|
||||
{% else %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">{{ title }}</h5>
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -344,13 +344,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">IP Addresses</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% if ipaddress_table.rows %}
|
||||
{% render_table ipaddress_table 'inc/table.html' %}
|
||||
{% else %}
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:ipaddress_list' %}?interface_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.ipam.add_ipaddress %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'ipam:ipaddress_add' %}?device={{ object.device.pk }}&interface={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
|
||||
|
@ -92,11 +92,11 @@
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Locations</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table child_locations_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=child_locations_table.paginator page=child_locations_table.page %}
|
||||
</div>
|
||||
<h5 class="card-header">Child Locations</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:location_list' %}?parent_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -45,19 +45,19 @@
|
||||
<tr>
|
||||
<th scope="row">Device types</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}">{{ devicetypes_table.rows|length }}</a>
|
||||
<a href="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}">{{ devicetype_count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Module types</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:moduletype_list' %}?manufacturer_id={{ object.pk }}">{{ module_type_count }}</a>
|
||||
<a href="{% url 'dcim:moduletype_list' %}?manufacturer_id={{ object.pk }}">{{ moduletype_count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Inventory Items</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:inventoryitem_list' %}?manufacturer_id={{ object.pk }}">{{ inventory_item_count }}</a>
|
||||
<a href="{% url 'dcim:inventoryitem_list' %}?manufacturer_id={{ object.pk }}">{{ inventoryitem_count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -76,10 +76,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Device Types</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table devicetypes_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=devicetypes_table.paginator page=devicetypes_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:devicetype_list' %}?manufacturer_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">{{ title }}</h5>
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
<div class="card-footer noprint">
|
||||
@ -36,7 +36,7 @@
|
||||
{% else %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">{{ title }}</h5>
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,7 +46,7 @@
|
||||
<tr>
|
||||
<th scope="row">Devices</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}">{{ devices_table.rows|length }}</a>
|
||||
<a href="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}">{{ device_count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -78,10 +78,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Devices</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table devices_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=devices_table.paginator page=devices_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:device_list' %}?platform_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -45,40 +45,42 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-3">
|
||||
<div class="col col-md-12">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table powerfeed_table 'inc/table.html' %}
|
||||
</div>
|
||||
<div class="card-footer noprint">
|
||||
{% if perms.dcim.change_powerfeed %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:powerfeed_bulk_edit' %}?return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.delete_cable %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:powerfeed_bulk_disconnect' %}?return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> Disconnect
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.delete_powerfeed %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'dcim:powerfeed_bulk_delete' %}?return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.add_powerfeed %}
|
||||
<div class="float-end">
|
||||
<a href="{% url 'dcim:powerfeed_add' %}?power_panel={{ object.pk }}&return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Power Feeds
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col col-md-12">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">Power Feeds</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:powerfeed_list' %}?power_panel_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
<div class="card-footer noprint">
|
||||
{% if perms.dcim.change_powerfeed %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:powerfeed_bulk_edit' %}?return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.delete_cable %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:powerfeed_bulk_disconnect' %}?return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> Disconnect
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.delete_powerfeed %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'dcim:powerfeed_bulk_delete' %}?return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.dcim.add_powerfeed %}
|
||||
<div class="float-end">
|
||||
<a href="{% url 'dcim:powerfeed_add' %}?power_panel={{ object.pk }}&return_url={% url 'dcim:powerpanel' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Power Feeds
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -37,7 +37,7 @@
|
||||
<tr>
|
||||
<th scope="row">Racks</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}">{{ racks_table.rows|length }}</a>
|
||||
<a href="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}">{{ object.racks.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -55,10 +55,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Racks</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table racks_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=racks_table.paginator page=racks_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:rack_list' %}?role_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -22,9 +22,7 @@
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Region
|
||||
</h5>
|
||||
<h5 class="card-header">Region</h5>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
@ -42,7 +40,7 @@
|
||||
<tr>
|
||||
<th scope="row">Sites</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:site_list' %}?region_id={{ object.pk }}">{{ sites_table.rows|length }}</a>
|
||||
<a href="{% url 'dcim:site_list' %}?region_id={{ object.pk }}">{{ object.sites.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -55,12 +53,11 @@
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Child Regions
|
||||
</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table child_regions_table 'inc/table.html' %}
|
||||
</div>
|
||||
<h5 class="card-header">Child Regions</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:region_list' %}?parent_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.dcim.add_region %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'dcim:region_add' %}?parent={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||
@ -76,10 +73,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Sites</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table sites_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:site_list' %}?region_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -22,9 +22,7 @@
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Site Group
|
||||
</h5>
|
||||
<h5 class="card-header">Site Group</h5>
|
||||
<div class="card-body">
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
@ -42,7 +40,7 @@
|
||||
<tr>
|
||||
<th scope="row">Sites</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:site_list' %}?group_id={{ object.pk }}">{{ sites_table.rows|length }}</a>
|
||||
<a href="{% url 'dcim:site_list' %}?group_id={{ object.pk }}">{{ object.sites.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -55,12 +53,11 @@
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Child Groups
|
||||
</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table child_groups_table 'inc/table.html' %}
|
||||
</div>
|
||||
<h5 class="card-header">Child Groups</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:sitegroup_list' %}?parent_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.dcim.add_sitegroup %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'dcim:sitegroup_add' %}?parent={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||
@ -76,10 +73,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Sites</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table sites_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:site_list' %}?group_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -49,6 +49,12 @@
|
||||
{{ object.tenant|linkify|placeholder }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Interfaces</th>
|
||||
<td>
|
||||
<a href="{% url 'dcim:interface_list' %}?vdc_id={{ object.pk }}">{{ object.interfaces.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -65,10 +71,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Interfaces</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table interfaces_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=interfaces_table.paginator page=interfaces_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:interface_list' %}?vdc_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -109,7 +109,7 @@ Context:
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -70,9 +70,10 @@
|
||||
<i class="mdi mdi-clipboard-clock"></i>
|
||||
<span class="ms-1">Change Log</span>
|
||||
</h6>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table changelog_table 'inc/table.html' %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'extras:objectchange_list' %}?sort=-time"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
{% with preferences|get_key:"pagination.placement" as paginator_placement %}
|
||||
{% if paginator_placement == 'top' or paginator_placement == 'both' %}
|
||||
{% include 'inc/paginator_htmx.html' with paginator=table.paginator page=table.page %}
|
||||
{% include 'inc/paginator_htmx.html' with table=table paginator=table.paginator page=table.page %}
|
||||
{% endif %}
|
||||
{% render_table table 'inc/table_htmx.html' %}
|
||||
{% if paginator_placement != 'top' %}
|
||||
{% include 'inc/paginator_htmx.html' with paginator=table.paginator page=table.page %}
|
||||
{% include 'inc/paginator_htmx.html' with table=table paginator=table.paginator page=table.page %}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
@ -7,9 +7,9 @@
|
||||
<div class="btn-group btn-group-sm" role="group" aria-label="Pages">
|
||||
{% if page.has_previous %}
|
||||
<a href="#"
|
||||
hx-get="{% querystring request page=page.previous_page_number %}"
|
||||
hx-target="#object_list"
|
||||
hx-push-url="true"
|
||||
hx-get="{{ table.htmx_url }}{% querystring request page=page.previous_page_number %}"
|
||||
hx-target="closest .htmx-container"
|
||||
{% if not table.embedded %}hx-push-url="true"{% endif %}
|
||||
class="btn btn-outline-secondary"
|
||||
>
|
||||
<i class="mdi mdi-chevron-double-left"></i>
|
||||
@ -18,9 +18,9 @@
|
||||
{% for p in page.smart_pages %}
|
||||
{% if p %}
|
||||
<a href="#"
|
||||
hx-get="{% querystring request page=p %}"
|
||||
hx-target="#object_list"
|
||||
hx-push-url="true"
|
||||
hx-get="{{ table.htmx_url }}{% querystring request page=p %}"
|
||||
hx-target="closest .htmx-container"
|
||||
{% if not table.embedded %}hx-push-url="true"{% endif %}
|
||||
class="btn btn-outline-secondary{% if page.number == p %} active{% endif %}"
|
||||
>
|
||||
{{ p }}
|
||||
@ -33,9 +33,9 @@
|
||||
{% endfor %}
|
||||
{% if page.has_next %}
|
||||
<a href="#"
|
||||
hx-get="{% querystring request page=page.next_page_number %}"
|
||||
hx-target="#object_list"
|
||||
hx-push-url="true"
|
||||
hx-get="{{ table.htmx_url }}{% querystring request page=page.next_page_number %}"
|
||||
hx-target="closest .htmx-container"
|
||||
{% if not table.embedded %}hx-push-url="true"{% endif %}
|
||||
class="btn btn-outline-secondary"
|
||||
>
|
||||
<i class="mdi mdi-chevron-double-right"></i>
|
||||
@ -55,9 +55,9 @@
|
||||
{% for n in page.paginator.get_page_lengths %}
|
||||
<li>
|
||||
<a href="#"
|
||||
hx-get="{% querystring request per_page=n %}"
|
||||
hx-target="#object_list"
|
||||
hx-push-url="true"
|
||||
hx-get="{{ table.htmx_url }}{% querystring request per_page=n %}"
|
||||
hx-target="closest .htmx-container"
|
||||
{% if not table.embedded %}hx-push-url="true"{% endif %}
|
||||
class="dropdown-item"
|
||||
>{{ n }}</a>
|
||||
</li>
|
||||
|
@ -1,16 +1,14 @@
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
<div class="card {% if panel_class %}bg-{{ panel_class }}{% endif %}">
|
||||
{% if heading %}
|
||||
<h5 class="card-header">
|
||||
{{ heading }}
|
||||
</h5>
|
||||
<div class="card {% if panel_class %}border-{{ panel_class }}{% endif %}">
|
||||
{% if heading %}
|
||||
<h5 class="card-header{% if panel_class %} text-{{ panel_class }}{% endif %}">{{ heading }}</h5>
|
||||
{% endif %}
|
||||
<div class="card-body table-responsive">
|
||||
{% if table.rows %}
|
||||
{% render_table table 'inc/table.html' %}
|
||||
{% else %}
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
<div class="card-body table-responsive">
|
||||
{% if table.rows %}
|
||||
{% render_table table 'inc/table.html' %}
|
||||
{% else %}
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,59 +1,56 @@
|
||||
{% load django_tables2 %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
|
||||
{% if table.show_header %}
|
||||
<thead>
|
||||
<table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
|
||||
{% if table.show_header %}
|
||||
<thead>
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
{% if column.orderable %}
|
||||
<th {{ column.attrs.th.as_html }}>
|
||||
{% if column.is_ordered %}
|
||||
<div class="float-end">
|
||||
<a href="#"
|
||||
hx-get="{{ table.htmx_url }}{% querystring table.prefixed_order_by_field='' %}"
|
||||
hx-target="closest .htmx-container"
|
||||
{% if not table.embedded %}hx-push-url="true"{% endif %}
|
||||
class="text-danger"
|
||||
><i class="mdi mdi-close"></i></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a href="#"
|
||||
hx-get="{{ table.htmx_url }}{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}"
|
||||
hx-target="closest .htmx-container"
|
||||
{% if not table.embedded %}hx-push-url="true"{% endif %}
|
||||
>{{ column.header }}</a>
|
||||
</th>
|
||||
{% else %}
|
||||
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for row in table.page.object_list|default:table.rows %}
|
||||
<tr {{ row.attrs.as_html }}>
|
||||
{% for column, cell in row.items %}
|
||||
<td {{ column.attrs.td.as_html }}>{{ cell }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
{% if table.empty_text %}
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
{% if column.orderable %}
|
||||
<th {{ column.attrs.th.as_html }}>
|
||||
{% if column.is_ordered %}
|
||||
<div class="float-end">
|
||||
<a href="#"
|
||||
hx-get="{% querystring table.prefixed_order_by_field='' %}"
|
||||
hx-target="#object_list"
|
||||
hx-push-url="true"
|
||||
class="text-danger"
|
||||
><i class="mdi mdi-close"></i></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<a href="#"
|
||||
hx-get="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}"
|
||||
hx-target="#object_list"
|
||||
hx-push-url="true"
|
||||
>{{ column.header }}</a>
|
||||
</th>
|
||||
{% else %}
|
||||
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<td colspan="{{ table.columns|length }}" class="text-center text-muted">— {{ table.empty_text }} —</td>
|
||||
</tr>
|
||||
</thead>
|
||||
{% endif %}
|
||||
<tbody>
|
||||
{% for row in table.page.object_list|default:table.rows %}
|
||||
<tr {{ row.attrs.as_html }}>
|
||||
{% for column, cell in row.items %}
|
||||
<td {{ column.attrs.td.as_html }}>{{ cell }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% empty %}
|
||||
{% if table.empty_text %}
|
||||
<tr>
|
||||
<td colspan="{{ table.columns|length }}" class="text-center text-muted">— {{ table.empty_text }} —</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% if table.has_footer %}
|
||||
<tfoot>
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
<td>{{ column.footer }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tfoot>
|
||||
{% endif %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% if table.has_footer %}
|
||||
<tfoot>
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
<td>{{ column.footer }}</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tfoot>
|
||||
{% endif %}
|
||||
</table>
|
||||
|
@ -18,7 +18,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -75,17 +75,17 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Sites</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table sites_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=sites_table.paginator page=sites_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'dcim:site_list' %}?asn_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h5 class="card-header">Providers</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table providers_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=providers_table.paginator page=providers_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'circuits:provider_list' %}?asn_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -69,13 +69,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Virtual IP Addresses</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% if ipaddress_table.rows %}
|
||||
{% render_table ipaddress_table 'inc/table.html' %}
|
||||
{% else %}
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:ipaddress_list' %}?fhrpgroup_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.ipam.add_ipaddress %}
|
||||
<div class="card-footer text-end">
|
||||
<a href="{% url 'ipam:ipaddress_add' %}?fhrpgroup={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
|
||||
@ -84,16 +81,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card">
|
||||
<h5 class="card-header">Members</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% if members_table.rows %}
|
||||
{% render_table members_table 'inc/table.html' %}
|
||||
{% else %}
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'inc/panel_table.html' with table=members_table heading='Members' %}
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -114,30 +114,9 @@
|
||||
<div class="col col-md-8">
|
||||
{% include 'inc/panel_table.html' with table=parent_prefixes_table heading='Parent Prefixes' %}
|
||||
{% if duplicate_ips_table.rows %}
|
||||
{# Custom version of panel_table.html #}
|
||||
<div class="card border-danger">
|
||||
<h5 class="card-header">
|
||||
<span class="text-danger">Duplicate IP Addresses</span>
|
||||
{% if more_duplicate_ips %}
|
||||
<div class="float-end">
|
||||
<a type="button" class="btn btn-primary btn-sm"
|
||||
{% if object.vrf %}
|
||||
href="{% url 'ipam:ipaddress_list' %}?address={{ object.address.ip }}&vrf_id={{ object.vrf.pk }}"
|
||||
{% else %}
|
||||
href="{% url 'ipam:ipaddress_list' %}?address={{ object.address.ip }}&vrf_id=null"
|
||||
{% endif %}
|
||||
>Show all</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table duplicate_ips_table 'inc/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'inc/panel_table.html' with table=duplicate_ips_table heading='Duplicate IPs' panel_class='danger' %}
|
||||
{% endif %}
|
||||
<div class="my-3">
|
||||
{% include 'inc/panel_table.html' with table=related_ips_table heading='Related IP Addresses' %}
|
||||
</div>
|
||||
{% include 'inc/panel_table.html' with table=related_ips_table heading='Related IPs' %}
|
||||
{% include 'inc/panels/services.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -55,9 +55,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Terminations</h5>
|
||||
<div class="card-body">
|
||||
{% render_table terminations_table 'inc/table.html' %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:l2vpntermination_list' %}?l2vpn_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.ipam.add_l2vpntermination %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'ipam:l2vpntermination_add' %}?l2vpn={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-primary btn-sm{% if not object.can_add_termination %} disabled" aria-disabled="true{% endif %}">
|
||||
|
@ -16,7 +16,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,7 +18,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -35,16 +35,16 @@
|
||||
<tr>
|
||||
<th scope="row">Aggregates</th>
|
||||
<td>
|
||||
<a href="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}">{{ aggregates_table.rows|length }}</a>
|
||||
<a href="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}">{{ object.aggregates.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
@ -53,10 +53,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Aggregates</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table aggregates_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=aggregates_table.paginator page=aggregates_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:aggregate_list' %}?rir_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -35,40 +35,28 @@
|
||||
<tr>
|
||||
<th scope="row">Prefixes</th>
|
||||
<td>
|
||||
<a href="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}">{{ prefixes_table.rows|length }}</a>
|
||||
<a href="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}">{{ object.prefixes.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">IP Ranges</th>
|
||||
<td>
|
||||
{% with ipranges_count=object.ip_ranges.count %}
|
||||
{% if ipranges_count %}
|
||||
<a href="{% url 'ipam:iprange_list' %}?role_id={{ object.pk }}">{{ ipranges_count }}</a>
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<a href="{% url 'ipam:iprange_list' %}?role_id={{ object.pk }}">{{ object.ip_ranges.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">VLANs</th>
|
||||
<td>
|
||||
{% with vlans_count=object.vlans.count %}
|
||||
{% if vlans_count %}
|
||||
<a href="{% url 'ipam:vlan_list' %}?role_id={{ object.pk }}">{{ vlans_count }}</a>
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<a href="{% url 'ipam:vlan_list' %}?role_id={{ object.pk }}">{{ object.vlans.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
@ -77,10 +65,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Prefixes</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table prefixes_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=prefixes_table.paginator page=prefixes_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:prefix_list' %}?role_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -81,24 +81,22 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Prefixes
|
||||
</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table prefix_table 'inc/table.html' %}
|
||||
</div>
|
||||
{% if perms.ipam.add_prefix %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'ipam:prefix_add' %}?{% if object.tenant %}tenant={{ object.tenant.pk }}&{% endif %}site={{ object.site.pk }}&vlan={{ object.pk }}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i>
|
||||
Add a Prefix
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Prefixes</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:prefix_list' %}?vlan_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.ipam.add_prefix %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'ipam:prefix_add' %}?{% if object.tenant %}tenant={{ object.tenant.pk }}&{% endif %}site={{ object.site.pk }}&vlan={{ object.pk }}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> Add a Prefix
|
||||
</a>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
<div class="row px-3">
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@
|
||||
<tr>
|
||||
<th scope="row">Contacts</th>
|
||||
<td>
|
||||
<a href="{% url 'tenancy:contact_list' %}?group_id={{ object.pk }}">{{ contacts_table.rows|length }}</a>
|
||||
<a href="{% url 'tenancy:contact_list' %}?group_id={{ object.pk }}">{{ object.contacts.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -46,12 +46,11 @@
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Child Groups
|
||||
</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table child_groups_table 'inc/table.html' %}
|
||||
</div>
|
||||
<h5 class="card-header">Child Groups</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'tenancy:contactgroup_list' %}?parent_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.tenancy.add_contactgroup %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'tenancy:contactgroup_add' %}?parent={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||
@ -63,16 +62,14 @@
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Contacts</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table contacts_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=contacts_table.paginator page=contacts_table.page %}
|
||||
</div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Contacts</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'tenancy:contact_list' %}?group_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -42,7 +42,7 @@
|
||||
<tr>
|
||||
<th scope="row">Tenants</th>
|
||||
<td>
|
||||
<a href="{% url 'tenancy:tenant_list' %}?group_id={{ object.pk }}">{{ tenants_table.rows|length }}</a>
|
||||
<a href="{% url 'tenancy:tenant_list' %}?group_id={{ object.pk }}">{{ object.tenants.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -53,6 +53,20 @@
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">Child Groups</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'tenancy:tenantgroup_list' %}?parent_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.tenancy.add_tenantgroup %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'tenancy:tenantgroup_add' %}?parent={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Tenant Group
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
@ -60,10 +74,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Tenants</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table tenants_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=tenants_table.paginator page=tenants_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'tenancy:tenant_list' %}?group_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<form action="{% url 'virtualization:cluster_remove_devices' pk=object.pk %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<th scope="row">Clusters</th>
|
||||
<td>
|
||||
<a href="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}">{{ clusters_table.rows|length }}</a>
|
||||
<a href="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}">{{ object.clusters.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -50,10 +50,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Clusters</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table clusters_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=clusters_table.paginator page=clusters_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'virtualization:cluster_list' %}?group_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -31,7 +31,7 @@
|
||||
<tr>
|
||||
<th scope="row">Clusters</th>
|
||||
<td>
|
||||
<a href="{% url 'virtualization:cluster_list' %}?type_id={{ object.pk }}">{{ clusters_table.rows|length }}</a>
|
||||
<a href="{% url 'virtualization:cluster_list' %}?type_id={{ object.pk }}">{{ object.clusters.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -49,10 +49,10 @@
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">Clusters</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table clusters_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=clusters_table.paginator page=clusters_table.page %}
|
||||
</div>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'virtualization:cluster_list' %}?type_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -80,16 +80,11 @@
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
IP Addresses
|
||||
</h5>
|
||||
<div class="card-body table-responsive">
|
||||
{% if ipaddress_table.rows %}
|
||||
{% render_table ipaddress_table 'inc/table.html' %}
|
||||
{% else %}
|
||||
<div class="text-muted">None</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<h5 class="card-header">IP Addresses</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'ipam:ipaddress_list' %}?vminterface_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.ipam.add_ipaddress %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'ipam:ipaddress_add' %}?virtual_machine={{ object.virtual_machine.pk }}&vminterface={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-sm btn-primary">
|
||||
|
@ -40,7 +40,7 @@
|
||||
<tr>
|
||||
<th scope="row">Wireless LANs</th>
|
||||
<td>
|
||||
<a href="{% url 'wireless:wirelesslan_list' %}?group_id={{ object.pk }}">{{ wirelesslans_table.rows|length }}</a>
|
||||
<a href="{% url 'wireless:wirelesslan_list' %}?group_id={{ object.pk }}">{{ object.wirelesslans.count }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -51,17 +51,31 @@
|
||||
</div>
|
||||
<div class="col col-md-6">
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
<div class="card">
|
||||
<h5 class="card-header">Child Groups</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'wireless:wirelesslangroup_list' %}?parent_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
{% if perms.wireless.add_wirelesslangroup %}
|
||||
<div class="card-footer text-end noprint">
|
||||
<a href="{% url 'wireless:wirelesslangroup_add' %}?parent={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Wireless LAN Group
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">Wireless LANs</div>
|
||||
<div class="card-body table-responsive">
|
||||
{% render_table wirelesslans_table 'inc/table.html' %}
|
||||
{% include 'inc/paginator.html' with paginator=wirelesslans_table.paginator page=wirelesslans_table.page %}
|
||||
</div>
|
||||
<h5 class="card-header">Wireless LANs</h5>
|
||||
<div class="card-body htmx-container table-responsive"
|
||||
hx-get="{% url 'wireless:wirelesslan_list' %}?group_id={{ object.pk }}"
|
||||
hx-trigger="load"
|
||||
></div>
|
||||
</div>
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
|
@ -34,17 +34,6 @@ class TenantGroupListView(generic.ObjectListView):
|
||||
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, user=request.user, exclude=('group',))
|
||||
tenants_table.configure(request)
|
||||
|
||||
return {
|
||||
'tenants_table': tenants_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(TenantGroup, 'edit')
|
||||
class TenantGroupEditView(generic.ObjectEditView):
|
||||
@ -182,32 +171,6 @@ class ContactGroupListView(generic.ObjectListView):
|
||||
class ContactGroupView(generic.ObjectView):
|
||||
queryset = ContactGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
child_groups = ContactGroup.objects.add_related_count(
|
||||
ContactGroup.objects.all(),
|
||||
Contact,
|
||||
'group',
|
||||
'contact_count',
|
||||
cumulative=True
|
||||
).restrict(request.user, 'view').filter(
|
||||
parent__in=instance.get_descendants(include_self=True)
|
||||
)
|
||||
child_groups_table = tables.ContactGroupTable(child_groups)
|
||||
child_groups_table.columns.hide('actions')
|
||||
|
||||
contacts = Contact.objects.restrict(request.user, 'view').filter(
|
||||
group=instance
|
||||
).annotate(
|
||||
assignment_count=count_related(ContactAssignment, 'contact')
|
||||
)
|
||||
contacts_table = tables.ContactTable(contacts, user=request.user, exclude=('group',))
|
||||
contacts_table.configure(request)
|
||||
|
||||
return {
|
||||
'child_groups_table': child_groups_table,
|
||||
'contacts_table': contacts_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(ContactGroup, 'edit')
|
||||
class ContactGroupEditView(generic.ObjectEditView):
|
||||
|
@ -1,5 +1,19 @@
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
def is_htmx(request):
|
||||
"""
|
||||
Returns True if the request was made by HTMX; False otherwise.
|
||||
"""
|
||||
return 'Hx-Request' in request.headers
|
||||
|
||||
|
||||
def is_embedded(request):
|
||||
"""
|
||||
Returns True if the request indicates that it originates from a URL different from
|
||||
the path being requested.
|
||||
"""
|
||||
hx_current_url = request.headers.get('HX-Current-URL', None)
|
||||
if not hx_current_url:
|
||||
return False
|
||||
return request.path != urlparse(hx_current_url).path
|
||||
|
@ -100,20 +100,6 @@ class ClusterGroupListView(generic.ObjectListView):
|
||||
class ClusterGroupView(generic.ObjectView):
|
||||
queryset = ClusterGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
clusters = Cluster.objects.restrict(request.user, 'view').filter(
|
||||
group=instance
|
||||
).annotate(
|
||||
device_count=count_related(Device, 'cluster'),
|
||||
vm_count=count_related(VirtualMachine, 'cluster')
|
||||
)
|
||||
clusters_table = tables.ClusterTable(clusters, user=request.user, exclude=('group',))
|
||||
clusters_table.configure(request)
|
||||
|
||||
return {
|
||||
'clusters_table': clusters_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(ClusterGroup, 'edit')
|
||||
class ClusterGroupEditView(generic.ObjectEditView):
|
||||
@ -444,11 +430,6 @@ class VMInterfaceView(generic.ObjectView):
|
||||
queryset = VMInterface.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
# Get assigned IP addresses
|
||||
ipaddress_table = AssignedIPAddressesTable(
|
||||
data=instance.ip_addresses.restrict(request.user, 'view'),
|
||||
orderable=False
|
||||
)
|
||||
|
||||
# Get child interfaces
|
||||
child_interfaces = VMInterface.objects.restrict(request.user, 'view').filter(parent=instance)
|
||||
@ -473,7 +454,6 @@ class VMInterfaceView(generic.ObjectView):
|
||||
)
|
||||
|
||||
return {
|
||||
'ipaddress_table': ipaddress_table,
|
||||
'child_interfaces_table': child_interfaces_tables,
|
||||
'vlan_table': vlan_table,
|
||||
}
|
||||
|
@ -27,17 +27,6 @@ class WirelessLANGroupListView(generic.ObjectListView):
|
||||
class WirelessLANGroupView(generic.ObjectView):
|
||||
queryset = WirelessLANGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
wirelesslans = WirelessLAN.objects.restrict(request.user, 'view').filter(
|
||||
group=instance
|
||||
)
|
||||
wirelesslans_table = tables.WirelessLANTable(wirelesslans, user=request.user, exclude=('group',))
|
||||
wirelesslans_table.configure(request)
|
||||
|
||||
return {
|
||||
'wirelesslans_table': wirelesslans_table,
|
||||
}
|
||||
|
||||
|
||||
@register_model_view(WirelessLANGroup, 'edit')
|
||||
class WirelessLANGroupEditView(generic.ObjectEditView):
|
||||
|
Loading…
Reference in New Issue
Block a user