diff --git a/docs/plugins/development/views.md b/docs/plugins/development/views.md index 3c13a6fcbf..f6624f42c1 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 d27bb67cad..fbece12e56 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 85229dbafd..ccd549160c 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 b63338f2f0..764faa60e1 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 9ce20e204c..c85f257fac 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 d53591cb4a..940f74346b 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 @@