Coverage for netbox/navigation/__init__.py: 88%
50 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 collections.abc import Sequence
2from dataclasses import dataclass
4from django.urls import reverse_lazy
6__all__ = (
7 'Menu',
8 'MenuGroup',
9 'MenuItem',
10 'MenuItemButton',
11 'get_model_buttons',
12 'get_model_item',
13)
16#
17# Navigation menu data classes
18#
20@dataclass
21class MenuItemButton:
23 link: str
24 title: str
25 icon_class: str
26 _url: str | None = None
27 permissions: Sequence[str] | None = ()
28 color: str | None = None
30 def __post_init__(self):
31 if self.link: 31 ↛ exitline 31 didn't return from function '__post_init__' because the condition on line 31 was always true
32 self._url = reverse_lazy(self.link)
34 @property
35 def url(self):
36 return self._url
38 @url.setter
39 def url(self, value):
40 self._url = value
43@dataclass
44class MenuItem:
46 link: str
47 link_text: str
48 _url: str | None = None
49 permissions: Sequence[str] | None = ()
50 auth_required: bool | None = False
51 staff_only: bool | None = False
52 buttons: Sequence[MenuItemButton] | None = ()
54 def __post_init__(self):
55 if self.link: 55 ↛ exitline 55 didn't return from function '__post_init__' because the condition on line 55 was always true
56 self._url = reverse_lazy(self.link)
58 @property
59 def url(self):
60 return self._url
62 @url.setter
63 def url(self, value):
64 self._url = value
67@dataclass
68class MenuGroup:
70 label: str
71 items: Sequence[MenuItem]
74@dataclass
75class Menu:
77 label: str
78 icon_class: str
79 groups: Sequence[MenuGroup]
81 @property
82 def name(self):
83 return self.label.replace(' ', '_')
86#
87# Utility functions
88#
90def get_model_item(app_label, model_name, label, actions=('add', 'bulk_import')):
91 return MenuItem(
92 link=f'{app_label}:{model_name}_list',
93 link_text=label,
94 permissions=[f'{app_label}.view_{model_name}'],
95 buttons=get_model_buttons(app_label, model_name, actions)
96 )
99def get_model_buttons(app_label, model_name, actions=('add', 'bulk_import')):
100 buttons = []
102 if 'add' in actions:
103 buttons.append(
104 MenuItemButton(
105 link=f'{app_label}:{model_name}_add',
106 title='Add',
107 icon_class='mdi mdi-plus-thick',
108 permissions=[f'{app_label}.add_{model_name}']
109 )
110 )
111 if 'bulk_import' in actions:
112 buttons.append(
113 MenuItemButton(
114 link=f'{app_label}:{model_name}_bulk_import',
115 title='Import',
116 icon_class='mdi mdi-upload',
117 permissions=[f'{app_label}.add_{model_name}']
118 )
119 )
121 return buttons