mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Simplify the mechanism for plugins to register navigation menu items
This commit is contained in:
@ -1,11 +1,16 @@
|
|||||||
import collections
|
import collections
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from django.apps import AppConfig, apps
|
from django.apps import AppConfig
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
|
||||||
from extras.registry import registry
|
from extras.registry import registry
|
||||||
from .signals import register_detail_page_content_classes, register_nav_menu_link_classes
|
from .signals import register_detail_page_content_classes
|
||||||
|
|
||||||
|
|
||||||
|
# Initialize plugin registry stores
|
||||||
|
registry['plugin_nav_menu_links'] = {}
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -41,6 +46,23 @@ class PluginConfig(AppConfig):
|
|||||||
# Caching configuration
|
# Caching configuration
|
||||||
caching_config = {}
|
caching_config = {}
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
|
||||||
|
# Register navigation menu items (if defined)
|
||||||
|
register_menu_items(self.verbose_name, self.get_menu_items())
|
||||||
|
|
||||||
|
def get_menu_items(self):
|
||||||
|
"""
|
||||||
|
Default method to import navigation menu items for a plugin from the default location (menu_items in a
|
||||||
|
file named navigation.py). This method may be overridden by a plugin author to import menu items from
|
||||||
|
a different location if needed.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
menu_items = import_string(f"{self.__module__}.navigation.menu_items")
|
||||||
|
return menu_items
|
||||||
|
except ImportError:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Template content injection
|
# Template content injection
|
||||||
@ -138,7 +160,7 @@ def get_content_classes(model):
|
|||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Nav menu links
|
# Navigation menu links
|
||||||
#
|
#
|
||||||
|
|
||||||
class PluginNavMenuLink:
|
class PluginNavMenuLink:
|
||||||
@ -149,10 +171,14 @@ class PluginNavMenuLink:
|
|||||||
Links are specified as Django reverse URL strings.
|
Links are specified as Django reverse URL strings.
|
||||||
Buttons are each specified as a list of PluginNavMenuButton instances.
|
Buttons are each specified as a list of PluginNavMenuButton instances.
|
||||||
"""
|
"""
|
||||||
link = None
|
def __init__(self, link, link_text, permission=None, buttons=None):
|
||||||
link_text = None
|
self.link = link
|
||||||
link_permission = None
|
self.link_text = link_text
|
||||||
buttons = []
|
self.link_permission = permission
|
||||||
|
if buttons is None:
|
||||||
|
self.buttons = []
|
||||||
|
else:
|
||||||
|
self.buttons = buttons
|
||||||
|
|
||||||
|
|
||||||
class PluginNavMenuButton:
|
class PluginNavMenuButton:
|
||||||
@ -168,42 +194,16 @@ class PluginNavMenuButton:
|
|||||||
self.permission = permission
|
self.permission = permission
|
||||||
|
|
||||||
|
|
||||||
def register_nav_menu_links():
|
def register_menu_items(section_name, class_list):
|
||||||
"""
|
"""
|
||||||
Helper method that populates the registry with all nav menu link classes that have been registered by plugins
|
Register a list of PluginNavMenuLink instances for a given menu section (e.g. plugin name)
|
||||||
"""
|
"""
|
||||||
registry['plugin_nav_menu_link_classes'] = {}
|
# Validation
|
||||||
|
for menu_link in class_list:
|
||||||
responses = register_nav_menu_link_classes.send('registration_event')
|
if not isinstance(menu_link, PluginNavMenuLink):
|
||||||
for receiver, response in responses:
|
raise TypeError(f"{menu_link} must be an instance of extras.plugins.PluginNavMenuLink")
|
||||||
|
for button in menu_link.buttons:
|
||||||
# Derive menu section header from plugin name
|
|
||||||
app_config = apps.get_app_config(receiver.__module__.split('.')[0])
|
|
||||||
section_name = getattr(app_config, 'verbose_name', app_config.name)
|
|
||||||
|
|
||||||
if not isinstance(response, list):
|
|
||||||
response = [response]
|
|
||||||
for link_class in response:
|
|
||||||
if not inspect.isclass(link_class):
|
|
||||||
raise TypeError('Plugin nav menu link class {} was passes as an instance!'.format(link_class))
|
|
||||||
if not issubclass(link_class, PluginNavMenuLink):
|
|
||||||
raise TypeError('{} is not a subclass of extras.plugins.PluginNavMenuLink!'.format(link_class))
|
|
||||||
if link_class.link is None or link_class.link_text is None:
|
|
||||||
raise TypeError('Plugin nav menu link {} must specify at least link and link_text'.format(link_class))
|
|
||||||
|
|
||||||
for button in link_class.buttons:
|
|
||||||
if not isinstance(button, PluginNavMenuButton):
|
if not isinstance(button, PluginNavMenuButton):
|
||||||
raise TypeError('{} must be an instance of PluginNavMenuButton!'.format(button))
|
raise TypeError(f"{button} must be an instance of extras.plugins.PluginNavMenuButton")
|
||||||
|
|
||||||
registry['plugin_nav_menu_link_classes'][section_name] = response
|
registry['plugin_nav_menu_links'][section_name] = class_list
|
||||||
|
|
||||||
|
|
||||||
def get_nav_menu_link_classes():
|
|
||||||
"""
|
|
||||||
Return the list of all registered nav menu link classes.
|
|
||||||
Populate the registry if it is empty.
|
|
||||||
"""
|
|
||||||
if 'plugin_nav_menu_link_classes' not in registry:
|
|
||||||
register_nav_menu_links()
|
|
||||||
|
|
||||||
return registry['plugin_nav_menu_link_classes']
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
from . import get_nav_menu_link_classes
|
from extras.registry import registry
|
||||||
|
|
||||||
|
|
||||||
def nav_menu_links(request):
|
def nav_menu_links(request):
|
||||||
"""
|
"""
|
||||||
Retrieve and expose all plugin registered nav links
|
Retrieve and expose all plugin registered nav links
|
||||||
"""
|
"""
|
||||||
nav_menu_links = get_nav_menu_link_classes()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'plugin_nav_menu_links': nav_menu_links
|
'plugin_nav_menu_links': registry['plugin_nav_menu_links']
|
||||||
}
|
}
|
||||||
|
@ -32,11 +32,3 @@ This signal collects template content classes which render content for object de
|
|||||||
register_detail_page_content_classes = PluginSignal(
|
register_detail_page_content_classes = PluginSignal(
|
||||||
providing_args=[]
|
providing_args=[]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
This signal collects nav menu link classes
|
|
||||||
"""
|
|
||||||
register_nav_menu_link_classes = PluginSignal(
|
|
||||||
providing_args=[]
|
|
||||||
)
|
|
||||||
|
Reference in New Issue
Block a user