From bfa1c4e8366504f3889e84ff25c7486135206eb7 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Thu, 21 May 2026 00:57:12 -0500 Subject: [PATCH 1/3] Closes: #186 - Migrate to Layouts and Panels for all Detail Views --- netbox_routing/__init__.py | 1 - .../templates/netbox_routing/aspath.html | 37 ----- .../templates/netbox_routing/aspathentry.html | 55 -------- .../templates/netbox_routing/bfdprofile.html | 59 -------- .../netbox_routing/bgpaddressfamily.html | 42 ------ .../templates/netbox_routing/bgppeer.html | 60 -------- .../netbox_routing/bgppeeraddressfamily.html | 72 ---------- .../netbox_routing/bgppeertemplate.html | 54 ------- .../netbox_routing/bgppolicytemplate.html | 72 ---------- .../templates/netbox_routing/bgprouter.html | 42 ------ .../templates/netbox_routing/bgpscope.html | 42 ------ .../netbox_routing/bgpsessiontemplate.html | 78 ---------- .../templates/netbox_routing/community.html | 55 -------- .../netbox_routing/communitylist.html | 41 ------ .../netbox_routing/communitylistentry.html | 53 ------- .../netbox_routing/eigrpaddressfamily.html | 53 ------- .../netbox_routing/eigrpinterface.html | 76 ---------- .../netbox_routing/eigrpnetwork.html | 47 ------- .../templates/netbox_routing/eigrprouter.html | 53 ------- .../netbox_routing/inc/extra_controls.html | 18 --- .../inc/routemapentry_custom.html | 21 --- .../netbox_routing/inc/settings.html | 13 -- .../netbox_routing/objectchildrentable.html | 20 --- .../netbox_routing/ospf_interfaces.html | 14 -- .../templates/netbox_routing/ospfarea.html | 41 ------ .../netbox_routing/ospfinstance.html | 59 -------- .../netbox_routing/ospfinterface.html | 82 ----------- .../templates/netbox_routing/prefixlist.html | 35 ----- .../netbox_routing/prefixlistentry.html | 65 --------- .../templates/netbox_routing/routemap.html | 43 ------ .../netbox_routing/routemapentry.html | 56 -------- .../templates/netbox_routing/staticroute.html | 98 ------------- .../netbox_routing/staticroute_devices.html | 23 --- netbox_routing/templatetags/__init__.py | 0 netbox_routing/templatetags/entries.py | 18 --- netbox_routing/ui/__init__.py | 45 ++++++ netbox_routing/ui/attributes/__init__.py | 3 + netbox_routing/ui/attributes/gfk.py | 18 +++ netbox_routing/ui/panels/__init__.py | 48 +++++++ netbox_routing/ui/panels/bgp.py | 122 ++++++++++++++++ netbox_routing/ui/panels/community.py | 29 ++++ netbox_routing/ui/panels/core.py | 50 +++++++ netbox_routing/ui/panels/eigrp.py | 49 +++++++ netbox_routing/ui/panels/objects.py | 83 +++++++++++ netbox_routing/ui/panels/ospf.py | 41 ++++++ netbox_routing/ui/panels/static.py | 26 ++++ netbox_routing/views/bgp.py | 133 +++++++++++++++++- netbox_routing/views/community.py | 39 ++++- netbox_routing/views/eigrp.py | 62 +++++++- netbox_routing/views/objects.py | 98 +++++++++++-- netbox_routing/views/ospf.py | 50 +++++-- netbox_routing/views/static.py | 19 ++- 52 files changed, 881 insertions(+), 1632 deletions(-) delete mode 100644 netbox_routing/templates/netbox_routing/aspath.html delete mode 100644 netbox_routing/templates/netbox_routing/aspathentry.html delete mode 100644 netbox_routing/templates/netbox_routing/bfdprofile.html delete mode 100644 netbox_routing/templates/netbox_routing/bgpaddressfamily.html delete mode 100644 netbox_routing/templates/netbox_routing/bgppeer.html delete mode 100644 netbox_routing/templates/netbox_routing/bgppeeraddressfamily.html delete mode 100644 netbox_routing/templates/netbox_routing/bgppeertemplate.html delete mode 100644 netbox_routing/templates/netbox_routing/bgppolicytemplate.html delete mode 100644 netbox_routing/templates/netbox_routing/bgprouter.html delete mode 100644 netbox_routing/templates/netbox_routing/bgpscope.html delete mode 100644 netbox_routing/templates/netbox_routing/bgpsessiontemplate.html delete mode 100644 netbox_routing/templates/netbox_routing/community.html delete mode 100644 netbox_routing/templates/netbox_routing/communitylist.html delete mode 100644 netbox_routing/templates/netbox_routing/communitylistentry.html delete mode 100644 netbox_routing/templates/netbox_routing/eigrpaddressfamily.html delete mode 100644 netbox_routing/templates/netbox_routing/eigrpinterface.html delete mode 100644 netbox_routing/templates/netbox_routing/eigrpnetwork.html delete mode 100644 netbox_routing/templates/netbox_routing/eigrprouter.html delete mode 100644 netbox_routing/templates/netbox_routing/inc/extra_controls.html delete mode 100644 netbox_routing/templates/netbox_routing/inc/routemapentry_custom.html delete mode 100644 netbox_routing/templates/netbox_routing/inc/settings.html delete mode 100644 netbox_routing/templates/netbox_routing/objectchildrentable.html delete mode 100644 netbox_routing/templates/netbox_routing/ospf_interfaces.html delete mode 100644 netbox_routing/templates/netbox_routing/ospfarea.html delete mode 100644 netbox_routing/templates/netbox_routing/ospfinstance.html delete mode 100644 netbox_routing/templates/netbox_routing/ospfinterface.html delete mode 100644 netbox_routing/templates/netbox_routing/prefixlist.html delete mode 100644 netbox_routing/templates/netbox_routing/prefixlistentry.html delete mode 100644 netbox_routing/templates/netbox_routing/routemap.html delete mode 100644 netbox_routing/templates/netbox_routing/routemapentry.html delete mode 100644 netbox_routing/templates/netbox_routing/staticroute.html delete mode 100644 netbox_routing/templates/netbox_routing/staticroute_devices.html delete mode 100644 netbox_routing/templatetags/__init__.py delete mode 100644 netbox_routing/templatetags/entries.py create mode 100644 netbox_routing/ui/__init__.py create mode 100644 netbox_routing/ui/attributes/__init__.py create mode 100644 netbox_routing/ui/attributes/gfk.py create mode 100644 netbox_routing/ui/panels/__init__.py create mode 100644 netbox_routing/ui/panels/bgp.py create mode 100644 netbox_routing/ui/panels/community.py create mode 100644 netbox_routing/ui/panels/core.py create mode 100644 netbox_routing/ui/panels/eigrp.py create mode 100644 netbox_routing/ui/panels/objects.py create mode 100644 netbox_routing/ui/panels/ospf.py create mode 100644 netbox_routing/ui/panels/static.py diff --git a/netbox_routing/__init__.py b/netbox_routing/__init__.py index 414e96f..86eb3c8 100644 --- a/netbox_routing/__init__.py +++ b/netbox_routing/__init__.py @@ -21,7 +21,6 @@ class NetboxRouting(PluginConfig): graphql_schema = 'graphql.schema.schema' def ready(self): - from netbox_routing.templatetags.entries import get_entry_url # noqa: F401 from netbox_routing.fields.generic import NetBoxGenericRelation from dcim.models import Region, SiteGroup, Site, Location, Device diff --git a/netbox_routing/templates/netbox_routing/aspath.html b/netbox_routing/templates/netbox_routing/aspath.html deleted file mode 100644 index e8b6596..0000000 --- a/netbox_routing/templates/netbox_routing/aspath.html +++ /dev/null @@ -1,37 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
AS Path
-
- - - - - -
Name - {{ object.name }} -
-
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/aspathentry.html b/netbox_routing/templates/netbox_routing/aspathentry.html deleted file mode 100644 index d977980..0000000 --- a/netbox_routing/templates/netbox_routing/aspathentry.html +++ /dev/null @@ -1,55 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
AS Path Entry
-
- - - - - - - - - - - - - - - - - -
AS Path Entry - {{ object.aspath|linkify }} -
Action - {{ object.action }} -
Sequence - {{ object.sequence }} -
ASN - {{ object.asn|linkify }} -
-
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bfdprofile.html b/netbox_routing/templates/netbox_routing/bfdprofile.html deleted file mode 100644 index 62acf3f..0000000 --- a/netbox_routing/templates/netbox_routing/bfdprofile.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Peer
- - - - - - - - - - - - - - - - - - - - - -
Name - {{ object.name }} -
Min RX - {{ object.min_rx_int|placeholder }} -
Min TX - {{ object.min_tx_int|placeholder }} -
Multiplier - {{ object.multiplier|placeholder }} -
Hold Time - {{ object.hold|placeholder }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgpaddressfamily.html b/netbox_routing/templates/netbox_routing/bgpaddressfamily.html deleted file mode 100644 index d15f255..0000000 --- a/netbox_routing/templates/netbox_routing/bgpaddressfamily.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Address Family
- - - - - - - - - -
Scope - {{ object.scope|linkify }} -
Address Family - {{ object.address_family }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgppeer.html b/netbox_routing/templates/netbox_routing/bgppeer.html deleted file mode 100644 index 859f1be..0000000 --- a/netbox_routing/templates/netbox_routing/bgppeer.html +++ /dev/null @@ -1,60 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Peer
- - - - - - - - - - - - - - - - - - - - - -
Scope - {{ object.scope|linkify }} -
Peer - {{ object.peer|linkify }} -
Remote AS - {{ object.remote_as|linkify }} -
Local AS - {{ object.local_as|linkify }} -
Status - {{ object.status }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgppeeraddressfamily.html b/netbox_routing/templates/netbox_routing/bgppeeraddressfamily.html deleted file mode 100644 index 713038b..0000000 --- a/netbox_routing/templates/netbox_routing/bgppeeraddressfamily.html +++ /dev/null @@ -1,72 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Peer Address Family
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Assigned Object - {{ object.assigned_object|linkify }} -
Address Family - {{ object.address_family|linkify }} -
Enabled - {{ object.enabled }} -
Route Map (in) - {{ object.routemap_in|linkify }} -
Route Map (out) - {{ object.routemap_out|linkify }} -
Prefix List (in) - {{ object.prefixlist_in|linkify }} -
Prefix List (out) - {{ object.prefixlist_out|linkify }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgppeertemplate.html b/netbox_routing/templates/netbox_routing/bgppeertemplate.html deleted file mode 100644 index 33a3ca7..0000000 --- a/netbox_routing/templates/netbox_routing/bgppeertemplate.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Peer Template
- - - - - - - - - - - - - - - - - -
Name - {{ object.name }} -
Remote AS - {{ object.remote_as|linkify }} -
Enabled - {{ object.enabled }} -
Tenant - {{ object.tenant|linkify }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgppolicytemplate.html b/netbox_routing/templates/netbox_routing/bgppolicytemplate.html deleted file mode 100644 index 4d17f5b..0000000 --- a/netbox_routing/templates/netbox_routing/bgppolicytemplate.html +++ /dev/null @@ -1,72 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Policy Template
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name - {{ object.name }} -
Enabled - {{ object.enabled }} -
Prefix List (In) - {{ object.prefixlist_in|linkify }} -
Prefix List (Out) - {{ object.prefixlist_out|linkify }} -
Route Map (In) - {{ object.routemap_in|linkify }} -
Route Map (Out) - {{ object.routemap_out|linkify }} -
Tenant - {{ object.tenant|linkify }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgprouter.html b/netbox_routing/templates/netbox_routing/bgprouter.html deleted file mode 100644 index 1bad551..0000000 --- a/netbox_routing/templates/netbox_routing/bgprouter.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Router
- - - - - - - - - -
Device - {{ object.assigned_object|linkify }} -
AS Number - {{ object.asn|linkify }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgpscope.html b/netbox_routing/templates/netbox_routing/bgpscope.html deleted file mode 100644 index 4316c41..0000000 --- a/netbox_routing/templates/netbox_routing/bgpscope.html +++ /dev/null @@ -1,42 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Scope
- - - - - - - - - -
Router - {{ object.router|linkify }} -
AS Number - {{ object.vrf|linkify }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/bgpsessiontemplate.html b/netbox_routing/templates/netbox_routing/bgpsessiontemplate.html deleted file mode 100644 index ff429b7..0000000 --- a/netbox_routing/templates/netbox_routing/bgpsessiontemplate.html +++ /dev/null @@ -1,78 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
BGP Session Template
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Name - {{ object.name }} -
Parent Template - {{ object.parent|linkify }} -
Remote AS - {{ object.remote_as|linkify }} -
Local AS - {{ object.local_as|linkify }} -
Enabled - {{ object.enabled }} -
BFD - {{ object.bfd }} -
Password - {{ object.password }} -
Tenant - {{ object.tenant|linkify }} -
-
- {% include 'netbox_routing/inc/settings.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/community.html b/netbox_routing/templates/netbox_routing/community.html deleted file mode 100644 index 8ce1771..0000000 --- a/netbox_routing/templates/netbox_routing/community.html +++ /dev/null @@ -1,55 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
Community
-
- - - - - - - - - - - - - - - - - - - - - -
Name{{ object.name|placeholder }}
Community - {{ object.community }} -
Status - {{ object.get_status_display }} -
Role{{ object.role|linkify|placeholder }}
Description{{ object.description|placeholder }}
-
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/communitylist.html b/netbox_routing/templates/netbox_routing/communitylist.html deleted file mode 100644 index ed36022..0000000 --- a/netbox_routing/templates/netbox_routing/communitylist.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
Community List
-
- - - - - - - - - -
Name - {{ object.name }} -
Description{{ object.description|placeholder }}
-
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/communitylistentry.html b/netbox_routing/templates/netbox_routing/communitylistentry.html deleted file mode 100644 index bd32f7e..0000000 --- a/netbox_routing/templates/netbox_routing/communitylistentry.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
Community List
-
- - - - - - - - - - - - - - - - - -
Community List - {{ object.community_list|linkify }} -
Action - {{ object.action }} -
Community - {{ object.community|linkify }} -
Description{{ object.description|placeholder }}
-
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/eigrpaddressfamily.html b/netbox_routing/templates/netbox_routing/eigrpaddressfamily.html deleted file mode 100644 index e3e05dd..0000000 --- a/netbox_routing/templates/netbox_routing/eigrpaddressfamily.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
EIGRP Details
- - - - - - - - - - - - - - - - - -
Router - {{ object.router }} -
VRF - {{ object.vrf }} -
Family - {{ object.family }} -
Router ID - {% if object.rid %}{{ object.rid }}{% else %}{{ object.router.rid}}{% endif %} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/eigrpinterface.html b/netbox_routing/templates/netbox_routing/eigrpinterface.html deleted file mode 100644 index db688a4..0000000 --- a/netbox_routing/templates/netbox_routing/eigrpinterface.html +++ /dev/null @@ -1,76 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
- - - - - - - - - - - - - -
Router - {{ object.router|linkify }} -
Address Family - {{ object.address_family|linkify }} -
Interface - {{ object.interface|linkify }} -
-
-
-
Attributes
- - - - - - - - - - - - - - - - - -
Passive - {{ object.passive|placeholder }} -
BFD - {{ object.bfd|placeholder }} -
Authentication Type - {{ object.authentication|placeholder }} -
Passphrase (or keyring) - {{ object.passphrase|placeholder }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/eigrpnetwork.html b/netbox_routing/templates/netbox_routing/eigrpnetwork.html deleted file mode 100644 index 3d44a60..0000000 --- a/netbox_routing/templates/netbox_routing/eigrpnetwork.html +++ /dev/null @@ -1,47 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
- - - - - - - - - - - - - -
Router - {{ object.router|linkify }} -
Address Family - {{ object.address_family|linkify }} -
Network - {{ object.network|linkify }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/eigrprouter.html b/netbox_routing/templates/netbox_routing/eigrprouter.html deleted file mode 100644 index 5c17687..0000000 --- a/netbox_routing/templates/netbox_routing/eigrprouter.html +++ /dev/null @@ -1,53 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
EIGRP Details
- - - - - - - - - - - - - - - - - -
Device - {{ object.device|linkify }} -
Router ID - {{ object.rid }} -
Name - {{ object.name }} -
Process ID - {{ object.process_id }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/inc/extra_controls.html b/netbox_routing/templates/netbox_routing/inc/extra_controls.html deleted file mode 100644 index 29f095a..0000000 --- a/netbox_routing/templates/netbox_routing/inc/extra_controls.html +++ /dev/null @@ -1,18 +0,0 @@ -{% block extra_controls %} - {% if 'bulk_edit' in actions %} - - Bulk Edit - - {% endif %} - {% if 'bulk_delete' in actions %} - - Bulk Delete - - {% endif %} - - Add Entry - -{% endblock %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/inc/routemapentry_custom.html b/netbox_routing/templates/netbox_routing/inc/routemapentry_custom.html deleted file mode 100644 index d301b6f..0000000 --- a/netbox_routing/templates/netbox_routing/inc/routemapentry_custom.html +++ /dev/null @@ -1,21 +0,0 @@ -{% load humanize %} -{% load helpers %} -{% load i18n %} -
-

- {% trans "Custom Match" %} -
- {% copy_content "match" %} -
-

-
{{ object.match }}
-
-
-

- {% trans "Custom Set" %} -
- {% copy_content "set" %} -
-

-
{{ object.set }}
-
\ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/inc/settings.html b/netbox_routing/templates/netbox_routing/inc/settings.html deleted file mode 100644 index d65b41c..0000000 --- a/netbox_routing/templates/netbox_routing/inc/settings.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
Settings
- - {% for setting in object.settings.all %} - - - - - {% endfor %} -
{{ setting.get_key_display }} - {{ setting.value }} -
-
diff --git a/netbox_routing/templates/netbox_routing/objectchildrentable.html b/netbox_routing/templates/netbox_routing/objectchildrentable.html deleted file mode 100644 index 464aaf4..0000000 --- a/netbox_routing/templates/netbox_routing/objectchildrentable.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends 'generic/object_children.html' %} - -{% block extra_controls %} - {% if 'bulk_edit' in actions %} - - Bulk Edit - - {% endif %} - {% if 'bulk_delete' in actions %} - - Bulk Delete - - {% endif %} - - Add Entry - -{% endblock %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/ospf_interfaces.html b/netbox_routing/templates/netbox_routing/ospf_interfaces.html deleted file mode 100644 index c704fe5..0000000 --- a/netbox_routing/templates/netbox_routing/ospf_interfaces.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends 'generic/object_children.html' %} -{% load helpers %} - -{% block bulk_extra_controls %} - {{ block.super }} - {% if perms.netbox_routing.add_ospfinterface %} -
- - Add Interfaces - -
- {% endif %} -{% endblock bulk_extra_controls %} diff --git a/netbox_routing/templates/netbox_routing/ospfarea.html b/netbox_routing/templates/netbox_routing/ospfarea.html deleted file mode 100644 index cd3d27a..0000000 --- a/netbox_routing/templates/netbox_routing/ospfarea.html +++ /dev/null @@ -1,41 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
OSPF Area Details
- - - - - - - - - -
Area ID - {{ object.area_id }} -
Area Type - {{ object.get_area_type_display }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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_routing/templates/netbox_routing/ospfinstance.html b/netbox_routing/templates/netbox_routing/ospfinstance.html deleted file mode 100644 index b9d2875..0000000 --- a/netbox_routing/templates/netbox_routing/ospfinstance.html +++ /dev/null @@ -1,59 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
OSPF Details
- - - - - - - - - - - - - - - - - - - - - -
Name - {{ object.name }} -
Router ID - {{ object.router_id }} -
Process ID - {{ object.process_id }} -
Device - {{ object.device|linkify }} -
VRF - {{ object.vrf|linkify }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/ospfinterface.html b/netbox_routing/templates/netbox_routing/ospfinterface.html deleted file mode 100644 index 2d173a4..0000000 --- a/netbox_routing/templates/netbox_routing/ospfinterface.html +++ /dev/null @@ -1,82 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
- - - - - - - - - - - - - -
Instance - {{ object.instance|linkify }} -
Area - {{ object.area|linkify }} -
Interface - {{ object.interface|linkify }} -
-
-
-
Attributes
- - - - - - - - - - - - - - - - - - - - - -
Passive - {{ object.passive|placeholder }} -
BFD - {{ object.bfd|placeholder }} -
Priority - {{ object.priority|placeholder }} -
Authentication Type - {{ object.authentication|placeholder }} -
Passphrase (or keyring) - {{ object.passphrase|placeholder }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/prefixlist.html b/netbox_routing/templates/netbox_routing/prefixlist.html deleted file mode 100644 index 04cb34f..0000000 --- a/netbox_routing/templates/netbox_routing/prefixlist.html +++ /dev/null @@ -1,35 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
Static Route
- - - - - -
Name - {{ object.name }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/prefixlistentry.html b/netbox_routing/templates/netbox_routing/prefixlistentry.html deleted file mode 100644 index af4dee6..0000000 --- a/netbox_routing/templates/netbox_routing/prefixlistentry.html +++ /dev/null @@ -1,65 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
Prefix List Entry
- - - - - - - - - - - - - - - - - - - - - - - - - -
Prefix List - {{ object.prefix_list|linkify }} -
Sequence - {{ object.sequence }} -
Type - {% badge object.assigned_prefix_type %} -
Prefix - {{ object.assigned_prefix|linkify|placeholder }} -
GE - {{ object.ge }} -
LE - {{ object.le }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/routemap.html b/netbox_routing/templates/netbox_routing/routemap.html deleted file mode 100644 index 9fb28c5..0000000 --- a/netbox_routing/templates/netbox_routing/routemap.html +++ /dev/null @@ -1,43 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} -{% load entries %} - -{% block extra_controls %} - - Bulk Edit - -{% endblock %} - -{% block content %} -
-
-
-
Static Route
- - - - - -
Name - {{ object.name }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/routemapentry.html b/netbox_routing/templates/netbox_routing/routemapentry.html deleted file mode 100644 index dbf90b1..0000000 --- a/netbox_routing/templates/netbox_routing/routemapentry.html +++ /dev/null @@ -1,56 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} -{% load i18n %} - -{% block content %} -
-
-
-
Route Map Entry
- - - - - - - - - - - - - - - - - -
Route Map - {{ object.route_map|linkify }} -
Action - {{ object.action }} -
Sequence - {{ object.sequence }} -
Flow Control (Continue) - {{ object.flow_control }} -
-
- {% include 'netbox_routing/inc/routemapentry_custom.html' %} - {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/comments.html' %} - {% include 'inc/panels/tags.html' %} - {% include 'inc/panels/tags.html' %} - {% plugin_right_page object %} -
-
-
-
- {% plugin_full_width_page object %} -
-
-{% endblock %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/staticroute.html b/netbox_routing/templates/netbox_routing/staticroute.html deleted file mode 100644 index 3f20492..0000000 --- a/netbox_routing/templates/netbox_routing/staticroute.html +++ /dev/null @@ -1,98 +0,0 @@ -{% extends 'generic/object.html' %} -{% load humanize %} -{% load helpers %} -{% load plugins %} - -{% block content %} -
-
-
-
Details
- - - - - - - - - -
Name - {{object.name}} -
Description - {{object.description}} -
-
-
-
Static Route
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VRF - {% if object.vrf %} - {{ object.vrf }} - {% else %} - Global - {% endif %} -
Prefix - {{ object.prefix }} -
Next Hop - {{ object.next_hop }} -
Interface Next Hop - {{ object.interface_next_hop }} -
Name - {{ object.name|placeholder }} -
Metric - {{ object.metric }} -
Permanent - {{ object.permanent }} -
Route Tag - {{ object.tag }} -
-
- {% plugin_left_page object %} -
-
- {% include 'inc/panels/related_objects.html' %} - {% 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 %} \ No newline at end of file diff --git a/netbox_routing/templates/netbox_routing/staticroute_devices.html b/netbox_routing/templates/netbox_routing/staticroute_devices.html deleted file mode 100644 index f94597e..0000000 --- a/netbox_routing/templates/netbox_routing/staticroute_devices.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends 'generic/object.html' %} -{% load render_table from django_tables2 %} -{% load helpers %} -{% load static %} - -{% block content %} - {% include 'inc/table_controls_htmx.html' with table_modal="StaticRouteDevices_config" %} - -
- {% csrf_token %} - -
-
- {% include 'htmx/table.html' %} -
-
-
-{% endblock %} - -{% block modals %} - {{ block.super }} - {% table_config_form table table_name="StaticRouteDevices"%} -{% endblock modals %} \ No newline at end of file diff --git a/netbox_routing/templatetags/__init__.py b/netbox_routing/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/netbox_routing/templatetags/entries.py b/netbox_routing/templatetags/entries.py deleted file mode 100644 index be9f8bd..0000000 --- a/netbox_routing/templatetags/entries.py +++ /dev/null @@ -1,18 +0,0 @@ -from django import template -from django.urls import reverse - -register = template.Library() - - -@register.simple_tag() -def get_entry_url(method, instance, return_url): - url = ( - f'plugins:{instance._meta.app_label}:{instance._meta.model_name}entry_{method}' - ) - - if not return_url: - return_url = instance.get_absolute_url() - return reverse( - url, - query={f'{instance._meta.model_name}': instance.pk, 'return_url': return_url}, - ) diff --git a/netbox_routing/ui/__init__.py b/netbox_routing/ui/__init__.py new file mode 100644 index 0000000..38a79d2 --- /dev/null +++ b/netbox_routing/ui/__init__.py @@ -0,0 +1,45 @@ +from .panels import * +from .attributes import * + +__all__ = ( + # Attributes + 'ContentTypeAttribute', + # Panels + 'SettingsChoicePanel', + 'BGPPolicyFilteringPanel', + 'BGPPolicyTemplatePanel', + 'BGPSessionTemplatePanel', + 'BGPSettingPanel', + 'BGPPeerTemplatePanel', + 'BGPRouterPanel', + 'BGPRouterTemplatesPanel', + 'BGPScopePanel', + 'BGPAddressFamilyPanel', + 'BGPPeerPanel', + 'BGPPeerAddressFamilyPanel', + 'BGPPeerSettingPanel', + 'CommunityListPanel', + 'CommunityPanel', + 'CommunityListEntryPanel', + 'EIGRPRouterPanel', + 'EIGRPAddressFamilyPanel', + 'EIGRPNetworkPanel', + 'EIGRPInterfacePanel', + 'StaticRoutePanel', + 'StaticRouteRoutePanel', + 'BFDProfilePanel', + 'BFDProfileSessionPanel', + 'CustomPrefixPanel', + 'ASPathPanel', + 'ASPathEntryPanel', + 'PrefixListPanel', + 'PrefixListEntryPanel', + 'RouteMapPanel', + 'RouteMapEntryPanel', + 'RouteMapEntryMatchPanel', + 'RouteMapEntrySetPanel', + 'OSPFInstancePanel', + 'OSPFAreaPanel', + 'OSPFInterfacePanel', + 'OSPFInterfaceSettingsPanel', +) diff --git a/netbox_routing/ui/attributes/__init__.py b/netbox_routing/ui/attributes/__init__.py new file mode 100644 index 0000000..f66e818 --- /dev/null +++ b/netbox_routing/ui/attributes/__init__.py @@ -0,0 +1,3 @@ +from .gfk import * + +__all__ = ('ContentTypeAttribute',) diff --git a/netbox_routing/ui/attributes/gfk.py b/netbox_routing/ui/attributes/gfk.py new file mode 100644 index 0000000..36ab9a7 --- /dev/null +++ b/netbox_routing/ui/attributes/gfk.py @@ -0,0 +1,18 @@ +from netbox.ui.attrs import TextAttr +from utilities.data import resolve_attr_path +from utilities.object_types import object_type_name + +__all__ = ('ContentTypeAttribute',) + + +class ContentTypeAttribute(TextAttr): + """ + An ObjectAttribute for displaying a ContentType. The value is the ContentType's model name, but the label is the + verbose name of the model. + """ + + def get_value(self, obj): + value = resolve_attr_path(obj, self.accessor) + if value is None: + return None + return object_type_name(value, include_app=False) diff --git a/netbox_routing/ui/panels/__init__.py b/netbox_routing/ui/panels/__init__.py new file mode 100644 index 0000000..fca0815 --- /dev/null +++ b/netbox_routing/ui/panels/__init__.py @@ -0,0 +1,48 @@ +from .core import * +from .bgp import * +from .community import * +from .eigrp import * +from .static import * +from .objects import * +from .ospf import * + + +__all__ = ( + 'SettingsChoicePanel', + 'BGPSettingPanel', + 'BGPPeerTemplatePanel', + 'BGPPolicyTemplatePanel', + 'BGPSessionTemplatePanel', + 'BGPPolicyFilteringPanel', + 'BGPRouterPanel', + 'BGPRouterTemplatesPanel', + 'BGPScopePanel', + 'BGPAddressFamilyPanel', + 'BGPPeerPanel', + 'BGPPeerAddressFamilyPanel', + 'BGPPeerSettingPanel', + 'CommunityListPanel', + 'CommunityPanel', + 'CommunityListEntryPanel', + 'EIGRPRouterPanel', + 'EIGRPAddressFamilyPanel', + 'EIGRPNetworkPanel', + 'EIGRPInterfacePanel', + 'StaticRoutePanel', + 'StaticRouteRoutePanel', + 'BFDProfilePanel', + 'BFDProfileSessionPanel', + 'CustomPrefixPanel', + 'ASPathPanel', + 'ASPathEntryPanel', + 'PrefixListPanel', + 'PrefixListEntryPanel', + 'RouteMapPanel', + 'RouteMapEntryPanel', + 'RouteMapEntryMatchPanel', + 'RouteMapEntrySetPanel', + 'OSPFInstancePanel', + 'OSPFAreaPanel', + 'OSPFInterfacePanel', + 'OSPFInterfaceSettingsPanel', +) diff --git a/netbox_routing/ui/panels/bgp.py b/netbox_routing/ui/panels/bgp.py new file mode 100644 index 0000000..4c151b9 --- /dev/null +++ b/netbox_routing/ui/panels/bgp.py @@ -0,0 +1,122 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels +from netbox_routing.ui.attributes import ContentTypeAttribute + +__all__ = ( + 'BGPSettingPanel', + 'BGPPeerTemplatePanel', + 'BGPPolicyTemplatePanel', + 'BGPSessionTemplatePanel', + 'BGPPolicyFilteringPanel', + 'BGPRouterPanel', + 'BGPRouterTemplatesPanel', + 'BGPScopePanel', + 'BGPAddressFamilyPanel', + 'BGPPeerPanel', + 'BGPPeerAddressFamilyPanel', + 'BGPPeerSettingPanel', + 'BFDProfilePanel', + 'BFDProfileSessionPanel', +) + + +class BFDProfilePanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + description = attrs.TextAttr('description', label=_('Description')) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BFDProfileSessionPanel(panels.ObjectAttributesPanel): + min_rx_int = attrs.NumericAttr('min_rx_int', label=_('Min Receive')) + min_tx_int = attrs.NumericAttr('min_tx_int', label=_('Min Transmit')) + multiplier = attrs.NumericAttr('multiplier', label=_('Multiplier')) + hold = attrs.NumericAttr('hold', label=_('Hold Time')) + + +class BGPPolicyFilteringPanel(panels.ObjectAttributesPanel): + prefixlist_out = attrs.RelatedObjectAttr('prefixlist_out', linkify=True) + prefixlist_in = attrs.RelatedObjectAttr('prefixlist_in', linkify=True) + routemap_out = attrs.RelatedObjectAttr('routemap_out', linkify=True) + routemap_in = attrs.RelatedObjectAttr('routemap_in', linkify=True) + + +class BGPPeerSettingPanel(panels.ObjectAttributesPanel): + enabled = attrs.BooleanAttr('enabled', label=_('Enabled')) + password = attrs.TextAttr('password', label=_('Password')) + ttl = attrs.TextAttr('ttl', label=_('TTL')) + bfd_profile = attrs.RelatedObjectAttr('bfd_profile', linkify=True) + + +class BGPSettingPanel(panels.ObjectAttributesPanel): + assigned_object_type = ContentTypeAttribute('assigned_object_type', label=_('Type')) + assigned_object = attrs.RelatedObjectAttr('assigned_object', linkify=True) + name = attrs.TextAttr('key', label=_('Name')) + value = attrs.TextAttr('value') + + +class BGPPeerTemplatePanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + remote_as = attrs.TextAttr('remote_as', label=_('Remote AS')) + enabled = attrs.BooleanAttr('enabled', label=_('Enabled')) + tenant = attrs.RelatedObjectAttr('tenant', linkify=True) + + +class BGPPolicyTemplatePanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + parents = attrs.RelatedObjectListAttr('parents', linkify=True) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BGPSessionTemplatePanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + remote_as = attrs.RelatedObjectAttr('remote_as', label=_('Remote AS'), linkify=True) + local_as = attrs.RelatedObjectAttr('local_as', label=_('Local AS'), linkify=True) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BGPRouterPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + assigned_object_type = ContentTypeAttribute('assigned_object_type', label=_('Type')) + assigned_object = attrs.RelatedObjectAttr('assigned_object', linkify=True) + asn = attrs.RelatedObjectAttr('asn', label=_('ASN'), linkify=True) + description = attrs.TextAttr('description', label=_('Description')) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BGPRouterTemplatesPanel(panels.ObjectAttributesPanel): + peer_templates = attrs.RelatedObjectListAttr('peer_templates', linkify=True) + policy_templates = attrs.RelatedObjectListAttr('policy_templates', linkify=True) + session_templates = attrs.RelatedObjectListAttr('session_templates', linkify=True) + + +class BGPScopePanel(panels.ObjectAttributesPanel): + router = attrs.RelatedObjectAttr('router', linkify=True) + vrf = attrs.RelatedObjectAttr('vrf', linkify=True) + description = attrs.TextAttr('description', label=_('Description')) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BGPAddressFamilyPanel(panels.ObjectAttributesPanel): + scope = attrs.RelatedObjectAttr('router', linkify=True) + address_family = attrs.ChoiceAttr('address_family', label=_('Address Family')) + description = attrs.TextAttr('description', label=_('Description')) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BGPPeerPanel(panels.ObjectAttributesPanel): + scope = attrs.RelatedObjectAttr('scope', linkify=True) + peer = attrs.RelatedObjectAttr('peer', linkify=True) + remote_as = attrs.RelatedObjectAttr('remote_as', label=_('Remote AS'), linkify=True) + local_as = attrs.RelatedObjectAttr('local_as', label=_('Local AS'), linkify=True) + status = attrs.ChoiceAttr('status', label=_('Status')) + description = attrs.TextAttr('description', label=_('Description')) + tenants = attrs.RelatedObjectAttr('tenants', linkify=True) + + +class BGPPeerAddressFamilyPanel(panels.ObjectAttributesPanel): + assigned_object = attrs.RelatedObjectAttr('assigned_object', linkify=True) + address_family = attrs.RelatedObjectAttr( + 'address_family', linkify=True, label=_('Address Family') + ) + enabled = attrs.BooleanAttr('enabled', label=_('Enabled')) diff --git a/netbox_routing/ui/panels/community.py b/netbox_routing/ui/panels/community.py new file mode 100644 index 0000000..fbace70 --- /dev/null +++ b/netbox_routing/ui/panels/community.py @@ -0,0 +1,29 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + +__all__ = ( + 'CommunityListPanel', + 'CommunityPanel', + 'CommunityListEntryPanel', +) + + +class CommunityListPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + description = attrs.TextAttr('description', label=_('Description')) + + +class CommunityPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + community = attrs.TextAttr('community', label=_('Community')) + status = attrs.ChoiceAttr('status', label=_('Status')) + role = attrs.ChoiceAttr('role', label=_('Role')) + description = attrs.TextAttr('description', label=_('Description')) + + +class CommunityListEntryPanel(panels.ObjectAttributesPanel): + community_list = attrs.RelatedObjectAttr('community_list', linkify=True) + action = attrs.ChoiceAttr('action', label=_('Action')) + community = attrs.RelatedObjectAttr('community', linkify=True) + description = attrs.TextAttr('description', label=_('Description')) diff --git a/netbox_routing/ui/panels/core.py b/netbox_routing/ui/panels/core.py new file mode 100644 index 0000000..b984eeb --- /dev/null +++ b/netbox_routing/ui/panels/core.py @@ -0,0 +1,50 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + +__all__ = ('SettingsChoicePanel',) + + +class SettingsChoicePanel(panels.ObjectPanel): + template_name = 'ui/panels/object_attributes.html' + + def __init__(self, choices, accessor='settings', **kwargs): + super().__init__(**kwargs) + self._accessor = accessor + self._attrs = {} + self._choices = choices + + for choice, label in self._choices.CHOICES: + choice_type = self._choices.FIELD_TYPES[choice] + if choice_type in ['ipaddr', 'string']: + self._attrs[choice] = attrs.TextAttr('value', label=_(label)) + elif choice_type in [ + 'integer', + ]: + self._attrs[choice] = attrs.NumericAttr('value', label=_(label)) + elif choice_type in [ + 'boolean', + ]: + self._attrs[choice] = attrs.BooleanAttr('value', label=_(label)) + + def get_context(self, context): + ctx = super().get_context(context) + settings = { + setting.key: setting + for setting in getattr(ctx['object'], self._accessor).all() + } + + attr_names = set(settings.keys()) + return { + **ctx, + 'attrs': [ + { + 'label': attr.label, + 'value': attr.render( + settings.get(name), {'name': name, 'perms': ctx['perms']} + ), + } + for name, attr in self._attrs.items() + if name in attr_names + ], + } diff --git a/netbox_routing/ui/panels/eigrp.py b/netbox_routing/ui/panels/eigrp.py new file mode 100644 index 0000000..2364401 --- /dev/null +++ b/netbox_routing/ui/panels/eigrp.py @@ -0,0 +1,49 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + +__all__ = ( + 'EIGRPRouterPanel', + 'EIGRPAddressFamilyPanel', + 'EIGRPNetworkPanel', + 'EIGRPInterfacePanel', +) + + +class EIGRPRouterPanel(panels.ObjectAttributesPanel): + device = attrs.RelatedObjectAttr('device', label=_('Device')) + mode = attrs.ChoiceAttr('mode', label=_('Mode')) + name = attrs.TextAttr('__str__', label=_('Display Name')) + process_id = attrs.NumericAttr('process_id', label=_('Process ID')) + router_id = attrs.TextAttr('router_id', label=_('Router ID')) + description = attrs.TextAttr('description', label=_('Description')) + + +class EIGRPAddressFamilyPanel(panels.ObjectAttributesPanel): + scope = attrs.RelatedObjectAttr('router', linkify=True) + address_family = attrs.ChoiceAttr('address_family', label=_('Address Family')) + description = attrs.TextAttr('description', label=_('Description')) + + +class EIGRPNetworkPanel(panels.ObjectAttributesPanel): + router = attrs.RelatedObjectAttr('router', linkify=True) + address_family = attrs.RelatedObjectAttr('address_family', linkify=True) + network = attrs.RelatedObjectAttr('network', linkify=True) + description = attrs.TextAttr('description', label=_('Description')) + + +class EIGRPInterfacePanel(panels.ObjectAttributesPanel): + device = attrs.RelatedObjectAttr('device', label=_('Device')) + router = attrs.RelatedObjectAttr('router', linkify=True) + address_family = attrs.RelatedObjectAttr('address_family', linkify=True) + interface = attrs.RelatedObjectAttr('interface', label=_('Interface')) + description = attrs.TextAttr('description', label=_('Description')) + + +class EIGRPInterfaceSettingsPanel(panels.ObjectAttributesPanel): + passive_interface = attrs.BooleanAttr( + 'passive_interface', label=_('Passive Interface') + ) + bfd = attrs.BooleanAttr('bfd', label=_('BFD')) + authentication = attrs.ChoiceAttr('authentication', label=_('Authentication')) + passphrase = attrs.TextAttr('passphrase', label=_('Passphrase')) diff --git a/netbox_routing/ui/panels/objects.py b/netbox_routing/ui/panels/objects.py new file mode 100644 index 0000000..653f7af --- /dev/null +++ b/netbox_routing/ui/panels/objects.py @@ -0,0 +1,83 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + +__all__ = ( + 'CustomPrefixPanel', + 'ASPathPanel', + 'ASPathEntryPanel', + 'PrefixListPanel', + 'PrefixListEntryPanel', + 'RouteMapPanel', + 'RouteMapEntryPanel', + 'RouteMapEntryMatchPanel', + 'RouteMapEntrySetPanel', +) + + +class CustomPrefixPanel(panels.ObjectAttributesPanel): + prefix = attrs.TextAttr('prefix', label=_('Prefix')) + description = attrs.TextAttr('description', label=_('Description')) + + +class ASPathPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + description = attrs.TextAttr('description', label=_('Description')) + + +class ASPathEntryPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + sequence = attrs.NumericAttr('sequence', label=_('Sequence')) + action = attrs.ChoiceAttr('action', label=_('Action')) + pattern = attrs.TextAttr('pattern', label=_('Pattern')) + description = attrs.TextAttr('description', label=_('Description')) + + +class PrefixListPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + family = attrs.ChoiceAttr('family', label=_('Family')) + description = attrs.TextAttr('description', label=_('Description')) + + +class PrefixListEntryPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + sequence = attrs.NumericAttr('sequence', label=_('Sequence')) + action = attrs.ChoiceAttr('action', label=_('Action')) + assigned_prefix = attrs.RelatedObjectAttr( + 'assigned_prefix', linkify=True, label=_('Prefix') + ) + le = attrs.NumericAttr('le', label=_('Less Then')) + ge = attrs.NumericAttr('ge', label=_('Greater Then')) + description = attrs.TextAttr('description', label=_('Description')) + + +class RouteMapPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + description = attrs.TextAttr('description', label=_('Description')) + + +class RouteMapEntryPanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + sequence = attrs.NumericAttr('sequence', label=_('Sequence')) + action = attrs.ChoiceAttr('action', label=_('Action')) + flow_control = attrs.NumericAttr('flow_control', label=_('Flow Control')) + description = attrs.TextAttr('description', label=_('Description')) + + +class RouteMapEntryMatchPanel(panels.ObjectAttributesPanel): + match_prefix_list = attrs.RelatedObjectListAttr( + 'match_prefix_list', linkify=True, label=_('Prefix List') + ) + match_aspath = attrs.RelatedObjectListAttr( + 'match_as_path_list', linkify=True, label=_('AS Path List') + ) + match_community_list = attrs.RelatedObjectListAttr( + 'match_community_list', linkify=True, label=_('Community List') + ) + match_community = attrs.RelatedObjectListAttr( + 'match_community', linkify=True, label=_('Community') + ) + + +class RouteMapEntrySetPanel(panels.ObjectAttributesPanel): + pass diff --git a/netbox_routing/ui/panels/ospf.py b/netbox_routing/ui/panels/ospf.py new file mode 100644 index 0000000..f2351d5 --- /dev/null +++ b/netbox_routing/ui/panels/ospf.py @@ -0,0 +1,41 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + + +__all__ = ( + 'OSPFInstancePanel', + 'OSPFAreaPanel', + 'OSPFInterfacePanel', + 'OSPFInterfaceSettingsPanel', +) + + +class OSPFInstancePanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Name')) + process_id = attrs.NumericAttr('process_id', label=_('Process ID')) + router_id = attrs.TextAttr('router_id', label=_('Router ID')) + device = attrs.RelatedObjectAttr('device', label=_('Device')) + vrf = attrs.RelatedObjectAttr('vrf', linkify=True) + description = attrs.TextAttr('description', label=_('Description')) + + +class OSPFAreaPanel(panels.ObjectAttributesPanel): + area_id = attrs.NumericAttr('area_id', label=_('Area ID')) + area_type = attrs.ChoiceAttr('area_type', label=_('Area Type')) + description = attrs.TextAttr('description', label=_('Description')) + + +class OSPFInterfacePanel(panels.ObjectAttributesPanel): + area = attrs.RelatedObjectAttr('area', label=_('Area')) + device = attrs.RelatedObjectAttr('instance.device', label=_('Device')) + instance = attrs.RelatedObjectAttr('instance', label=_('Instance')) + interface = attrs.RelatedObjectAttr('interface', label=_('Interface')) + + +class OSPFInterfaceSettingsPanel(panels.ObjectAttributesPanel): + priority = attrs.NumericAttr('priority', label=_('Priority')) + passive = attrs.BooleanAttr('passive', label=_('Passive')) + bfd = attrs.BooleanAttr('bfd', label=_('BFD')) + authentication = attrs.ChoiceAttr('authentication', label=_('Authentication')) + passphrase = attrs.TextAttr('passphrase', label=_('Passphrase')) diff --git a/netbox_routing/ui/panels/static.py b/netbox_routing/ui/panels/static.py new file mode 100644 index 0000000..40a3414 --- /dev/null +++ b/netbox_routing/ui/panels/static.py @@ -0,0 +1,26 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + +__all__ = ( + 'StaticRoutePanel', + 'StaticRouteRoutePanel', +) + + +class StaticRoutePanel(panels.ObjectAttributesPanel): + display = attrs.TextAttr('__str__', label=_('Display Name')) + description = attrs.TextAttr('description', label=_('Description')) + + +class StaticRouteRoutePanel(panels.ObjectAttributesPanel): + name = attrs.TextAttr('name', label=_('Route Name')) + vrf = attrs.RelatedObjectAttr('vrf', linkify=True, label=_('VRF')) + prefix = attrs.TextAttr('prefix', label=_('Prefix')) + next_hop = attrs.TextAttr('next_hop', label=_('Next Hop')) + interface_next_hop = attrs.TextAttr( + 'interface_next_hop', label=_('Interface Next Hop') + ) + metric = attrs.TextAttr('metric', label=_('Metric')) + tag = attrs.TextAttr('tag', label=_('Route Tag')) + permanent = attrs.BooleanAttr('permanent', label=_('Permanent')) diff --git a/netbox_routing/views/bgp.py b/netbox_routing/views/bgp.py index 41768f5..dd1413b 100644 --- a/netbox_routing/views/bgp.py +++ b/netbox_routing/views/bgp.py @@ -1,3 +1,6 @@ +from django.utils.translation import gettext_lazy as _ + +from extras.ui.panels import TagsPanel from netbox.object_actions import CloneObject, EditObject, DeleteObject from netbox.views.generic import ( ObjectView, @@ -8,6 +11,9 @@ BulkEditView, BulkDeleteView, ) +from netbox.ui import panels, layout +from netbox_routing.choices import BGPSettingChoices +from netbox_routing.ui import * from utilities.views import register_model_view, ViewTab @@ -85,6 +91,17 @@ class BGPSettingListView(ObjectListView): @register_model_view(BGPSetting) class BGPSettingView(ObjectView): queryset = BGPSetting.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPSettingPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPSetting, name='add', detail=False) @@ -128,6 +145,18 @@ class BGPPeerTemplateListView(ObjectListView): @register_model_view(BGPPeerTemplate) class BGPPeerTemplateView(ObjectView): queryset = BGPPeerTemplate.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPPeerTemplatePanel(), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPPeerTemplate, name='add', detail=False) @@ -168,6 +197,19 @@ class BGPPolicyTemplateListView(ObjectListView): @register_model_view(BGPPolicyTemplate) class BGPPolicyTemplateView(ObjectView): queryset = BGPPolicyTemplate.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPPolicyTemplatePanel(), + BGPPolicyFilteringPanel(title=_('Filtering')), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPPolicyTemplate, name='add', detail=False) @@ -208,6 +250,19 @@ class BGPSessionTemplateListView(ObjectListView): @register_model_view(BGPSessionTemplate) class BGPSessionTemplateView(ObjectView): queryset = BGPSessionTemplate.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPSessionTemplatePanel(), + BGPPeerSettingPanel(title=_('Peer Parameters')), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPSessionTemplate, name='add', detail=False) @@ -251,7 +306,19 @@ class BGPRouterListView(ObjectListView): @register_model_view(BGPRouter) class BGPRouterView(ObjectView): queryset = BGPRouter.objects.all() - template_name = 'netbox_routing/bgprouter.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPRouterPanel(), + BGPRouterTemplatesPanel(title=_('Templates')), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPRouter, name='add', detail=False) @@ -360,7 +427,18 @@ class BGPScopeListView(ObjectListView): @register_model_view(BGPScope) class BGPScopeView(ObjectView): queryset = BGPScope.objects.all() - template_name = 'netbox_routing/bgpscope.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPScopePanel(), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPScope, name='add', detail=False) @@ -404,7 +482,18 @@ class BGPAddressFamilyListView(ObjectListView): @register_model_view(BGPAddressFamily) class BGPAddressFamilyView(ObjectView): queryset = BGPAddressFamily.objects.all() - template_name = 'netbox_routing/bgpaddressfamily.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPAddressFamilyPanel(), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPAddressFamily, name='add', detail=False) @@ -462,6 +551,19 @@ class BGPPeerListView(ObjectListView): @register_model_view(BGPPeer) class BGPPeerView(ObjectView): queryset = BGPPeer.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPPeerPanel(), + BGPPeerSettingPanel(title=_('Peer Parameters')), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPPeer, name='add', detail=False) @@ -538,6 +640,19 @@ class BGPPeerAddressFamilyListView(ObjectListView): @register_model_view(BGPPeerAddressFamily) class BGPPeerAddressFamilyView(ObjectView): queryset = BGPPeerAddressFamily.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BGPPeerAddressFamilyPanel(), + BGPPolicyFilteringPanel(title=_('Filtering')), + TagsPanel(), + ], + right_panels=[ + SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BGPPeerAddressFamily, name='add', detail=False) @@ -595,6 +710,18 @@ class BFDProfileListView(ObjectListView): @register_model_view(BFDProfile) class BFDProfileView(ObjectView): queryset = BFDProfile.objects.all() + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + BFDProfilePanel(), + BFDProfileSessionPanel(title=_('Session Parameters')), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(BFDProfile, name='add', detail=False) diff --git a/netbox_routing/views/community.py b/netbox_routing/views/community.py index 06f9d9e..5568da1 100644 --- a/netbox_routing/views/community.py +++ b/netbox_routing/views/community.py @@ -1,3 +1,4 @@ +from extras.ui.panels import TagsPanel from netbox.views.generic import ( ObjectListView, ObjectView, @@ -8,12 +9,14 @@ BulkDeleteView, BulkImportView, ) +from netbox.ui import panels, layout from utilities.views import register_model_view, ViewTab from netbox_routing.filtersets.community import * from netbox_routing.forms.community import * from netbox_routing.models.community import * from netbox_routing.tables.community import * +from netbox_routing.ui import * __all__ = ( 'CommunityListListView', @@ -55,7 +58,17 @@ class CommunityListListView(ObjectListView): @register_model_view(CommunityList) class CommunityListDetailView(ObjectView): queryset = CommunityList.objects.all() - template_name = 'netbox_routing/communitylist.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + CommunityListPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(CommunityList, name='add', detail=False) @@ -126,7 +139,17 @@ class CommunityListView(ObjectListView): @register_model_view(Community) class CommunityDetailView(ObjectView): queryset = Community.objects.all() - template_name = 'netbox_routing/community.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + CommunityPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(Community, name='add', detail=False) @@ -178,7 +201,17 @@ class CommunityListEntryListView(ObjectListView): @register_model_view(CommunityListEntry) class CommunityListEntryDetailView(ObjectView): queryset = CommunityListEntry.objects.all() - template_name = 'netbox_routing/communitylistentry.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + CommunityListEntryPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(CommunityListEntry, name='add', detail=False) diff --git a/netbox_routing/views/eigrp.py b/netbox_routing/views/eigrp.py index 1d6427a..dbaaa42 100644 --- a/netbox_routing/views/eigrp.py +++ b/netbox_routing/views/eigrp.py @@ -1,3 +1,6 @@ +from django.utils.translation import gettext_lazy as _ + +from extras.ui.panels import TagsPanel from netbox.views.generic import ( ObjectListView, ObjectEditView, @@ -8,12 +11,16 @@ BulkEditView, BulkDeleteView, ) -from netbox_routing.filtersets.eigrp import * -from netbox_routing.forms import * -from netbox_routing.tables.eigrp import * +from netbox.ui import panels, layout +from netbox_routing.ui.panels.eigrp import EIGRPInterfaceSettingsPanel + from utilities.views import register_model_view, ViewTab +from netbox_routing.filtersets.eigrp import * +from netbox_routing.forms import * from netbox_routing.models import * +from netbox_routing.tables.eigrp import * +from netbox_routing.ui import * __all__ = ( 'EIGRPRouterListView', @@ -65,7 +72,17 @@ class EIGRPRouterListView(ObjectListView): @register_model_view(EIGRPRouter) class EIGRPRouterView(ObjectView): queryset = EIGRPRouter.objects.all() - template_name = 'netbox_routing/eigrprouter.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + EIGRPRouterPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(EIGRPRouter, name='address_families') @@ -165,7 +182,17 @@ class EIGRPAddressFamilyListView(ObjectListView): @register_model_view(EIGRPAddressFamily) class EIGRPAddressFamilyView(ObjectView): queryset = EIGRPAddressFamily.objects.all() - template_name = 'netbox_routing/eigrpaddressfamily.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + EIGRPAddressFamilyPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(EIGRPAddressFamily, name='interfaces') @@ -244,7 +271,17 @@ class EIGRPNetworkListView(ObjectListView): @register_model_view(EIGRPNetwork) class EIGRPNetworkView(ObjectView): queryset = EIGRPNetwork.objects.all() - template_name = 'netbox_routing/eigrpnetwork.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + EIGRPNetworkPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(EIGRPNetwork, name='add', detail=False) @@ -294,7 +331,18 @@ class EIGRPInterfaceListView(ObjectListView): @register_model_view(EIGRPInterface) class EIGRPInterfaceView(ObjectView): queryset = EIGRPInterface.objects.all() - template_name = 'netbox_routing/eigrpinterface.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + EIGRPInterfacePanel(), + EIGRPInterfaceSettingsPanel(title=_('Interface Settings')), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(EIGRPInterface, name='add', detail=False) diff --git a/netbox_routing/views/objects.py b/netbox_routing/views/objects.py index ca06e6d..a5c19c1 100644 --- a/netbox_routing/views/objects.py +++ b/netbox_routing/views/objects.py @@ -1,3 +1,6 @@ +from django.utils.translation import gettext_lazy as _ + +from extras.ui.panels import TagsPanel from netbox import object_actions from netbox.views.generic import ( ObjectListView, @@ -8,12 +11,14 @@ BulkDeleteView, BulkEditView, ) -from netbox_routing.models import Community, CommunityList +from netbox.ui import panels, layout from utilities.views import register_model_view, ViewTab, GetRelatedModelsMixin from netbox_routing.filtersets.objects import * from netbox_routing.forms.objects import * +from netbox_routing.models import Community, CommunityList from netbox_routing.models.objects import * from netbox_routing.tables.objects import * +from netbox_routing.ui import * # @@ -30,12 +35,21 @@ class PrefixListListView(ObjectListView): @register_model_view(PrefixList) class PrefixListView(ObjectView): queryset = PrefixList.objects.all() - template_name = 'netbox_routing/prefixlist.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + PrefixListPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(PrefixList, name='entries') class PrefixListEntriesView(ObjectChildrenView): - template_name = 'netbox_routing/objectchildrentable.html' queryset = PrefixList.objects.all() child_model = PrefixListEntry table = PrefixListEntryTable @@ -105,7 +119,17 @@ class PrefixListEntryListView(ObjectListView): @register_model_view(PrefixListEntry) class PrefixListEntryView(ObjectView): queryset = PrefixListEntry.objects.all() - template_name = 'netbox_routing/prefixlistentry.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + PrefixListEntryPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(PrefixListEntry, name='add', detail=False) @@ -152,7 +176,17 @@ class CustomPrefixListView(ObjectListView): @register_model_view(CustomPrefix) class CustomPrefixView(ObjectView): queryset = CustomPrefix.objects.all() - template_name = 'netbox_routing/customprefix.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + CustomPrefixPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(CustomPrefix, name='add', detail=False) @@ -181,12 +215,21 @@ class RouteMapListView(ObjectListView): @register_model_view(RouteMap) class RouteMapView(ObjectView): queryset = RouteMap.objects.all() - template_name = 'netbox_routing/routemap.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + RouteMapPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(RouteMap, name='entries') class RouteMapEntriesView(ObjectChildrenView): - template_name = 'netbox_routing/objectchildrentable.html' queryset = RouteMap.objects.all() child_model = RouteMapEntry table = RouteMapEntryTable @@ -254,7 +297,21 @@ class RouteMapEntryListView(ObjectListView): @register_model_view(RouteMapEntry) class RouteMapEntryView(GetRelatedModelsMixin, ObjectView): queryset = RouteMapEntry.objects.all() - template_name = 'netbox_routing/routemapentry.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + RouteMapEntryPanel(title=_('Route Map Entry')), + RouteMapEntryMatchPanel(title=_('Match Actions')), + panels.JSONPanel('match', title=_('Match Parameters'), copy_button=True), + RouteMapEntrySetPanel(title=_('Set Actions')), + panels.JSONPanel('set', title=_('Set Parameters'), copy_button=True), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) def get_extra_context(self, request, instance): @@ -334,7 +391,17 @@ class ASPathListView(ObjectListView): @register_model_view(ASPath) class ASPathView(ObjectView): queryset = ASPath.objects.all() - template_name = 'netbox_routing/aspath.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + ASPathPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(ASPath, name='add', detail=False) @@ -366,7 +433,6 @@ class ASPathBulkDeleteView(BulkDeleteView): @register_model_view(ASPath, name='entries') class ASPathEntriesView(ObjectChildrenView): - template_name = 'netbox_routing/objectchildrentable.html' queryset = ASPath.objects.all() child_model = ASPathEntry table = ASPathEntryTable @@ -408,7 +474,17 @@ class ASPathEntryListView(ObjectListView): @register_model_view(ASPathEntry) class ASPathEntryView(ObjectView): queryset = ASPathEntry.objects.all() - template_name = 'netbox_routing/aspathentry.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + ASPathEntryPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(ASPathEntry, name='add', detail=False) diff --git a/netbox_routing/views/ospf.py b/netbox_routing/views/ospf.py index 0b226bb..d8efa8f 100644 --- a/netbox_routing/views/ospf.py +++ b/netbox_routing/views/ospf.py @@ -1,3 +1,6 @@ +from django.utils.translation import gettext_lazy as _ + +from extras.ui.panels import TagsPanel from netbox.views.generic import ( ObjectListView, ObjectEditView, @@ -8,20 +11,22 @@ BulkEditView, BulkDeleteView, ) +from netbox.ui import panels, layout +from utilities.views import register_model_view, ViewTab + from netbox_routing.filtersets.ospf import ( OSPFInterfaceFilterSet, OSPFAreaFilterSet, OSPFInstanceFilterSet, ) from netbox_routing.forms import * +from netbox_routing.models import OSPFArea, OSPFInstance, OSPFInterface from netbox_routing.tables.ospf import ( OSPFAreaTable, OSPFInstanceTable, OSPFInterfaceTable, ) -from utilities.views import register_model_view, ViewTab - -from netbox_routing.models import OSPFArea, OSPFInstance, OSPFInterface +from netbox_routing.ui import * __all__ = ( 'OSPFInstanceListView', @@ -61,12 +66,21 @@ class OSPFInstanceListView(ObjectListView): @register_model_view(OSPFInstance) class OSPFInstanceView(ObjectView): queryset = OSPFInstance.objects.all() - template_name = 'netbox_routing/ospfinstance.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + OSPFInstancePanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(OSPFInstance, name='interfaces') class OSPFInstanceInterfacesView(ObjectChildrenView): - template_name = 'netbox_routing/ospf_interfaces.html' queryset = OSPFInstance.objects.all() child_model = OSPFInterface table = OSPFInterfaceTable @@ -138,12 +152,21 @@ class OSPFAreaListView(ObjectListView): @register_model_view(OSPFArea) class OSPFAreaView(ObjectView): queryset = OSPFArea.objects.all() - template_name = 'netbox_routing/ospfarea.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + OSPFAreaPanel(), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(OSPFArea, name='interfaces') class OSPFAreaInterfacesView(ObjectChildrenView): - template_name = 'netbox_routing/ospf_interfaces.html' queryset = OSPFArea.objects.all() child_model = OSPFInterface table = OSPFInterfaceTable @@ -209,7 +232,18 @@ class OSPFInterfaceListView(ObjectListView): @register_model_view(OSPFInterface) class OSPFInterfaceView(ObjectView): queryset = OSPFInterface.objects.all() - template_name = 'netbox_routing/ospfinterface.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + OSPFInterfacePanel(), + OSPFInterfaceSettingsPanel(title=_('Interface Settings')), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(OSPFInterface, name='add', detail=False) diff --git a/netbox_routing/views/static.py b/netbox_routing/views/static.py index cadb208..5f5fe4c 100644 --- a/netbox_routing/views/static.py +++ b/netbox_routing/views/static.py @@ -1,6 +1,9 @@ +from django.utils.translation import gettext_lazy as _ + from dcim.filtersets import DeviceFilterSet from dcim.models import Device from dcim.tables import DeviceTable +from extras.ui.panels import TagsPanel from netbox.views.generic import ( ObjectListView, ObjectEditView, @@ -11,6 +14,7 @@ BulkEditView, BulkImportView, ) +from netbox.ui import panels, layout from utilities.views import register_model_view, ViewTab from netbox_routing.filtersets.static import StaticRouteFilterSet @@ -20,6 +24,7 @@ from netbox_routing.forms.bulk_import import StaticRouteImportForm from netbox_routing.models import StaticRoute from netbox_routing.tables.static import StaticRouteTable +from netbox_routing.ui import * __all__ = ( 'StaticRouteListView', @@ -44,12 +49,22 @@ class StaticRouteListView(ObjectListView): @register_model_view(StaticRoute) class StaticRouteView(ObjectView): queryset = StaticRoute.objects.all() - template_name = 'netbox_routing/staticroute.html' + template_name = 'generic/object.html' + layout = layout.SimpleLayout( + left_panels=[ + StaticRoutePanel(), + StaticRouteRoutePanel(title=_('Route Parameters')), + TagsPanel(), + ], + right_panels=[ + panels.CommentsPanel(), + panels.RelatedObjectsPanel(), + ], + ) @register_model_view(StaticRoute, name='devices') class StaticRouteDevicesView(ObjectChildrenView): - template_name = 'netbox_routing/staticroute_devices.html' queryset = StaticRoute.objects.all() child_model = Device table = DeviceTable From 5f632bbcada3bd07fcd6170b9b40993cbfa6ecfe Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Thu, 21 May 2026 01:00:18 -0500 Subject: [PATCH 2/3] Fix Black Failures --- netbox_routing/ui/panels/__init__.py | 1 - netbox_routing/ui/panels/ospf.py | 1 - 2 files changed, 2 deletions(-) diff --git a/netbox_routing/ui/panels/__init__.py b/netbox_routing/ui/panels/__init__.py index fca0815..d39f2da 100644 --- a/netbox_routing/ui/panels/__init__.py +++ b/netbox_routing/ui/panels/__init__.py @@ -6,7 +6,6 @@ from .objects import * from .ospf import * - __all__ = ( 'SettingsChoicePanel', 'BGPSettingPanel', diff --git a/netbox_routing/ui/panels/ospf.py b/netbox_routing/ui/panels/ospf.py index f2351d5..3e63f55 100644 --- a/netbox_routing/ui/panels/ospf.py +++ b/netbox_routing/ui/panels/ospf.py @@ -2,7 +2,6 @@ from netbox.ui import attrs, panels - __all__ = ( 'OSPFInstancePanel', 'OSPFAreaPanel', From c030a233f7907bbee8282c019c8b411a2945a438 Mon Sep 17 00:00:00 2001 From: Daniel Sheppard Date: Thu, 21 May 2026 07:51:56 -0500 Subject: [PATCH 3/3] Fix invalid reference to settings on template views --- netbox_routing/ui/panels/core.py | 3 +++ netbox_routing/views/bgp.py | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox_routing/ui/panels/core.py b/netbox_routing/ui/panels/core.py index b984eeb..faff26e 100644 --- a/netbox_routing/ui/panels/core.py +++ b/netbox_routing/ui/panels/core.py @@ -29,6 +29,9 @@ def __init__(self, choices, accessor='settings', **kwargs): def get_context(self, context): ctx = super().get_context(context) + if not hasattr(ctx['object'], self._accessor): + return {**ctx, 'attrs': []} + settings = { setting.key: setting for setting in getattr(ctx['object'], self._accessor).all() diff --git a/netbox_routing/views/bgp.py b/netbox_routing/views/bgp.py index dd1413b..78a8c9c 100644 --- a/netbox_routing/views/bgp.py +++ b/netbox_routing/views/bgp.py @@ -152,7 +152,6 @@ class BGPPeerTemplateView(ObjectView): TagsPanel(), ], right_panels=[ - SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), panels.CommentsPanel(), panels.RelatedObjectsPanel(), ], @@ -205,7 +204,6 @@ class BGPPolicyTemplateView(ObjectView): TagsPanel(), ], right_panels=[ - SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), panels.CommentsPanel(), panels.RelatedObjectsPanel(), ], @@ -258,7 +256,6 @@ class BGPSessionTemplateView(ObjectView): TagsPanel(), ], right_panels=[ - SettingsChoicePanel(title=_('Settings'), choices=BGPSettingChoices), panels.CommentsPanel(), panels.RelatedObjectsPanel(), ],