Coverage for netbox/plugins/navigation.py: 30%
65 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django.urls import reverse_lazy
2from django.utils.text import slugify
3from django.utils.translation import gettext as _
5from netbox.choices import ButtonColorChoices
6from netbox.navigation import MenuGroup
8__all__ = (
9 'PluginMenu',
10 'PluginMenuButton',
11 'PluginMenuItem',
12)
15class PluginMenu:
16 icon_class = 'mdi mdi-puzzle'
18 def __init__(self, label, groups, icon_class=None):
19 self.label = label
20 self.groups = [
21 MenuGroup(label, items) for label, items in groups
22 ]
23 if icon_class is not None:
24 self.icon_class = icon_class
26 @property
27 def name(self):
28 return slugify(self.label)
31class PluginMenuItem:
32 """
33 This class represents a navigation menu item. This constitutes primary link and its text, but also allows for
34 specifying additional link buttons that appear to the right of the item in the van menu.
36 Links are specified as Django reverse URL strings suitable for rendering via {% url item.link %}.
37 Alternatively, a pre-generated url can be set on the object which will be rendered literally.
38 Buttons are each specified as a list of PluginMenuButton instances.
39 """
40 _url = None
42 def __init__(
43 self, link, link_text, auth_required=False, staff_only=False, permissions=None, buttons=None
44 ):
45 self.link = link
46 self.link_text = link_text
47 self.auth_required = auth_required
48 self.staff_only = staff_only
49 if link:
50 self._url = reverse_lazy(link)
51 if permissions is not None:
52 if type(permissions) not in (list, tuple):
53 raise TypeError(_("Permissions must be passed as a tuple or list."))
54 self.permissions = permissions
55 else:
56 self.permissions = []
57 if buttons is not None:
58 if type(buttons) not in (list, tuple):
59 raise TypeError(_("Buttons must be passed as a tuple or list."))
60 self.buttons = buttons
61 else:
62 self.buttons = []
64 @property
65 def url(self):
66 return self._url
68 @url.setter
69 def url(self, value):
70 self._url = value
73class PluginMenuButton:
74 """
75 This class represents a button within a PluginMenuItem. Note that button colors should come from
76 ButtonColorChoices.
77 """
78 color = ButtonColorChoices.DEFAULT
79 _url = None
81 def __init__(self, link, title, icon_class, color=None, permissions=None):
82 self.link = link
83 self.title = title
84 self.icon_class = icon_class
85 if link:
86 self._url = reverse_lazy(link)
87 if permissions is not None:
88 if type(permissions) not in (list, tuple):
89 raise TypeError(_("Permissions must be passed as a tuple or list."))
90 self.permissions = permissions
91 else:
92 self.permissions = []
93 if color is not None:
94 if color not in ButtonColorChoices.values():
95 raise ValueError(_("Button color must be a choice within ButtonColorChoices."))
96 self.color = color
98 @property
99 def url(self):
100 return self._url
102 @url.setter
103 def url(self, value):
104 self._url = value