diff --git a/netbox/templates/vpn/attrs/preshared_key.html b/netbox/templates/vpn/attrs/preshared_key.html
new file mode 100644
index 000000000..3401a3eb4
--- /dev/null
+++ b/netbox/templates/vpn/attrs/preshared_key.html
@@ -0,0 +1,3 @@
+{% load i18n %}
+{{ value }}
+
diff --git a/netbox/templates/vpn/ikepolicy.html b/netbox/templates/vpn/ikepolicy.html
index a098fb91b..f15e1d050 100644
--- a/netbox/templates/vpn/ikepolicy.html
+++ b/netbox/templates/vpn/ikepolicy.html
@@ -1,63 +1 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load i18n %}
-
-{% block content %}
-
-
-
-
-
- {% htmx_table 'vpn:ipsecproposal_list' ipsec_policy_id=object.pk %}
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/ipsecprofile.html b/netbox/templates/vpn/ipsecprofile.html
index d7d5a1e5b..f15e1d050 100644
--- a/netbox/templates/vpn/ipsecprofile.html
+++ b/netbox/templates/vpn/ipsecprofile.html
@@ -1,102 +1 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load i18n %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Mode" %} |
- {{ object.get_mode_display }} |
-
-
-
- {% include 'inc/panels/tags.html' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_left_page object %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.ike_policy|linkify }} |
-
-
- | {% trans "Description" %} |
- {{ object.ike_policy.description|placeholder }} |
-
-
- | {% trans "Version" %} |
- {{ object.ike_policy.get_version_display }} |
-
-
- | {% trans "Mode" %} |
- {{ object.ike_policy.get_mode_display }} |
-
-
- | {% trans "Proposals" %} |
-
-
- {% for proposal in object.ike_policy.proposals.all %}
- -
- {{ proposal }}
-
- {% endfor %}
-
- |
-
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.ipsec_policy|linkify }} |
-
-
- | {% trans "Description" %} |
- {{ object.ipsec_policy.description|placeholder }} |
-
-
- | {% trans "Proposals" %} |
-
-
- {% for proposal in object.ipsec_policy.proposals.all %}
- -
- {{ proposal }}
-
- {% endfor %}
-
- |
-
-
- | {% trans "PFS Group" %} |
- {{ object.ipsec_policy.get_pfs_group_display }} |
-
-
-
- {% plugin_right_page object %}
-
-
-
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/ipsecproposal.html b/netbox/templates/vpn/ipsecproposal.html
index 5b199905e..f15e1d050 100644
--- a/netbox/templates/vpn/ipsecproposal.html
+++ b/netbox/templates/vpn/ipsecproposal.html
@@ -1,58 +1 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load i18n %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Encryption algorithm" %} |
- {{ object.get_encryption_algorithm_display }} |
-
-
- | {% trans "Authentication algorithm" %} |
- {{ object.get_authentication_algorithm_display }} |
-
-
- | {% trans "SA lifetime (seconds)" %} |
- {{ object.sa_lifetime_seconds|placeholder }} |
-
-
- | {% trans "SA lifetime (KB)" %} |
- {{ object.sa_lifetime_data|placeholder }} |
-
-
- | {% trans "IPSec Policies" %} |
-
- {{ object.ipsec_policies.count }}
- |
-
-
-
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/comments.html' %}
- {% include 'inc/panels/tags.html' %}
- {% plugin_right_page object %}
-
-
-
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/l2vpn.html b/netbox/templates/vpn/l2vpn.html
index 593123849..f15e1d050 100644
--- a/netbox/templates/vpn/l2vpn.html
+++ b/netbox/templates/vpn/l2vpn.html
@@ -1,78 +1 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load render_table from django_tables2 %}
-{% load i18n %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name|placeholder }} |
-
-
- | {% trans "Identifier" %} |
- {{ object.identifier|placeholder }} |
-
-
- | {% trans "Type" %} |
- {{ object.get_type_display }} |
-
-
- | {% trans "Status" %} |
- {% badge object.get_status_display bg_color=object.get_status_color %} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Tenant" %} |
- {{ object.tenant|linkify|placeholder }} |
-
-
-
- {% include 'inc/panels/tags.html' with tags=object.tags.all url='vpn:l2vpn_list' %}
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_right_page object %}
-
-
-
-
- {% include 'inc/panel_table.html' with table=import_targets_table heading="Import Route Targets" %}
-
-
- {% include 'inc/panel_table.html' with table=export_targets_table heading="Export Route Targets" %}
-
-
-
-
-
-
- {% htmx_table 'vpn:l2vpntermination_list' l2vpn_id=object.pk %}
-
-
-
-
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/l2vpntermination.html b/netbox/templates/vpn/l2vpntermination.html
index 8b6b31aa7..f15e1d050 100644
--- a/netbox/templates/vpn/l2vpntermination.html
+++ b/netbox/templates/vpn/l2vpntermination.html
@@ -1,28 +1 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load i18n %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "L2VPN" %} |
- {{ object.l2vpn|linkify }} |
-
-
- | {% trans "Assigned Object" %} |
- {{ object.assigned_object|linkify }} |
-
-
-
-
-
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/tags.html' with tags=object.tags.all url='vpn:l2vpntermination_list' %}
-
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/panels/ipsecprofile_ike_policy.html b/netbox/templates/vpn/panels/ipsecprofile_ike_policy.html
new file mode 100644
index 000000000..8b3065cfd
--- /dev/null
+++ b/netbox/templates/vpn/panels/ipsecprofile_ike_policy.html
@@ -0,0 +1,34 @@
+{% load helpers %}
+{% load i18n %}
+
+
+
+
+
+ | {% trans "Name" %} |
+ {{ object.ike_policy|linkify }} |
+
+
+ | {% trans "Description" %} |
+ {{ object.ike_policy.description|placeholder }} |
+
+
+ | {% trans "Version" %} |
+ {{ object.ike_policy.get_version_display }} |
+
+
+ | {% trans "Mode" %} |
+ {{ object.ike_policy.get_mode_display }} |
+
+
+ | {% trans "Proposals" %} |
+
+
+ {% for proposal in object.ike_policy.proposals.all %}
+ - {{ proposal }}
+ {% endfor %}
+
+ |
+
+
+
diff --git a/netbox/templates/vpn/panels/ipsecprofile_ipsec_policy.html b/netbox/templates/vpn/panels/ipsecprofile_ipsec_policy.html
new file mode 100644
index 000000000..cb28c1620
--- /dev/null
+++ b/netbox/templates/vpn/panels/ipsecprofile_ipsec_policy.html
@@ -0,0 +1,30 @@
+{% load helpers %}
+{% load i18n %}
+
+
+
+
+
+ | {% trans "Name" %} |
+ {{ object.ipsec_policy|linkify }} |
+
+
+ | {% trans "Description" %} |
+ {{ object.ipsec_policy.description|placeholder }} |
+
+
+ | {% trans "Proposals" %} |
+
+
+ {% for proposal in object.ipsec_policy.proposals.all %}
+ - {{ proposal }}
+ {% endfor %}
+
+ |
+
+
+ | {% trans "PFS Group" %} |
+ {{ object.ipsec_policy.get_pfs_group_display }} |
+
+
+
diff --git a/netbox/templates/vpn/tunnel.html b/netbox/templates/vpn/tunnel.html
index 4e4b5f56e..671f7447d 100644
--- a/netbox/templates/vpn/tunnel.html
+++ b/netbox/templates/vpn/tunnel.html
@@ -1,6 +1,4 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
{% load i18n %}
{% block extra_controls %}
@@ -10,77 +8,3 @@
{% endif %}
{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Status" %} |
- {% badge object.get_status_display bg_color=object.get_status_color %} |
-
-
- | {% trans "Group" %} |
- {{ object.group|linkify|placeholder }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
- | {% trans "Encapsulation" %} |
- {{ object.get_encapsulation_display }} |
-
-
- | {% trans "IPSec profile" %} |
- {{ object.ipsec_profile|linkify|placeholder }} |
-
-
- | {% trans "Tunnel ID" %} |
- {{ object.tunnel_id|placeholder }} |
-
-
- | {% trans "Tenant" %} |
-
- {% if object.tenant.group %}
- {{ object.tenant.group|linkify }} /
- {% endif %}
- {{ object.tenant|linkify|placeholder }}
- |
-
-
-
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/tags.html' %}
- {% include 'inc/panels/comments.html' %}
- {% plugin_right_page object %}
-
-
-
-
-
-
- {% htmx_table 'vpn:tunneltermination_list' tunnel_id=object.pk %}
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/tunnelgroup.html b/netbox/templates/vpn/tunnelgroup.html
index 3c76e33ff..cc34b7e36 100644
--- a/netbox/templates/vpn/tunnelgroup.html
+++ b/netbox/templates/vpn/tunnelgroup.html
@@ -1,13 +1,6 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load render_table from django_tables2 %}
{% load i18n %}
-{% block breadcrumbs %}
-
{% trans "Tunnel Groups" %}
-{% endblock %}
-
{% block extra_controls %}
{% if perms.vpn.add_tunnel %}
@@ -15,36 +8,3 @@
{% endif %}
{% endblock extra_controls %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Name" %} |
- {{ object.name }} |
-
-
- | {% trans "Description" %} |
- {{ object.description|placeholder }} |
-
-
-
- {% include 'inc/panels/tags.html' %}
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/related_objects.html' %}
- {% include 'inc/panels/comments.html' %}
- {% include 'inc/panels/custom_fields.html' %}
- {% plugin_right_page object %}
-
-
-
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/templates/vpn/tunneltermination.html b/netbox/templates/vpn/tunneltermination.html
index bc5c591ec..f15e1d050 100644
--- a/netbox/templates/vpn/tunneltermination.html
+++ b/netbox/templates/vpn/tunneltermination.html
@@ -1,57 +1 @@
{% extends 'generic/object.html' %}
-{% load helpers %}
-{% load plugins %}
-{% load i18n %}
-
-{% block content %}
-
-
-
-
-
-
- | {% trans "Tunnel" %} |
- {{ object.tunnel|linkify }} |
-
-
- | {% trans "Role" %} |
- {% badge object.get_role_display bg_color=object.get_role_color %} |
-
-
- |
- {% if object.termination.device %}
- {% trans "Device" %}
- {% elif object.termination.virtual_machine %}
- {% trans "Virtual Machine" %}
- {% endif %}
- |
- {{ object.termination.parent_object|linkify }} |
-
-
- | {% trans "Interface" %} |
- {{ object.termination|linkify }} |
-
-
- | {% trans "Outside IP" %} |
- {{ object.outside_ip|linkify|placeholder }} |
-
-
-
- {% plugin_left_page object %}
-
-
- {% include 'inc/panels/custom_fields.html' %}
- {% include 'inc/panels/tags.html' %}
- {% plugin_right_page object %}
-
-
-
-
-
-
- {% htmx_table 'vpn:tunneltermination_list' tunnel_id=object.tunnel.pk id__n=object.pk %}
-
- {% plugin_full_width_page object %}
-
-
-{% endblock %}
diff --git a/netbox/vpn/ui/__init__.py b/netbox/vpn/ui/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/netbox/vpn/ui/panels.py b/netbox/vpn/ui/panels.py
new file mode 100644
index 000000000..41afec132
--- /dev/null
+++ b/netbox/vpn/ui/panels.py
@@ -0,0 +1,85 @@
+from django.utils.translation import gettext_lazy as _
+
+from netbox.ui import attrs, panels
+
+
+class TunnelGroupPanel(panels.OrganizationalObjectPanel):
+ pass
+
+
+class TunnelPanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ status = attrs.ChoiceAttr('status')
+ group = attrs.RelatedObjectAttr('group', linkify=True)
+ description = attrs.TextAttr('description')
+ encapsulation = attrs.ChoiceAttr('encapsulation')
+ ipsec_profile = attrs.RelatedObjectAttr('ipsec_profile', linkify=True, label=_('IPSec profile'))
+ tunnel_id = attrs.TextAttr('tunnel_id', label=_('Tunnel ID'))
+ tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
+
+
+class TunnelTerminationPanel(panels.ObjectAttributesPanel):
+ tunnel = attrs.RelatedObjectAttr('tunnel', linkify=True)
+ role = attrs.ChoiceAttr('role')
+ parent_object = attrs.RelatedObjectAttr(
+ 'termination.parent_object', linkify=True, label=_('Parent')
+ )
+ termination = attrs.RelatedObjectAttr('termination', linkify=True, label=_('Interface'))
+ outside_ip = attrs.RelatedObjectAttr('outside_ip', linkify=True, label=_('Outside IP'))
+
+
+class IKEProposalPanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ description = attrs.TextAttr('description')
+ authentication_method = attrs.ChoiceAttr('authentication_method', label=_('Authentication method'))
+ encryption_algorithm = attrs.ChoiceAttr('encryption_algorithm', label=_('Encryption algorithm'))
+ authentication_algorithm = attrs.ChoiceAttr('authentication_algorithm', label=_('Authentication algorithm'))
+ group = attrs.ChoiceAttr('group', label=_('DH group'))
+ sa_lifetime = attrs.TextAttr('sa_lifetime', label=_('SA lifetime (seconds)'))
+
+
+class IKEPolicyPanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ description = attrs.TextAttr('description')
+ version = attrs.ChoiceAttr('version', label=_('IKE version'))
+ mode = attrs.ChoiceAttr('mode')
+ preshared_key = attrs.TemplatedAttr(
+ 'preshared_key',
+ label=_('Pre-shared key'),
+ template_name='vpn/attrs/preshared_key.html',
+ )
+
+
+class IPSecProposalPanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ description = attrs.TextAttr('description')
+ encryption_algorithm = attrs.ChoiceAttr('encryption_algorithm', label=_('Encryption algorithm'))
+ authentication_algorithm = attrs.ChoiceAttr('authentication_algorithm', label=_('Authentication algorithm'))
+ sa_lifetime_seconds = attrs.TextAttr('sa_lifetime_seconds', label=_('SA lifetime (seconds)'))
+ sa_lifetime_data = attrs.TextAttr('sa_lifetime_data', label=_('SA lifetime (KB)'))
+
+
+class IPSecPolicyPanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ description = attrs.TextAttr('description')
+ pfs_group = attrs.ChoiceAttr('pfs_group', label=_('PFS group'))
+
+
+class IPSecProfilePanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ description = attrs.TextAttr('description')
+ mode = attrs.ChoiceAttr('mode')
+
+
+class L2VPNPanel(panels.ObjectAttributesPanel):
+ name = attrs.TextAttr('name')
+ identifier = attrs.TextAttr('identifier')
+ type = attrs.ChoiceAttr('type')
+ status = attrs.ChoiceAttr('status')
+ description = attrs.TextAttr('description')
+ tenant = attrs.RelatedObjectAttr('tenant', linkify=True)
+
+
+class L2VPNTerminationPanel(panels.ObjectAttributesPanel):
+ l2vpn = attrs.RelatedObjectAttr('l2vpn', linkify=True, label=_('L2VPN'))
+ assigned_object = attrs.RelatedObjectAttr('assigned_object', linkify=True, label=_('Assigned object'))
diff --git a/netbox/vpn/views.py b/netbox/vpn/views.py
index 219eab681..7da05e007 100644
--- a/netbox/vpn/views.py
+++ b/netbox/vpn/views.py
@@ -1,11 +1,24 @@
+from django.utils.translation import gettext_lazy as _
+
+from extras.ui.panels import CustomFieldsPanel, TagsPanel
from ipam.tables import RouteTargetTable
from netbox.object_actions import AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport
+from netbox.ui import actions, layout
+from netbox.ui.panels import (
+ CommentsPanel,
+ ContextTablePanel,
+ ObjectsTablePanel,
+ PluginContentPanel,
+ RelatedObjectsPanel,
+ TemplatePanel,
+)
from netbox.views import generic
from utilities.query import count_related
from utilities.views import GetRelatedModelsMixin, register_model_view
from . import filtersets, forms, tables
from .models import *
+from .ui import panels
#
# Tunnel groups
@@ -25,6 +38,17 @@ class TunnelGroupListView(generic.ObjectListView):
@register_model_view(TunnelGroup)
class TunnelGroupView(GetRelatedModelsMixin, generic.ObjectView):
queryset = TunnelGroup.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.TunnelGroupPanel(),
+ TagsPanel(),
+ ],
+ right_panels=[
+ RelatedObjectsPanel(),
+ CommentsPanel(),
+ CustomFieldsPanel(),
+ ],
+ )
def get_extra_context(self, request, instance):
return {
@@ -92,6 +116,30 @@ class TunnelListView(generic.ObjectListView):
@register_model_view(Tunnel)
class TunnelView(generic.ObjectView):
queryset = Tunnel.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.TunnelPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ TagsPanel(),
+ CommentsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ 'vpn.tunneltermination',
+ filters={'tunnel_id': lambda ctx: ctx['object'].pk},
+ actions=[
+ actions.AddObject(
+ 'vpn.tunneltermination',
+ url_params={'tunnel': lambda ctx: ctx['object'].pk},
+ label=_('Add a Termination'),
+ ),
+ ],
+ title=_('Terminations'),
+ ),
+ ],
+ )
@register_model_view(Tunnel, 'add', detail=False)
@@ -160,6 +208,25 @@ class TunnelTerminationListView(generic.ObjectListView):
@register_model_view(TunnelTermination)
class TunnelTerminationView(generic.ObjectView):
queryset = TunnelTermination.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.TunnelTerminationPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ TagsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ 'vpn.tunneltermination',
+ filters={
+ 'tunnel_id': lambda ctx: ctx['object'].tunnel.pk,
+ 'id__n': lambda ctx: ctx['object'].pk,
+ },
+ title=_('Peer Terminations'),
+ ),
+ ],
+ )
@register_model_view(TunnelTermination, 'add', detail=False)
@@ -210,6 +277,23 @@ class IKEProposalListView(generic.ObjectListView):
@register_model_view(IKEProposal)
class IKEProposalView(generic.ObjectView):
queryset = IKEProposal.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.IKEProposalPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ TagsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ 'vpn.ikepolicy',
+ filters={'ike_proposal_id': lambda ctx: ctx['object'].pk},
+ title=_('IKE Policies'),
+ ),
+ ],
+ )
@register_model_view(IKEProposal, 'add', detail=False)
@@ -264,8 +348,31 @@ class IKEPolicyListView(generic.ObjectListView):
@register_model_view(IKEPolicy)
-class IKEPolicyView(generic.ObjectView):
+class IKEPolicyView(GetRelatedModelsMixin, generic.ObjectView):
queryset = IKEPolicy.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.IKEPolicyPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ TagsPanel(),
+ RelatedObjectsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ 'vpn.ikeproposal',
+ filters={'ike_policy_id': lambda ctx: ctx['object'].pk},
+ title=_('Proposals'),
+ ),
+ ],
+ )
+
+ def get_extra_context(self, request, instance):
+ return {
+ 'related_models': self.get_related_models(request, instance),
+ }
@register_model_view(IKEPolicy, 'add', detail=False)
@@ -322,6 +429,23 @@ class IPSecProposalListView(generic.ObjectListView):
@register_model_view(IPSecProposal)
class IPSecProposalView(generic.ObjectView):
queryset = IPSecProposal.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.IPSecProposalPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ TagsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ 'vpn.ipsecpolicy',
+ filters={'ipsec_proposal_id': lambda ctx: ctx['object'].pk},
+ title=_('IPSec Policies'),
+ ),
+ ],
+ )
@register_model_view(IPSecProposal, 'add', detail=False)
@@ -376,8 +500,31 @@ class IPSecPolicyListView(generic.ObjectListView):
@register_model_view(IPSecPolicy)
-class IPSecPolicyView(generic.ObjectView):
+class IPSecPolicyView(GetRelatedModelsMixin, generic.ObjectView):
queryset = IPSecPolicy.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.IPSecPolicyPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ TagsPanel(),
+ RelatedObjectsPanel(),
+ ],
+ bottom_panels=[
+ ObjectsTablePanel(
+ 'vpn.ipsecproposal',
+ filters={'ipsec_policy_id': lambda ctx: ctx['object'].pk},
+ title=_('Proposals'),
+ ),
+ ],
+ )
+
+ def get_extra_context(self, request, instance):
+ return {
+ 'related_models': self.get_related_models(request, instance),
+ }
@register_model_view(IPSecPolicy, 'add', detail=False)
@@ -434,6 +581,18 @@ class IPSecProfileListView(generic.ObjectListView):
@register_model_view(IPSecProfile)
class IPSecProfileView(generic.ObjectView):
queryset = IPSecProfile.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.IPSecProfilePanel(),
+ TagsPanel(),
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ ],
+ right_panels=[
+ TemplatePanel('vpn/panels/ipsecprofile_ike_policy.html'),
+ TemplatePanel('vpn/panels/ipsecprofile_ipsec_policy.html'),
+ ],
+ )
@register_model_view(IPSecProfile, 'add', detail=False)
@@ -490,6 +649,45 @@ class L2VPNListView(generic.ObjectListView):
@register_model_view(L2VPN)
class L2VPNView(generic.ObjectView):
queryset = L2VPN.objects.all()
+ layout = layout.Layout(
+ layout.Row(
+ layout.Column(
+ panels.L2VPNPanel(),
+ TagsPanel(),
+ PluginContentPanel('left_page'),
+ ),
+ layout.Column(
+ CustomFieldsPanel(),
+ CommentsPanel(),
+ PluginContentPanel('right_page'),
+ ),
+ ),
+ layout.Row(
+ layout.Column(
+ ContextTablePanel('import_targets_table', title=_('Import Route Targets')),
+ ),
+ layout.Column(
+ ContextTablePanel('export_targets_table', title=_('Export Route Targets')),
+ ),
+ ),
+ layout.Row(
+ layout.Column(
+ ObjectsTablePanel(
+ 'vpn.l2vpntermination',
+ filters={'l2vpn_id': lambda ctx: ctx['object'].pk},
+ actions=[
+ actions.AddObject(
+ 'vpn.l2vpntermination',
+ url_params={'l2vpn': lambda ctx: ctx['object'].pk},
+ label=_('Add a Termination'),
+ ),
+ ],
+ title=_('Terminations'),
+ ),
+ PluginContentPanel('full_width_page'),
+ ),
+ ),
+ )
def get_extra_context(self, request, instance):
import_targets_table = RouteTargetTable(
@@ -564,6 +762,15 @@ class L2VPNTerminationListView(generic.ObjectListView):
@register_model_view(L2VPNTermination)
class L2VPNTerminationView(generic.ObjectView):
queryset = L2VPNTermination.objects.all()
+ layout = layout.SimpleLayout(
+ left_panels=[
+ panels.L2VPNTerminationPanel(),
+ ],
+ right_panels=[
+ CustomFieldsPanel(),
+ TagsPanel(),
+ ],
+ )
@register_model_view(L2VPNTermination, 'add', detail=False)