From bb6efa5418505037a69c5a8575ee41faec9bebdb Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 4 Jun 2024 14:24:57 -0400 Subject: [PATCH] Closes #16359: Add navbar() method to PluginTemplateExtension --- docs/plugins/development/views.md | 3 +++ netbox/netbox/plugins/registration.py | 10 +--------- netbox/netbox/plugins/templates.py | 10 +++++++++- netbox/netbox/tests/dummy_plugin/template_content.py | 8 +++++++- netbox/netbox/tests/test_plugins.py | 3 ++- netbox/templates/base/layout.html | 7 ++++++- netbox/utilities/templatetags/plugins.py | 10 +++++++++- 7 files changed, 37 insertions(+), 14 deletions(-) diff --git a/docs/plugins/development/views.md b/docs/plugins/development/views.md index 3c13a6fcbf8..f6624f42c13 100644 --- a/docs/plugins/development/views.md +++ b/docs/plugins/development/views.md @@ -195,12 +195,15 @@ Plugins can inject custom content into certain areas of core NetBox views. This | Method | View | Description | |---------------------|-------------|-----------------------------------------------------| +| `navbar()` | All | Inject content inside the top navigation bar | | `left_page()` | Object view | Inject content on the left side of the page | | `right_page()` | Object view | Inject content on the right side of the page | | `full_width_page()` | Object view | Inject content across the entire bottom of the page | | `buttons()` | Object view | Add buttons to the top of the page | | `list_buttons()` | List view | Add buttons to the top of the page | +!!! info "The `navbar()` method was introduced in NetBox v4.1." + Additionally, a `render()` method is available for convenience. This method accepts the name of a template to render, and any additional context data you want to pass. Its use is optional, however. When a PluginTemplateExtension is instantiated, context data is assigned to `self.context`. Available data include: diff --git a/netbox/netbox/plugins/registration.py b/netbox/netbox/plugins/registration.py index d27bb67cadc..fbece12e56c 100644 --- a/netbox/netbox/plugins/registration.py +++ b/netbox/netbox/plugins/registration.py @@ -32,21 +32,13 @@ def register_template_extensions(class_list): template_extension=template_extension ) ) - if template_extension.model is None: - raise TypeError( - _("PluginTemplateExtension class {template_extension} does not define a valid model!").format( - template_extension=template_extension - ) - ) registry['plugins']['template_extensions'][template_extension.model].append(template_extension) def register_menu(menu): if not isinstance(menu, PluginMenu): - raise TypeError(_("{item} must be an instance of netbox.plugins.PluginMenuItem").format( - item=menu_link - )) + raise TypeError(_("{item} must be an instance of netbox.plugins.PluginMenuItem").format(item=menu)) registry['plugins']['menus'].append(menu) diff --git a/netbox/netbox/plugins/templates.py b/netbox/netbox/plugins/templates.py index 85229dbafdf..ccd549160c1 100644 --- a/netbox/netbox/plugins/templates.py +++ b/netbox/netbox/plugins/templates.py @@ -14,7 +14,8 @@ class PluginTemplateExtension: The `model` attribute on the class defines the which model detail page this class renders content for. It should be set as a string in the form '.'. render() provides the following context data: - * object - The object being viewed + * object - The object being viewed (object views only) + * model - The type of object being viewed (list views only) * request - The current request * settings - Global NetBox settings * config - Plugin-specific configuration parameters @@ -36,6 +37,13 @@ def render(self, template_name, extra_context=None): return get_template(template_name).render({**self.context, **extra_context}) + def navbar(self): + """ + Content that will be rendered inside the top navigation menu. Content should be returned as an HTML + string. Note that content does not need to be marked as safe because this is automatically handled. + """ + raise NotImplementedError + def left_page(self): """ Content that will be rendered on the left of the detail page view. Content should be returned as an diff --git a/netbox/netbox/tests/dummy_plugin/template_content.py b/netbox/netbox/tests/dummy_plugin/template_content.py index b63338f2f0d..764faa60e1c 100644 --- a/netbox/netbox/tests/dummy_plugin/template_content.py +++ b/netbox/netbox/tests/dummy_plugin/template_content.py @@ -1,6 +1,12 @@ from netbox.plugins.templates import PluginTemplateExtension +class GlobalContent(PluginTemplateExtension): + + def navbar(self): + return "GLOBAL CONTENT - NAVBAR" + + class SiteContent(PluginTemplateExtension): model = 'dcim.site' @@ -20,4 +26,4 @@ def list_buttons(self): return "SITE CONTENT - LIST BUTTONS" -template_extensions = [SiteContent] +template_extensions = [GlobalContent, SiteContent] diff --git a/netbox/netbox/tests/test_plugins.py b/netbox/netbox/tests/test_plugins.py index 9ce20e204c5..c85f257facd 100644 --- a/netbox/netbox/tests/test_plugins.py +++ b/netbox/netbox/tests/test_plugins.py @@ -99,8 +99,9 @@ def test_template_extensions(self): """ Check that plugin TemplateExtensions are registered. """ - from netbox.tests.dummy_plugin.template_content import SiteContent + from netbox.tests.dummy_plugin.template_content import GlobalContent, SiteContent + self.assertIn(GlobalContent, registry['plugins']['template_extensions'][None]) self.assertIn(SiteContent, registry['plugins']['template_extensions']['dcim.site']) def test_registered_columns(self): diff --git a/netbox/templates/base/layout.html b/netbox/templates/base/layout.html index d53591cb4a8..940f74346b8 100644 --- a/netbox/templates/base/layout.html +++ b/netbox/templates/base/layout.html @@ -2,6 +2,7 @@ {% extends 'base/base.html' %} {% load helpers %} {% load navigation %} +{% load plugins %} {% load static %} {% load i18n %} @@ -51,8 +52,12 @@