mirror of
https://github.com/netbox-community/netbox.git
synced 2026-04-19 07:30:01 +02:00
* #20923: Migrate IPAM views to declarative layouts * #20923: Migrate IPAM views to declarative layouts * fix VRF view * fix Route Target view * fix addressing details modal * fix add prefix button * fix add aggregate button * fix add VLAN button * fix breadcrumb on Application Service * fix breadcrumb on ANS * move attrs to separate file * review feedback * review feedback * review feedback * review feedback
This commit is contained in:
@@ -367,6 +367,16 @@ class Prefix(ContactsMixin, GetAvailablePrefixesMixin, CachedScopeMixin, Primary
|
|||||||
def get_status_color(self):
|
def get_status_color(self):
|
||||||
return PrefixStatusChoices.colors.get(self.status)
|
return PrefixStatusChoices.colors.get(self.status)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def aggregate(self):
|
||||||
|
"""
|
||||||
|
Return the containing Aggregate for this Prefix, if any.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return Aggregate.objects.get(prefix__net_contains_or_equals=str(self.prefix))
|
||||||
|
except Aggregate.DoesNotExist:
|
||||||
|
return None
|
||||||
|
|
||||||
def get_parents(self, include_self=False):
|
def get_parents(self, include_self=False):
|
||||||
"""
|
"""
|
||||||
Return all containing Prefixes in the hierarchy.
|
Return all containing Prefixes in the hierarchy.
|
||||||
|
|||||||
24
netbox/ipam/ui/attrs.py
Normal file
24
netbox/ipam/ui/attrs.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
|
from netbox.ui import attrs
|
||||||
|
|
||||||
|
|
||||||
|
class VRFDisplayAttr(attrs.ObjectAttribute):
|
||||||
|
"""
|
||||||
|
Renders a VRF reference, displaying 'Global' when no VRF is assigned. Optionally includes
|
||||||
|
the route distinguisher (RD).
|
||||||
|
"""
|
||||||
|
template_name = 'ipam/attrs/vrf.html'
|
||||||
|
|
||||||
|
def __init__(self, *args, show_rd=False, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.show_rd = show_rd
|
||||||
|
|
||||||
|
def render(self, obj, context):
|
||||||
|
value = self.get_value(obj)
|
||||||
|
return render_to_string(self.template_name, {
|
||||||
|
**self.get_context(obj, context),
|
||||||
|
'name': context['name'],
|
||||||
|
'value': value,
|
||||||
|
'show_rd': self.show_rd,
|
||||||
|
})
|
||||||
@@ -2,14 +2,15 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from netbox.ui import actions, panels
|
from netbox.ui import actions, attrs, panels
|
||||||
|
|
||||||
|
from .attrs import VRFDisplayAttr
|
||||||
|
|
||||||
|
|
||||||
class FHRPGroupAssignmentsPanel(panels.ObjectPanel):
|
class FHRPGroupAssignmentsPanel(panels.ObjectPanel):
|
||||||
"""
|
"""
|
||||||
A panel which lists all FHRP group assignments for a given object.
|
A panel which lists all FHRP group assignments for a given object.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template_name = 'ipam/panels/fhrp_groups.html'
|
template_name = 'ipam/panels/fhrp_groups.html'
|
||||||
title = _('FHRP Groups')
|
title = _('FHRP Groups')
|
||||||
actions = [
|
actions = [
|
||||||
@@ -35,3 +36,220 @@ class FHRPGroupAssignmentsPanel(panels.ObjectPanel):
|
|||||||
label=_('Assign Group'),
|
label=_('Assign Group'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class VRFPanel(panels.ObjectAttributesPanel):
|
||||||
|
rd = attrs.TextAttr('rd', label=_('Route Distinguisher'), style='font-monospace')
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
enforce_unique = attrs.BooleanAttr('enforce_unique', label=_('Unique IP Space'))
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class RouteTargetPanel(panels.ObjectAttributesPanel):
|
||||||
|
name = attrs.TextAttr('name', style='font-monospace')
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class RIRPanel(panels.OrganizationalObjectPanel):
|
||||||
|
is_private = attrs.BooleanAttr('is_private', label=_('Private'))
|
||||||
|
|
||||||
|
|
||||||
|
class ASNRangePanel(panels.ObjectAttributesPanel):
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
rir = attrs.RelatedObjectAttr('rir', linkify=True, label=_('RIR'))
|
||||||
|
range = attrs.TextAttr('range_as_string_with_asdot', label=_('Range'))
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class ASNPanel(panels.ObjectAttributesPanel):
|
||||||
|
asn = attrs.TextAttr('asn_with_asdot', label=_('AS Number'))
|
||||||
|
rir = attrs.RelatedObjectAttr('rir', linkify=True, label=_('RIR'))
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class AggregatePanel(panels.ObjectAttributesPanel):
|
||||||
|
family = attrs.TextAttr('family', format_string='IPv{}', label=_('Family'))
|
||||||
|
rir = attrs.RelatedObjectAttr('rir', linkify=True, label=_('RIR'))
|
||||||
|
utilization = attrs.TemplatedAttr(
|
||||||
|
'prefix',
|
||||||
|
template_name='ipam/aggregate/attrs/utilization.html',
|
||||||
|
label=_('Utilization'),
|
||||||
|
)
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
date_added = attrs.DateTimeAttr('date_added', spec='date', label=_('Date Added'))
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class RolePanel(panels.OrganizationalObjectPanel):
|
||||||
|
weight = attrs.NumericAttr('weight')
|
||||||
|
|
||||||
|
|
||||||
|
class IPRangePanel(panels.ObjectAttributesPanel):
|
||||||
|
family = attrs.TextAttr('family', format_string='IPv{}', label=_('Family'))
|
||||||
|
start_address = attrs.TextAttr('start_address', label=_('Starting Address'))
|
||||||
|
end_address = attrs.TextAttr('end_address', label=_('Ending Address'))
|
||||||
|
size = attrs.NumericAttr('size')
|
||||||
|
mark_populated = attrs.BooleanAttr('mark_populated', label=_('Marked Populated'))
|
||||||
|
mark_utilized = attrs.BooleanAttr('mark_utilized', label=_('Marked Utilized'))
|
||||||
|
utilization = attrs.TemplatedAttr(
|
||||||
|
'utilization',
|
||||||
|
template_name='ipam/iprange/attrs/utilization.html',
|
||||||
|
label=_('Utilization'),
|
||||||
|
)
|
||||||
|
vrf = VRFDisplayAttr('vrf', label=_('VRF'), show_rd=True)
|
||||||
|
role = attrs.RelatedObjectAttr('role', linkify=True)
|
||||||
|
status = attrs.ChoiceAttr('status')
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class IPAddressPanel(panels.ObjectAttributesPanel):
|
||||||
|
family = attrs.TextAttr('family', format_string='IPv{}', label=_('Family'))
|
||||||
|
vrf = VRFDisplayAttr('vrf', label=_('VRF'))
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
status = attrs.ChoiceAttr('status')
|
||||||
|
role = attrs.ChoiceAttr('role')
|
||||||
|
dns_name = attrs.TextAttr('dns_name', label=_('DNS Name'))
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
assigned_object = attrs.RelatedObjectAttr(
|
||||||
|
'assigned_object',
|
||||||
|
linkify=True,
|
||||||
|
grouped_by='parent_object',
|
||||||
|
label=_('Assignment'),
|
||||||
|
)
|
||||||
|
nat_inside = attrs.TemplatedAttr(
|
||||||
|
'nat_inside',
|
||||||
|
template_name='ipam/ipaddress/attrs/nat_inside.html',
|
||||||
|
label=_('NAT (inside)'),
|
||||||
|
)
|
||||||
|
nat_outside = attrs.TemplatedAttr(
|
||||||
|
'nat_outside',
|
||||||
|
template_name='ipam/ipaddress/attrs/nat_outside.html',
|
||||||
|
label=_('NAT (outside)'),
|
||||||
|
)
|
||||||
|
is_primary_ip = attrs.BooleanAttr('is_primary_ip', label=_('Primary IP'))
|
||||||
|
is_oob_ip = attrs.BooleanAttr('is_oob_ip', label=_('OOB IP'))
|
||||||
|
|
||||||
|
|
||||||
|
class PrefixPanel(panels.ObjectAttributesPanel):
|
||||||
|
family = attrs.TextAttr('family', format_string='IPv{}', label=_('Family'))
|
||||||
|
vrf = VRFDisplayAttr('vrf', label=_('VRF'))
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
aggregate = attrs.TemplatedAttr(
|
||||||
|
'aggregate',
|
||||||
|
template_name='ipam/prefix/attrs/aggregate.html',
|
||||||
|
label=_('Aggregate'),
|
||||||
|
)
|
||||||
|
scope = attrs.GenericForeignKeyAttr('scope', linkify=True)
|
||||||
|
vlan = attrs.RelatedObjectAttr('vlan', linkify=True, label=_('VLAN'), grouped_by='group')
|
||||||
|
status = attrs.ChoiceAttr('status')
|
||||||
|
role = attrs.RelatedObjectAttr('role', linkify=True)
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
is_pool = attrs.BooleanAttr('is_pool', label=_('Is a pool'))
|
||||||
|
|
||||||
|
|
||||||
|
class VLANGroupPanel(panels.ObjectAttributesPanel):
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
scope = attrs.GenericForeignKeyAttr('scope', linkify=True)
|
||||||
|
vid_ranges = attrs.TemplatedAttr(
|
||||||
|
'vid_ranges_items',
|
||||||
|
template_name='ipam/vlangroup/attrs/vid_ranges.html',
|
||||||
|
label=_('VLAN IDs'),
|
||||||
|
)
|
||||||
|
utilization = attrs.UtilizationAttr('utilization')
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
|
||||||
|
|
||||||
|
class VLANTranslationPolicyPanel(panels.ObjectAttributesPanel):
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class VLANTranslationRulePanel(panels.ObjectAttributesPanel):
|
||||||
|
policy = attrs.RelatedObjectAttr('policy', linkify=True)
|
||||||
|
local_vid = attrs.NumericAttr('local_vid', label=_('Local VID'))
|
||||||
|
remote_vid = attrs.NumericAttr('remote_vid', label=_('Remote VID'))
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class FHRPGroupPanel(panels.ObjectAttributesPanel):
|
||||||
|
protocol = attrs.ChoiceAttr('protocol')
|
||||||
|
group_id = attrs.NumericAttr('group_id', label=_('Group ID'))
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
member_count = attrs.NumericAttr('member_count', label=_('Members'))
|
||||||
|
|
||||||
|
|
||||||
|
class FHRPGroupAuthPanel(panels.ObjectAttributesPanel):
|
||||||
|
title = _('Authentication')
|
||||||
|
|
||||||
|
auth_type = attrs.ChoiceAttr('auth_type', label=_('Authentication Type'))
|
||||||
|
auth_key = attrs.TextAttr('auth_key', label=_('Authentication Key'))
|
||||||
|
|
||||||
|
|
||||||
|
class VLANPanel(panels.ObjectAttributesPanel):
|
||||||
|
region = attrs.NestedObjectAttr('site.region', linkify=True, label=_('Region'))
|
||||||
|
site = attrs.RelatedObjectAttr('site', linkify=True)
|
||||||
|
group = attrs.RelatedObjectAttr('group', linkify=True)
|
||||||
|
vid = attrs.NumericAttr('vid', label=_('VLAN ID'))
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
|
||||||
|
status = attrs.ChoiceAttr('status')
|
||||||
|
role = attrs.RelatedObjectAttr('role', linkify=True)
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
qinq_role = attrs.ChoiceAttr('qinq_role', label=_('Q-in-Q Role'))
|
||||||
|
qinq_svlan = attrs.RelatedObjectAttr('qinq_svlan', linkify=True, label=_('Q-in-Q SVLAN'))
|
||||||
|
l2vpn = attrs.RelatedObjectAttr('l2vpn_termination.l2vpn', linkify=True, label=_('L2VPN'))
|
||||||
|
|
||||||
|
|
||||||
|
class VLANCustomerVLANsPanel(panels.ObjectsTablePanel):
|
||||||
|
"""
|
||||||
|
A panel listing customer VLANs (C-VLANs) for an S-VLAN. Only renders when the VLAN has Q-in-Q
|
||||||
|
role 'svlan'.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(
|
||||||
|
'ipam.vlan',
|
||||||
|
filters={'qinq_svlan_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Customer VLANs'),
|
||||||
|
actions=[
|
||||||
|
actions.AddObject(
|
||||||
|
'ipam.vlan',
|
||||||
|
url_params={
|
||||||
|
'qinq_role': 'cvlan',
|
||||||
|
'qinq_svlan': lambda ctx: ctx['object'].pk,
|
||||||
|
},
|
||||||
|
label=_('Add a VLAN'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def render(self, context):
|
||||||
|
obj = context.get('object')
|
||||||
|
if not obj or obj.qinq_role != 'svlan':
|
||||||
|
return ''
|
||||||
|
return super().render(context)
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceTemplatePanel(panels.ObjectAttributesPanel):
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
protocol = attrs.ChoiceAttr('protocol')
|
||||||
|
ports = attrs.TextAttr('port_list', label=_('Ports'))
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|
||||||
|
|
||||||
|
class ServicePanel(panels.ObjectAttributesPanel):
|
||||||
|
name = attrs.TextAttr('name')
|
||||||
|
parent = attrs.RelatedObjectAttr('parent', linkify=True)
|
||||||
|
protocol = attrs.ChoiceAttr('protocol')
|
||||||
|
ports = attrs.TextAttr('port_list', label=_('Ports'))
|
||||||
|
ip_addresses = attrs.TemplatedAttr(
|
||||||
|
'ipaddresses',
|
||||||
|
template_name='ipam/service/attrs/ip_addresses.html',
|
||||||
|
label=_('IP Addresses'),
|
||||||
|
)
|
||||||
|
description = attrs.TextAttr('description')
|
||||||
|
|||||||
@@ -9,8 +9,16 @@ from circuits.models import Provider
|
|||||||
from dcim.filtersets import InterfaceFilterSet
|
from dcim.filtersets import InterfaceFilterSet
|
||||||
from dcim.forms import InterfaceFilterForm
|
from dcim.forms import InterfaceFilterForm
|
||||||
from dcim.models import Device, Interface, Site
|
from dcim.models import Device, Interface, Site
|
||||||
from ipam.tables import VLANTranslationRuleTable
|
from extras.ui.panels import CustomFieldsPanel, TagsPanel
|
||||||
from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport
|
from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport
|
||||||
|
from netbox.ui import actions, layout
|
||||||
|
from netbox.ui.panels import (
|
||||||
|
CommentsPanel,
|
||||||
|
ContextTablePanel,
|
||||||
|
ObjectsTablePanel,
|
||||||
|
RelatedObjectsPanel,
|
||||||
|
TemplatePanel,
|
||||||
|
)
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.query import count_related
|
from utilities.query import count_related
|
||||||
from utilities.tables import get_table_ordering
|
from utilities.tables import get_table_ordering
|
||||||
@@ -23,6 +31,7 @@ from . import filtersets, forms, tables
|
|||||||
from .choices import PrefixStatusChoices
|
from .choices import PrefixStatusChoices
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .models import *
|
from .models import *
|
||||||
|
from .ui import panels
|
||||||
from .utils import add_available_vlans, add_requested_prefixes, annotate_ip_space
|
from .utils import add_available_vlans, add_requested_prefixes, annotate_ip_space
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -41,6 +50,27 @@ class VRFListView(generic.ObjectListView):
|
|||||||
@register_model_view(VRF)
|
@register_model_view(VRF)
|
||||||
class VRFView(GetRelatedModelsMixin, generic.ObjectView):
|
class VRFView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = VRF.objects.all()
|
queryset = VRF.objects.all()
|
||||||
|
layout = layout.Layout(
|
||||||
|
layout.Row(
|
||||||
|
layout.Column(
|
||||||
|
panels.VRFPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
),
|
||||||
|
layout.Column(
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
layout.Row(
|
||||||
|
layout.Column(
|
||||||
|
ContextTablePanel('import_targets_table', title=_('Import route targets')),
|
||||||
|
),
|
||||||
|
layout.Column(
|
||||||
|
ContextTablePanel('export_targets_table', title=_('Export route targets')),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
import_targets_table = tables.RouteTargetTable(
|
import_targets_table = tables.RouteTargetTable(
|
||||||
@@ -134,6 +164,50 @@ class RouteTargetListView(generic.ObjectListView):
|
|||||||
@register_model_view(RouteTarget)
|
@register_model_view(RouteTarget)
|
||||||
class RouteTargetView(generic.ObjectView):
|
class RouteTargetView(generic.ObjectView):
|
||||||
queryset = RouteTarget.objects.all()
|
queryset = RouteTarget.objects.all()
|
||||||
|
layout = layout.Layout(
|
||||||
|
layout.Row(
|
||||||
|
layout.Column(
|
||||||
|
panels.RouteTargetPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
),
|
||||||
|
layout.Column(
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
layout.Row(
|
||||||
|
layout.Column(
|
||||||
|
ObjectsTablePanel(
|
||||||
|
'ipam.vrf',
|
||||||
|
filters={'import_target_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Importing VRFs'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
layout.Column(
|
||||||
|
ObjectsTablePanel(
|
||||||
|
'ipam.vrf',
|
||||||
|
filters={'export_target_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Exporting VRFs'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
layout.Row(
|
||||||
|
layout.Column(
|
||||||
|
ObjectsTablePanel(
|
||||||
|
'vpn.l2vpn',
|
||||||
|
filters={'import_target_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Importing L2VPNs'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
layout.Column(
|
||||||
|
ObjectsTablePanel(
|
||||||
|
'vpn.l2vpn',
|
||||||
|
filters={'export_target_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Exporting L2VPNs'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(RouteTarget, 'add', detail=False)
|
@register_model_view(RouteTarget, 'add', detail=False)
|
||||||
@@ -192,6 +266,17 @@ class RIRListView(generic.ObjectListView):
|
|||||||
@register_model_view(RIR)
|
@register_model_view(RIR)
|
||||||
class RIRView(GetRelatedModelsMixin, generic.ObjectView):
|
class RIRView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = RIR.objects.all()
|
queryset = RIR.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.RIRPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
return {
|
return {
|
||||||
@@ -257,6 +342,16 @@ class ASNRangeListView(generic.ObjectListView):
|
|||||||
@register_model_view(ASNRange)
|
@register_model_view(ASNRange)
|
||||||
class ASNRangeView(generic.ObjectView):
|
class ASNRangeView(generic.ObjectView):
|
||||||
queryset = ASNRange.objects.all()
|
queryset = ASNRange.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.ASNRangePanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
CommentsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(ASNRange, 'asns')
|
@register_model_view(ASNRange, 'asns')
|
||||||
@@ -337,6 +432,17 @@ class ASNListView(generic.ObjectListView):
|
|||||||
@register_model_view(ASN)
|
@register_model_view(ASN)
|
||||||
class ASNView(GetRelatedModelsMixin, generic.ObjectView):
|
class ASNView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = ASN.objects.all()
|
queryset = ASN.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.ASNPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
return {
|
return {
|
||||||
@@ -412,6 +518,16 @@ class AggregateListView(generic.ObjectListView):
|
|||||||
@register_model_view(Aggregate)
|
@register_model_view(Aggregate)
|
||||||
class AggregateView(generic.ObjectView):
|
class AggregateView(generic.ObjectView):
|
||||||
queryset = Aggregate.objects.all()
|
queryset = Aggregate.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.AggregatePanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Aggregate, 'prefixes')
|
@register_model_view(Aggregate, 'prefixes')
|
||||||
@@ -506,6 +622,17 @@ class RoleListView(generic.ObjectListView):
|
|||||||
@register_model_view(Role)
|
@register_model_view(Role)
|
||||||
class RoleView(GetRelatedModelsMixin, generic.ObjectView):
|
class RoleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Role.objects.all()
|
queryset = Role.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.RolePanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
return {
|
return {
|
||||||
@@ -569,15 +696,23 @@ class PrefixListView(generic.ObjectListView):
|
|||||||
@register_model_view(Prefix)
|
@register_model_view(Prefix)
|
||||||
class PrefixView(generic.ObjectView):
|
class PrefixView(generic.ObjectView):
|
||||||
queryset = Prefix.objects.all()
|
queryset = Prefix.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.PrefixPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
TemplatePanel('ipam/panels/prefix_addressing.html'),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ContextTablePanel('duplicate_prefix_table', title=_('Duplicate prefixes')),
|
||||||
|
ContextTablePanel('parent_prefix_table', title=_('Parent prefixes')),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
try:
|
|
||||||
aggregate = Aggregate.objects.restrict(request.user, 'view').get(
|
|
||||||
prefix__net_contains_or_equals=str(instance.prefix)
|
|
||||||
)
|
|
||||||
except Aggregate.DoesNotExist:
|
|
||||||
aggregate = None
|
|
||||||
|
|
||||||
# Parent prefixes table
|
# Parent prefixes table
|
||||||
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
|
parent_prefixes = Prefix.objects.restrict(request.user, 'view').filter(
|
||||||
Q(vrf=instance.vrf) | Q(vrf__isnull=True, status=PrefixStatusChoices.STATUS_CONTAINER)
|
Q(vrf=instance.vrf) | Q(vrf__isnull=True, status=PrefixStatusChoices.STATUS_CONTAINER)
|
||||||
@@ -608,11 +743,12 @@ class PrefixView(generic.ObjectView):
|
|||||||
)
|
)
|
||||||
duplicate_prefix_table.configure(request)
|
duplicate_prefix_table.configure(request)
|
||||||
|
|
||||||
return {
|
context = {
|
||||||
'aggregate': aggregate,
|
|
||||||
'parent_prefix_table': parent_prefix_table,
|
'parent_prefix_table': parent_prefix_table,
|
||||||
'duplicate_prefix_table': duplicate_prefix_table,
|
|
||||||
}
|
}
|
||||||
|
if duplicate_prefixes.exists():
|
||||||
|
context['duplicate_prefix_table'] = duplicate_prefix_table
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(Prefix, 'prefixes')
|
@register_model_view(Prefix, 'prefixes')
|
||||||
@@ -756,6 +892,19 @@ class IPRangeListView(generic.ObjectListView):
|
|||||||
@register_model_view(IPRange)
|
@register_model_view(IPRange)
|
||||||
class IPRangeView(generic.ObjectView):
|
class IPRangeView(generic.ObjectView):
|
||||||
queryset = IPRange.objects.all()
|
queryset = IPRange.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.IPRangePanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
TagsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ContextTablePanel('parent_prefixes_table', title=_('Parent prefixes')),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
|
|
||||||
@@ -853,6 +1002,23 @@ class IPAddressListView(generic.ObjectListView):
|
|||||||
@register_model_view(IPAddress)
|
@register_model_view(IPAddress)
|
||||||
class IPAddressView(generic.ObjectView):
|
class IPAddressView(generic.ObjectView):
|
||||||
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
|
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.IPAddressPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
ContextTablePanel('parent_prefixes_table', title=_('Parent prefixes')),
|
||||||
|
ContextTablePanel('duplicate_ips_table', title=_('Duplicate IPs')),
|
||||||
|
ObjectsTablePanel(
|
||||||
|
'ipam.service',
|
||||||
|
filters={'ip_address_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Application services'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
# Parent prefixes table
|
# Parent prefixes table
|
||||||
@@ -885,10 +1051,12 @@ class IPAddressView(generic.ObjectView):
|
|||||||
duplicate_ips_table = tables.IPAddressTable(duplicate_ips[:10], orderable=False)
|
duplicate_ips_table = tables.IPAddressTable(duplicate_ips[:10], orderable=False)
|
||||||
duplicate_ips_table.configure(request)
|
duplicate_ips_table.configure(request)
|
||||||
|
|
||||||
return {
|
context = {
|
||||||
'parent_prefixes_table': parent_prefixes_table,
|
'parent_prefixes_table': parent_prefixes_table,
|
||||||
'duplicate_ips_table': duplicate_ips_table,
|
|
||||||
}
|
}
|
||||||
|
if duplicate_ips.exists():
|
||||||
|
context['duplicate_ips_table'] = duplicate_ips_table
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(IPAddress, 'add', detail=False)
|
@register_model_view(IPAddress, 'add', detail=False)
|
||||||
@@ -1038,6 +1206,17 @@ class VLANGroupListView(generic.ObjectListView):
|
|||||||
@register_model_view(VLANGroup)
|
@register_model_view(VLANGroup)
|
||||||
class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
class VLANGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = VLANGroup.objects.annotate_utilization()
|
queryset = VLANGroup.objects.annotate_utilization()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.VLANGroupPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
return {
|
return {
|
||||||
@@ -1125,19 +1304,32 @@ class VLANTranslationPolicyListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(VLANTranslationPolicy)
|
@register_model_view(VLANTranslationPolicy)
|
||||||
class VLANTranslationPolicyView(GetRelatedModelsMixin, generic.ObjectView):
|
class VLANTranslationPolicyView(generic.ObjectView):
|
||||||
queryset = VLANTranslationPolicy.objects.all()
|
queryset = VLANTranslationPolicy.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
def get_extra_context(self, request, instance):
|
left_panels=[
|
||||||
vlan_translation_table = VLANTranslationRuleTable(
|
panels.VLANTranslationPolicyPanel(),
|
||||||
data=instance.rules.all(),
|
],
|
||||||
orderable=False
|
right_panels=[
|
||||||
)
|
TagsPanel(),
|
||||||
vlan_translation_table.configure(request)
|
CustomFieldsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
return {
|
],
|
||||||
'vlan_translation_table': vlan_translation_table,
|
bottom_panels=[
|
||||||
}
|
ObjectsTablePanel(
|
||||||
|
'ipam.vlantranslationrule',
|
||||||
|
filters={'policy_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('VLAN translation rules'),
|
||||||
|
actions=[
|
||||||
|
actions.AddObject(
|
||||||
|
'ipam.vlantranslationrule',
|
||||||
|
url_params={'policy': lambda ctx: ctx['object'].pk},
|
||||||
|
label=_('Add Rule'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(VLANTranslationPolicy, 'add', detail=False)
|
@register_model_view(VLANTranslationPolicy, 'add', detail=False)
|
||||||
@@ -1193,13 +1385,17 @@ class VLANTranslationRuleListView(generic.ObjectListView):
|
|||||||
|
|
||||||
|
|
||||||
@register_model_view(VLANTranslationRule)
|
@register_model_view(VLANTranslationRule)
|
||||||
class VLANTranslationRuleView(GetRelatedModelsMixin, generic.ObjectView):
|
class VLANTranslationRuleView(generic.ObjectView):
|
||||||
queryset = VLANTranslationRule.objects.all()
|
queryset = VLANTranslationRule.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
def get_extra_context(self, request, instance):
|
left_panels=[
|
||||||
return {
|
panels.VLANTranslationRulePanel(),
|
||||||
'related_models': self.get_related_models(request, instance),
|
],
|
||||||
}
|
right_panels=[
|
||||||
|
TagsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(VLANTranslationRule, 'add', detail=False)
|
@register_model_view(VLANTranslationRule, 'add', detail=False)
|
||||||
@@ -1251,7 +1447,36 @@ class FHRPGroupListView(generic.ObjectListView):
|
|||||||
|
|
||||||
@register_model_view(FHRPGroup)
|
@register_model_view(FHRPGroup)
|
||||||
class FHRPGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
class FHRPGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = FHRPGroup.objects.all()
|
queryset = FHRPGroup.objects.annotate(
|
||||||
|
member_count=count_related(FHRPGroupAssignment, 'group')
|
||||||
|
)
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.FHRPGroupPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
panels.FHRPGroupAuthPanel(),
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ObjectsTablePanel(
|
||||||
|
'ipam.ipaddress',
|
||||||
|
filters={'fhrpgroup_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Virtual IP addresses'),
|
||||||
|
actions=[
|
||||||
|
actions.AddObject(
|
||||||
|
'ipam.ipaddress',
|
||||||
|
url_params={'fhrpgroup': lambda ctx: ctx['object'].pk},
|
||||||
|
label=_('Add IP Address'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ContextTablePanel('members_table', title=_('Members')),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
# Get assigned interfaces
|
# Get assigned interfaces
|
||||||
@@ -1276,7 +1501,6 @@ class FHRPGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
'members_table': members_table,
|
'members_table': members_table,
|
||||||
'member_count': FHRPGroupAssignment.objects.filter(group=instance).count(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1379,17 +1603,35 @@ class VLANListView(generic.ObjectListView):
|
|||||||
@register_model_view(VLAN)
|
@register_model_view(VLAN)
|
||||||
class VLANView(generic.ObjectView):
|
class VLANView(generic.ObjectView):
|
||||||
queryset = VLAN.objects.all()
|
queryset = VLAN.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
def get_extra_context(self, request, instance):
|
left_panels=[
|
||||||
prefixes = Prefix.objects.restrict(request.user, 'view').filter(vlan=instance).prefetch_related(
|
panels.VLANPanel(),
|
||||||
'vrf', 'scope', 'role', 'tenant'
|
],
|
||||||
)
|
right_panels=[
|
||||||
prefix_table = tables.PrefixTable(list(prefixes), exclude=('vlan', 'utilization'), orderable=False)
|
CustomFieldsPanel(),
|
||||||
prefix_table.configure(request)
|
TagsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
return {
|
],
|
||||||
'prefix_table': prefix_table,
|
bottom_panels=[
|
||||||
}
|
ObjectsTablePanel(
|
||||||
|
'ipam.prefix',
|
||||||
|
filters={'vlan_id': lambda ctx: ctx['object'].pk},
|
||||||
|
title=_('Prefixes'),
|
||||||
|
actions=[
|
||||||
|
actions.AddObject(
|
||||||
|
'ipam.prefix',
|
||||||
|
url_params={
|
||||||
|
'tenant': lambda ctx: ctx['object'].tenant.pk if ctx['object'].tenant else None,
|
||||||
|
'site': lambda ctx: ctx['object'].site.pk if ctx['object'].site else None,
|
||||||
|
'vlan': lambda ctx: ctx['object'].pk,
|
||||||
|
},
|
||||||
|
label=_('Add a Prefix'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
panels.VLANCustomerVLANsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(VLAN, 'interfaces')
|
@register_model_view(VLAN, 'interfaces')
|
||||||
@@ -1483,6 +1725,16 @@ class ServiceTemplateListView(generic.ObjectListView):
|
|||||||
@register_model_view(ServiceTemplate)
|
@register_model_view(ServiceTemplate)
|
||||||
class ServiceTemplateView(generic.ObjectView):
|
class ServiceTemplateView(generic.ObjectView):
|
||||||
queryset = ServiceTemplate.objects.all()
|
queryset = ServiceTemplate.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.ServiceTemplatePanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(ServiceTemplate, 'add', detail=False)
|
@register_model_view(ServiceTemplate, 'add', detail=False)
|
||||||
@@ -1539,6 +1791,16 @@ class ServiceListView(generic.ObjectListView):
|
|||||||
@register_model_view(Service)
|
@register_model_view(Service)
|
||||||
class ServiceView(generic.ObjectView):
|
class ServiceView(generic.ObjectView):
|
||||||
queryset = Service.objects.all()
|
queryset = Service.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[
|
||||||
|
panels.ServicePanel(),
|
||||||
|
],
|
||||||
|
right_panels=[
|
||||||
|
CustomFieldsPanel(),
|
||||||
|
TagsPanel(),
|
||||||
|
CommentsPanel(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
context = {}
|
context = {}
|
||||||
|
|||||||
@@ -1,62 +1 @@
|
|||||||
{% extends 'ipam/aggregate/base.html' %}
|
{% extends 'ipam/aggregate/base.html' %}
|
||||||
{% load buttons %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Aggregate" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Family" %}</th>
|
|
||||||
<td>IPv{{ object.family }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "RIR" %}</th>
|
|
||||||
<td>
|
|
||||||
<a href="{% url 'ipam:aggregate_list' %}?rir={{ object.rir.slug }}">{{ object.rir }}</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Utilization" %}</th>
|
|
||||||
<td>
|
|
||||||
{% utilization_graph object.get_utilization %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Date Added" %}</th>
|
|
||||||
<td>{{ object.date_added|isodate|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
2
netbox/templates/ipam/aggregate/attrs/utilization.html
Normal file
2
netbox/templates/ipam/aggregate/attrs/utilization.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
{% utilization_graph object.get_utilization %}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load buttons %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
@@ -12,51 +8,3 @@
|
|||||||
<li class="breadcrumb-item"><a href="{% url 'ipam:asn_list' %}?range_id={{ object.range.pk }}">{{ object.range }}</a></li>
|
<li class="breadcrumb-item"><a href="{% url 'ipam:asn_list' %}?range_id={{ object.range.pk }}">{{ object.range }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock breadcrumbs %}
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "ASN" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "AS Number" %}</th>
|
|
||||||
<td>{{ object.asn_with_asdot }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "RIR" %}</th>
|
|
||||||
<td>
|
|
||||||
<a href="{% url 'ipam:asn_list' %}?rir={{ object.rir.slug }}">{{ object.rir }}</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/related_objects.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
|
||||||
|
|||||||
@@ -1,57 +1 @@
|
|||||||
{% extends 'ipam/asnrange/base.html' %}
|
{% extends 'ipam/asnrange/base.html' %}
|
||||||
{% load buttons %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "ASN Range" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "RIR" %}</th>
|
|
||||||
<td>
|
|
||||||
<a href="{% url 'ipam:asnrange_list' %}?rir={{ object.rir.slug }}">{{ object.rir }}</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Range" %}</th>
|
|
||||||
<td>{{ object.range_as_string_with_asdot }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock content %}
|
|
||||||
|
|||||||
2
netbox/templates/ipam/attrs/vrf.html
Normal file
2
netbox/templates/ipam/attrs/vrf.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers i18n %}
|
||||||
|
{% if value %}{{ value|linkify }}{% if show_rd %} ({{ value.rd }}){% endif %}{% else %}<span>{% trans "Global" %}</span>{% endif %}
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{# Omit assigned IP addresses from object representation #}
|
{# Omit assigned IP addresses from object representation #}
|
||||||
@@ -11,75 +8,3 @@
|
|||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<li class="breadcrumb-item"><a href="{% url 'ipam:fhrpgroup_list' %}?protocol={{ object.protocol }}">{{ object.get_protocol_display }}</a></li>
|
<li class="breadcrumb-item"><a href="{% url 'ipam:fhrpgroup_list' %}?protocol={{ object.protocol }}">{{ object.get_protocol_display }}</a></li>
|
||||||
{% endblock breadcrumbs %}
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "FHRP Group" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Protocol" %}</th>
|
|
||||||
<td>{{ object.get_protocol_display }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Group ID" %}</th>
|
|
||||||
<td>{{ object.group_id }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Members" %}</th>
|
|
||||||
<td>{{ member_count }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Authentication" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Authentication Type" %}</th>
|
|
||||||
<td>{{ object.get_auth_type_display|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Authentication Key" %}</th>
|
|
||||||
<td>{{ object.auth_key|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/related_objects.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">
|
|
||||||
{% trans "Virtual IP Addresses" %}
|
|
||||||
{% if perms.ipam.add_ipaddress %}
|
|
||||||
<div class="card-actions">
|
|
||||||
<a href="{% url 'ipam:ipaddress_add' %}?fhrpgroup={{ object.pk }}&return_url={{ object.get_absolute_url }}" class="btn btn-ghost-primary btn-sm">
|
|
||||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add IP Address" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
{% htmx_table 'ipam:ipaddress_list' fhrpgroup_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panel_table.html' with table=members_table heading='Members' %}
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,129 +1 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'ipam/ipaddress/base.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-4">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "IP Address" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Family" %}</th>
|
|
||||||
<td>IPv{{ object.family }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "VRF" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.vrf %}
|
|
||||||
<a href="{% url 'ipam:vrf' pk=object.vrf.pk %}">{{ object.vrf }}</a>
|
|
||||||
{% else %}
|
|
||||||
<span>{% trans "Global" %}</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Status" %}</th>
|
|
||||||
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Role" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.role %}
|
|
||||||
<a href="{% url 'ipam:ipaddress_list' %}?role={{ object.role }}">{{ object.get_role_display }}</a>
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "DNS Name" %}</th>
|
|
||||||
<td>{{ object.dns_name|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Assignment" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.assigned_object %}
|
|
||||||
{% if object.assigned_object.parent_object %}
|
|
||||||
{{ object.assigned_object.parent_object|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.assigned_object|linkify }}
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "NAT (inside)" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.nat_inside %}
|
|
||||||
{{ object.nat_inside|linkify }}
|
|
||||||
{% if object.nat_inside.assigned_object %}
|
|
||||||
({{ object.nat_inside.assigned_object.parent_object|linkify }})
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "NAT (outside)" %}</th>
|
|
||||||
<td>
|
|
||||||
{% for ip in object.nat_outside.all %}
|
|
||||||
{{ ip|linkify }}
|
|
||||||
{% if ip.assigned_object %}
|
|
||||||
({{ ip.assigned_object.parent_object|linkify }})
|
|
||||||
{% endif %}<br/>
|
|
||||||
{% empty %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Primary IP</th>
|
|
||||||
<td>{% checkmark object.is_primary_ip %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">OOB IP</th>
|
|
||||||
<td>{% checkmark object.is_oob_ip %}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-md-8">
|
|
||||||
{% include 'inc/panel_table.html' with table=parent_prefixes_table heading='Parent Prefixes' %}
|
|
||||||
{% if duplicate_ips_table.rows %}
|
|
||||||
{% include 'inc/panel_table.html' with table=duplicate_ips_table heading='Duplicate IPs' panel_class='danger' %}
|
|
||||||
{% endif %}
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Application Services" %}</h2>
|
|
||||||
{% htmx_table 'ipam:service_list' ip_address_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
{% if value.parent_object %}{{ value.parent_object|linkify }} / {% endif %}{{ value|linkify }}
|
||||||
2
netbox/templates/ipam/ipaddress/attrs/nat_inside.html
Normal file
2
netbox/templates/ipam/ipaddress/attrs/nat_inside.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
{{ value|linkify }}{% if value.assigned_object %} ({{ value.assigned_object.parent_object|linkify }}){% endif %}
|
||||||
2
netbox/templates/ipam/ipaddress/attrs/nat_outside.html
Normal file
2
netbox/templates/ipam/ipaddress/attrs/nat_outside.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
{% for ip in value.all %}{{ ip|linkify }}{% if ip.assigned_object %} ({{ ip.assigned_object.parent_object|linkify }}){% endif %}<br/>{% empty %}<span class="text-muted">—</span>{% endfor %}
|
||||||
@@ -1,98 +1 @@
|
|||||||
{% extends 'ipam/iprange/base.html' %}
|
{% extends 'ipam/iprange/base.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "IP Range" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Family" %}</th>
|
|
||||||
<td>IPv{{ object.family }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Starting Address" %}</th>
|
|
||||||
<td>{{ object.start_address }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Ending Address" %}</th>
|
|
||||||
<td>{{ object.end_address }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Size" %}</th>
|
|
||||||
<td>{{ object.size }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Marked Populated" %}</th>
|
|
||||||
<td>{% checkmark object.mark_populated %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Marked Utilized" %}</th>
|
|
||||||
<td>{% checkmark object.mark_utilized %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Utilization" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.mark_utilized %}
|
|
||||||
{% utilization_graph 100 warning_threshold=0 danger_threshold=0 %}
|
|
||||||
{% else %}
|
|
||||||
{% utilization_graph object.utilization %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "VRF" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.vrf %}
|
|
||||||
{{ object.vrf|linkify }} ({{ object.vrf.rd }})
|
|
||||||
{% else %}
|
|
||||||
<span>{% trans "Global" %}</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Role" %}</th>
|
|
||||||
<td>{{ object.role|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Status" %}</th>
|
|
||||||
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% include 'inc/panel_table.html' with table=parent_prefixes_table heading='Parent Prefixes' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
6
netbox/templates/ipam/iprange/attrs/utilization.html
Normal file
6
netbox/templates/ipam/iprange/attrs/utilization.html
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
{% if object.mark_utilized %}
|
||||||
|
{% utilization_graph 100 warning_threshold=0 danger_threshold=0 %}
|
||||||
|
{% else %}
|
||||||
|
{% utilization_graph value %}
|
||||||
|
{% endif %}
|
||||||
62
netbox/templates/ipam/panels/prefix_addressing.html
Normal file
62
netbox/templates/ipam/panels/prefix_addressing.html
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{% load humanize helpers i18n %}
|
||||||
|
<div class="card">
|
||||||
|
<h2 class="card-header">
|
||||||
|
{% trans "Addressing" %}
|
||||||
|
{% if object.prefix.version == 4 %}
|
||||||
|
<div class="card-actions">
|
||||||
|
<a class="btn btn-ghost-primary btn-sm" data-bs-toggle="modal" data-bs-target="#prefix-modal">
|
||||||
|
<i class="mdi mdi-information-outline" aria-hidden="true"></i> {% trans "Addressing Details" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</h2>
|
||||||
|
<table class="table table-hover attr-table">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Utilization" %}</th>
|
||||||
|
<td>
|
||||||
|
{% if object.mark_utilized %}
|
||||||
|
{% utilization_graph 100 warning_threshold=0 danger_threshold=0 %}
|
||||||
|
<small>({% trans "Marked fully utilized" %})</small>
|
||||||
|
{% else %}
|
||||||
|
{% utilization_graph object.get_utilization %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% with child_ip_count=object.get_child_ips.count %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Child IPs" %}</th>
|
||||||
|
<td>
|
||||||
|
<a href="{% url 'ipam:prefix_ipaddresses' pk=object.pk %}">{{ child_ip_count }}</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endwith %}
|
||||||
|
{% with available_count=object.get_available_ips.size %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Available IPs" %}</th>
|
||||||
|
<td>
|
||||||
|
{% if available_count > 1000000 %}
|
||||||
|
{{ available_count|intword }}
|
||||||
|
{% else %}
|
||||||
|
{{ available_count|intcomma }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endwith %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "First available IP" %}</th>
|
||||||
|
<td>
|
||||||
|
{% with first_available_ip=object.get_first_available_ip %}
|
||||||
|
{% if first_available_ip %}
|
||||||
|
{% if perms.ipam.add_ipaddress %}
|
||||||
|
<a href="{% url 'ipam:ipaddress_add' %}?address={{ first_available_ip }}{% if object.vrf %}&vrf={{ object.vrf_id }}{% endif %}{% if object.tenant %}&tenant={{ object.tenant.pk }}{% endif %}">{{ first_available_ip }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ first_available_ip }}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{{ ''|placeholder }}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -1,202 +1 @@
|
|||||||
{% extends 'ipam/prefix/base.html' %}
|
{% extends 'ipam/prefix/base.html' %}
|
||||||
{% load humanize %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load mptt %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Prefix" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Family" %}</th>
|
|
||||||
<td>IPv{{ object.family }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "VRF" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.vrf %}
|
|
||||||
<a href="{% url 'ipam:vrf' pk=object.vrf.pk %}">{{ object.vrf }}</a>
|
|
||||||
{% else %}
|
|
||||||
<span>{% trans "Global" %}</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Aggregate" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if aggregate %}
|
|
||||||
<a href="{% url 'ipam:aggregate' pk=aggregate.pk %}">{{ aggregate.prefix }}</a> ({{ aggregate.rir }})
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Scope" %}</th>
|
|
||||||
{% if object.scope %}
|
|
||||||
<td>{{ object.scope|linkify }} ({% trans object.scope_type.name %})</td>
|
|
||||||
{% else %}
|
|
||||||
<td>{{ ''|placeholder }}</td>
|
|
||||||
{% endif %}
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "VLAN" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.vlan %}
|
|
||||||
{% if object.vlan.group %}
|
|
||||||
{{ object.vlan.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.vlan|linkify }}
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Status" %}</th>
|
|
||||||
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Role" %}</th>
|
|
||||||
<td>{{ object.role|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Is a pool" %}</th>
|
|
||||||
<td>{% checkmark object.is_pool %}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">
|
|
||||||
{% trans "Addressing" %}
|
|
||||||
{% if object.prefix.version == 4 %}
|
|
||||||
<div class="card-actions">
|
|
||||||
<a class="btn btn-ghost-primary btn-sm" data-bs-toggle="modal" data-bs-target="#prefix-modal">
|
|
||||||
<i class="mdi mdi-information-outline" aria-hidden="true"></i> {% trans "Addressing Details" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Utilization" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.mark_utilized %}
|
|
||||||
{% utilization_graph 100 warning_threshold=0 danger_threshold=0 %}
|
|
||||||
<small>({% trans "Marked fully utilized" %})</small>
|
|
||||||
{% else %}
|
|
||||||
{% utilization_graph object.get_utilization %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% with child_ip_count=object.get_child_ips.count %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Child IPs" %}</th>
|
|
||||||
<td>
|
|
||||||
<a href="{% url 'ipam:prefix_ipaddresses' pk=object.pk %}">{{ child_ip_count }}</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endwith %}
|
|
||||||
{% with available_count=object.get_available_ips.size %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Available IPs" %}</th>
|
|
||||||
<td>
|
|
||||||
{# Use human-friendly words for counts greater than one million #}
|
|
||||||
{% if available_count > 1000000 %}
|
|
||||||
{{ available_count|intword }}
|
|
||||||
{% else %}
|
|
||||||
{{ available_count|intcomma }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endwith %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "First available IP" %}</th>
|
|
||||||
<td>
|
|
||||||
{% with first_available_ip=object.get_first_available_ip %}
|
|
||||||
{% if first_available_ip %}
|
|
||||||
{% if perms.ipam.add_ipaddress %}
|
|
||||||
<a href="{% url 'ipam:ipaddress_add' %}?address={{ first_available_ip }}{% if object.vrf %}&vrf={{ object.vrf_id }}{% endif %}{% if object.tenant %}&tenant={{ object.tenant.pk }}{% endif %}">{{ first_available_ip }}</a>
|
|
||||||
{% else %}
|
|
||||||
{{ first_available_ip }}
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% if duplicate_prefix_table.rows %}
|
|
||||||
{% include 'inc/panel_table.html' with table=duplicate_prefix_table heading='Duplicate Prefixes' %}
|
|
||||||
{% endif %}
|
|
||||||
{% include 'inc/panel_table.html' with table=parent_prefix_table heading='Parent Prefixes' %}
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block modals %}
|
|
||||||
{{ block.super }}
|
|
||||||
{% if object.prefix.version == 4 %}
|
|
||||||
<div class="modal fade" id="prefix-modal" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{% trans "Prefix Details" %}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body p-0">
|
|
||||||
<table class="table table-hover attr-table m-0">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Network Address" %}</th>
|
|
||||||
<td>{{ object.prefix.network }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Network Mask" %}</th>
|
|
||||||
<td>{{ object.prefix.netmask }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Wildcard Mask" %}</th>
|
|
||||||
<td>{{ object.prefix.hostmask }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Broadcast Address" %}</th>
|
|
||||||
<td>{{ object.prefix.broadcast }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
2
netbox/templates/ipam/prefix/attrs/aggregate.html
Normal file
2
netbox/templates/ipam/prefix/attrs/aggregate.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
<span>{{ value|linkify }} ({{ value.rir }})</span>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load buttons %}
|
{% load buttons %}
|
||||||
{% load helpers %}
|
{% load helpers %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
@@ -8,3 +9,39 @@
|
|||||||
<li class="breadcrumb-item"><a href="{% url 'ipam:prefix_list' %}?vrf_id={{ object.vrf.pk }}">{{ object.vrf }}</a></li>
|
<li class="breadcrumb-item"><a href="{% url 'ipam:prefix_list' %}?vrf_id={{ object.vrf.pk }}">{{ object.vrf }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modals %}
|
||||||
|
{{ block.super }}
|
||||||
|
{% if object.prefix.version == 4 %}
|
||||||
|
<div class="modal fade" id="prefix-modal" tabindex="-1" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{% trans "Prefix Details" %}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body p-0">
|
||||||
|
<table class="table table-hover attr-table m-0">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Network Address" %}</th>
|
||||||
|
<td>{{ object.prefix.network }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Network Mask" %}</th>
|
||||||
|
<td>{{ object.prefix.netmask }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Wildcard Mask" %}</th>
|
||||||
|
<td>{{ object.prefix.hostmask }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{% trans "Broadcast Address" %}</th>
|
||||||
|
<td>{{ object.prefix.broadcast }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock modals %}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block extra_controls %}
|
{% block extra_controls %}
|
||||||
@@ -11,40 +8,3 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock extra_controls %}
|
{% endblock extra_controls %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "RIR" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Private" %}</th>
|
|
||||||
<td>{% checkmark object.is_private %}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/related_objects.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block extra_controls %}
|
{% block extra_controls %}
|
||||||
@@ -11,40 +8,3 @@
|
|||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock extra_controls %}
|
{% endblock extra_controls %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Role" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Weight" %}</th>
|
|
||||||
<td>{{ object.weight }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/related_objects.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,68 +1 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Route Target" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td class="font-monospace">{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>{{ object.tenant|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Importing VRFs" %}</h2>
|
|
||||||
{% htmx_table 'ipam:vrf_list' import_target_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Exporting VRFs" %}</h2>
|
|
||||||
{% htmx_table 'ipam:vrf_list' export_target_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Importing L2VPNs" %}</h2>
|
|
||||||
{% htmx_table 'vpn:l2vpn_list' import_target_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Exporting L2VPNs" %}</h2>
|
|
||||||
{% htmx_table 'vpn:l2vpn_list' export_target_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load buttons %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load perms %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
@@ -14,58 +10,4 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Service" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Parent" %}</th>
|
|
||||||
<td>{{ object.parent|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Protocol" %}</th>
|
|
||||||
<td>{{ object.get_protocol_display }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Ports" %}</th>
|
|
||||||
<td>{{ object.port_list }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "IP Addresses" %}</th>
|
|
||||||
<td>
|
|
||||||
{% for ipaddress in object.ipaddresses.all %}
|
|
||||||
{{ ipaddress|linkify }}<br />
|
|
||||||
{% empty %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
2
netbox/templates/ipam/service/attrs/ip_addresses.html
Normal file
2
netbox/templates/ipam/service/attrs/ip_addresses.html
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
{% load helpers %}
|
||||||
|
{% for ipaddress in value.all %}{{ ipaddress|linkify }}<br />{% empty %}<span class="text-muted">—</span>{% endfor %}
|
||||||
@@ -1,46 +1 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load buttons %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load perms %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "Application Service Template" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Protocol" %}</th>
|
|
||||||
<td>{{ object.get_protocol_display }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Ports" %}</th>
|
|
||||||
<td>{{ object.port_list }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,129 +1 @@
|
|||||||
{% extends 'ipam/vlan/base.html' %}
|
{% extends 'ipam/vlan/base.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load mptt %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "VLAN" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
{% if object.site.region %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Region" %}</th>
|
|
||||||
<td>
|
|
||||||
{% nested_tree object.site.region %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Site" %}</th>
|
|
||||||
<td>{{ object.site|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Group" %}</th>
|
|
||||||
<td>{{ object.group|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "VLAN ID" %}</th>
|
|
||||||
<td>{{ object.vid }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Status" %}</th>
|
|
||||||
<td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Role" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.role %}
|
|
||||||
<a href="{% url 'ipam:vlan_list' %}?role={{ object.role.slug }}">{{ object.role }}</a>
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Q-in-Q Role" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.qinq_role %}
|
|
||||||
{% badge object.get_qinq_role_display bg_color=object.get_qinq_role_color %}
|
|
||||||
{% else %}
|
|
||||||
{{ ''|placeholder }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% if object.qinq_role == 'cvlan' %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Q-in-Q SVLAN" %}</th>
|
|
||||||
<td>{{ object.qinq_svlan|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "L2VPN" %}</th>
|
|
||||||
<td>{{ object.l2vpn_termination.l2vpn|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">
|
|
||||||
{% trans "Prefixes" %}
|
|
||||||
{% if perms.ipam.add_prefix %}
|
|
||||||
<div class="card-actions">
|
|
||||||
<a href="{% url 'ipam:prefix_add' %}?{% if object.tenant %}tenant={{ object.tenant.pk }}&{% endif %}site={{ object.site.pk }}&vlan={{ object.pk }}" class="btn btn-ghost-primary btn-sm">
|
|
||||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add a Prefix" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
{% htmx_table 'ipam:prefix_list' vlan_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
{% if object.qinq_role == 'svlan' %}
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">
|
|
||||||
{% trans "Customer VLANs" %}
|
|
||||||
{% if perms.ipam.add_vlan %}
|
|
||||||
<div class="card-actions">
|
|
||||||
<a href="{% url 'ipam:vlan_add' %}?qinq_role=cvlan&qinq_svlan={{ object.pk }}" class="btn btn-ghost-primary btn-sm">
|
|
||||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add a VLAN" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
{% htmx_table 'ipam:vlan_list' qinq_svlan_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
{% load helpers %}
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
@@ -18,53 +16,4 @@
|
|||||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add VLAN" %}
|
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add VLAN" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock extra_controls %}
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "VLAN Group" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Scope" %}</th>
|
|
||||||
<td>{{ object.scope|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "VLAN IDs" %}</th>
|
|
||||||
<td>{{ object.vid_ranges_items|join:", " }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Utilization</th>
|
|
||||||
<td>{% utilization_graph object.utilization %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/related_objects.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
1
netbox/templates/ipam/vlangroup/attrs/vid_ranges.html
Normal file
1
netbox/templates/ipam/vlangroup/attrs/vid_ranges.html
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{{ value|join:", " }}
|
||||||
@@ -1,65 +1 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-4">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "VLAN Translation Policy" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Name" %}</th>
|
|
||||||
<td>{{ object.name|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Rules" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.rules.count %}
|
|
||||||
<a href="{% url 'ipam:vlantranslationrule_list' %}?policy_id={{ object.pk }}">{{ object.rules.count }}</a>
|
|
||||||
{% else %}
|
|
||||||
0
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-md-8">
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">
|
|
||||||
{% trans "VLAN Translation Rules" %}
|
|
||||||
{% if perms.ipam.add_vlantranslationrule %}
|
|
||||||
<div class="card-actions">
|
|
||||||
<a href="{% url 'ipam:vlantranslationrule_add' %}?device={{ object.device.pk }}&policy={{ object.pk }}&return_url={{ object.get_absolute_url }}"
|
|
||||||
class="btn btn-ghost-primary btn-sm">
|
|
||||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add Rule" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</h2>
|
|
||||||
{% htmx_table 'ipam:vlantranslationrule_list' policy_id=object.pk %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,45 +1 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load render_table from django_tables2 %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-4">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "VLAN Translation Rule" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Policy" %}</th>
|
|
||||||
<td>{{ object.policy|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Local VID" %}</th>
|
|
||||||
<td>{{ object.local_vid }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Remote VID" %}</th>
|
|
||||||
<td>{{ object.remote_vid }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-8">
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
@@ -1,61 +1 @@
|
|||||||
{% extends 'generic/object.html' %}
|
{% extends 'generic/object.html' %}
|
||||||
{% load buttons %}
|
|
||||||
{% load helpers %}
|
|
||||||
{% load plugins %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block title %}{% trans "VRF" %} {{ object }}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
<div class="card">
|
|
||||||
<h2 class="card-header">{% trans "VRF" %}</h2>
|
|
||||||
<table class="table table-hover attr-table">
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Route Distinguisher" %}</th>
|
|
||||||
<td>{{ object.rd|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Tenant" %}</th>
|
|
||||||
<td>
|
|
||||||
{% if object.tenant.group %}
|
|
||||||
{{ object.tenant.group|linkify }} /
|
|
||||||
{% endif %}
|
|
||||||
{{ object.tenant|linkify|placeholder }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Unique IP Space" %}</th>
|
|
||||||
<td>{% checkmark object.enforce_unique %}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans "Description" %}</th>
|
|
||||||
<td>{{ object.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% include 'inc/panels/tags.html' %}
|
|
||||||
{% plugin_left_page object %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panels/related_objects.html' %}
|
|
||||||
{% include 'inc/panels/custom_fields.html' %}
|
|
||||||
{% include 'inc/panels/comments.html' %}
|
|
||||||
{% plugin_right_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panel_table.html' with table=import_targets_table heading="Import Route Targets" %}
|
|
||||||
</div>
|
|
||||||
<div class="col col-12 col-md-6">
|
|
||||||
{% include 'inc/panel_table.html' with table=export_targets_table heading="Export Route Targets" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col col-md-12">
|
|
||||||
{% plugin_full_width_page object %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user