diff --git a/netbox/netbox/plugins/navigation.py b/netbox/netbox/plugins/navigation.py index fc86b134a..48b2558b0 100644 --- a/netbox/netbox/plugins/navigation.py +++ b/netbox/netbox/plugins/navigation.py @@ -38,9 +38,12 @@ class PluginMenuItem: permissions = [] buttons = [] - def __init__(self, link, link_text, auth_required=False, staff_only=False, permissions=None, buttons=None): + def __init__( + self, link, link_text, url=None, auth_required=False, staff_only=False, permissions=None, buttons=None + ): self.link = link self.link_text = link_text + self.url = url self.auth_required = auth_required self.staff_only = staff_only if permissions is not None: @@ -61,10 +64,11 @@ class PluginMenuButton: color = ButtonColorChoices.DEFAULT permissions = [] - def __init__(self, link, title, icon_class, color=None, permissions=None): + def __init__(self, link, title, icon_class, url=None, color=None, permissions=None): self.link = link self.title = title self.icon_class = icon_class + self.url = url if permissions is not None: if type(permissions) not in (list, tuple): raise TypeError(_("Permissions must be passed as a tuple or list.")) diff --git a/netbox/netbox/plugins/registration.py b/netbox/netbox/plugins/registration.py index 515405f1b..10cbc7f24 100644 --- a/netbox/netbox/plugins/registration.py +++ b/netbox/netbox/plugins/registration.py @@ -53,8 +53,11 @@ def register_template_extensions(class_list): def register_menu(menu): - if not isinstance(menu, PluginMenu): - raise TypeError(_("{item} must be an instance of netbox.plugins.PluginMenuItem").format(item=menu)) + if not (isinstance(menu, PluginMenu) or callable(menu)): + raise TypeError(_( + "{item} must be an instance of netbox.plugins.PluginMenu " + "or a callable returning such an instance").format(item=menu) + ) registry['plugins']['menus'].append(menu) @@ -64,15 +67,17 @@ def register_menu_items(section_name, class_list): """ # Validation for menu_link in class_list: - if not isinstance(menu_link, PluginMenuItem): - raise TypeError(_("{menu_link} must be an instance of netbox.plugins.PluginMenuItem").format( - menu_link=menu_link - )) + if not (isinstance(menu_link, PluginMenuItem) or callable(menu_link)): + raise TypeError(_( + "{menu_link} must be an instance of netbox.plugins.PluginMenuItem " + "or a callable returning such an instance").format(menu_link=menu_link) + ) for button in menu_link.buttons: - if not isinstance(button, PluginMenuButton): - raise TypeError(_("{button} must be an instance of netbox.plugins.PluginMenuButton").format( - button=button - )) + if not (isinstance(button, PluginMenuButton) or callable(button)): + raise TypeError(_( + "{button} must be an instance of netbox.plugins.PluginMenuButton " + "or a callable returning such an instance").format(button=button) + ) registry['plugins']['menu_items'][section_name] = class_list diff --git a/netbox/utilities/templates/navigation/menu.html b/netbox/utilities/templates/navigation/menu.html index 3983915df..a7c921ec5 100644 --- a/netbox/utilities/templates/navigation/menu.html +++ b/netbox/utilities/templates/navigation/menu.html @@ -41,11 +41,11 @@ {% for item, buttons in items %}