|
3 | 3 | from typing import TYPE_CHECKING |
4 | 4 |
|
5 | 5 | from fastapi import APIRouter, Depends |
6 | | -from pydantic import BaseModel, Field |
7 | 6 |
|
8 | 7 | from infrahub.api.dependencies import get_branch_dep, get_current_user, get_db |
9 | 8 | from infrahub.core import registry |
10 | 9 | from infrahub.core.branch import Branch # noqa: TCH001 |
11 | | -from infrahub.core.constants import InfrahubKind |
12 | 10 | from infrahub.core.protocols import CoreMenuItem |
13 | | -from infrahub.core.schema import NodeSchema |
14 | 11 | from infrahub.log import get_logger |
15 | 12 | from infrahub.menu.generator import generate_menu |
16 | 13 | from infrahub.menu.models import Menu # noqa: TCH001 |
17 | 14 |
|
18 | 15 | if TYPE_CHECKING: |
19 | 16 | from infrahub.auth import AccountSession |
20 | | - from infrahub.core.schema import MainSchemaTypes |
21 | 17 | from infrahub.database import InfrahubDatabase |
22 | 18 |
|
23 | 19 |
|
24 | 20 | log = get_logger() |
25 | 21 | router = APIRouter(prefix="/menu") |
26 | 22 |
|
27 | 23 |
|
28 | | -class InterfaceMenu(BaseModel): |
29 | | - title: str = Field(..., description="Title of the menu item") |
30 | | - path: str = Field(default="", description="URL endpoint if applicable") |
31 | | - icon: str = Field(default="", description="The icon to show for the current view") |
32 | | - children: list[InterfaceMenu] = Field(default_factory=list, description="Child objects") |
33 | | - kind: str = Field(default="") |
34 | | - |
35 | | - def __lt__(self, other: object) -> bool: |
36 | | - if not isinstance(other, InterfaceMenu): |
37 | | - raise NotImplementedError |
38 | | - return self.title < other.title |
39 | | - |
40 | | - def list_title(self) -> str: |
41 | | - return f"All {self.title}(s)" |
42 | | - |
43 | | - |
44 | | -def add_to_menu(structure: dict[str, list[InterfaceMenu]], menu_item: InterfaceMenu) -> None: |
45 | | - all_items = InterfaceMenu(title=menu_item.list_title(), path=menu_item.path, icon=menu_item.icon) |
46 | | - menu_item.path = "" |
47 | | - menu_item.icon = "" |
48 | | - for child in structure[menu_item.kind]: |
49 | | - menu_item.children.append(child) |
50 | | - if child.kind in structure: |
51 | | - add_to_menu(structure, child) |
52 | | - menu_item.children.sort() |
53 | | - menu_item.children.insert(0, all_items) |
54 | | - |
55 | | - |
56 | | -def _extract_node_icon(model: MainSchemaTypes) -> str: |
57 | | - if not model.icon: |
58 | | - return "" |
59 | | - return model.icon |
60 | | - |
61 | | - |
62 | 24 | @router.get("") |
63 | | -async def get_menu(branch: Branch = Depends(get_branch_dep)) -> list[InterfaceMenu]: |
64 | | - log.info("menu_request", branch=branch.name) |
65 | | - |
66 | | - full_schema = registry.schema.get_full(branch=branch, duplicate=False) |
67 | | - objects = InterfaceMenu(title="Objects", children=[]) |
68 | | - |
69 | | - structure: dict[str, list[InterfaceMenu]] = {} |
70 | | - |
71 | | - ipam = InterfaceMenu( |
72 | | - title="IPAM", |
73 | | - children=[ |
74 | | - InterfaceMenu( |
75 | | - title="Namespaces", |
76 | | - path=f"/objects/{InfrahubKind.IPNAMESPACE}", |
77 | | - icon=_extract_node_icon(full_schema[InfrahubKind.IPNAMESPACE]), |
78 | | - ), |
79 | | - InterfaceMenu( |
80 | | - title="IP Prefixes", path="/ipam/prefixes", icon=_extract_node_icon(full_schema[InfrahubKind.IPPREFIX]) |
81 | | - ), |
82 | | - InterfaceMenu( |
83 | | - title="IP Addresses", |
84 | | - path="/ipam/addresses?ipam-tab=ip-details", |
85 | | - icon=_extract_node_icon(full_schema[InfrahubKind.IPADDRESS]), |
86 | | - ), |
87 | | - ], |
88 | | - ) |
89 | | - |
90 | | - has_ipam = False |
91 | | - |
92 | | - for key in full_schema.keys(): |
93 | | - model = full_schema[key] |
94 | | - |
95 | | - if isinstance(model, NodeSchema) and ( |
96 | | - InfrahubKind.IPADDRESS in model.inherit_from or InfrahubKind.IPPREFIX in model.inherit_from |
97 | | - ): |
98 | | - has_ipam = True |
99 | | - |
100 | | - if not model.include_in_menu: |
101 | | - continue |
102 | | - |
103 | | - menu_name = model.menu_placement or "base" |
104 | | - if menu_name not in structure: |
105 | | - structure[menu_name] = [] |
106 | | - |
107 | | - structure[menu_name].append( |
108 | | - InterfaceMenu(title=model.menu_title, path=f"/objects/{model.kind}", icon=model.icon or "", kind=model.kind) |
109 | | - ) |
110 | | - |
111 | | - for menu_item in structure["base"]: |
112 | | - if menu_item.kind in structure: |
113 | | - add_to_menu(structure, menu_item) |
114 | | - |
115 | | - objects.children.append(menu_item) |
116 | | - |
117 | | - objects.children.sort() |
118 | | - groups = InterfaceMenu( |
119 | | - title="Object Management", |
120 | | - children=[ |
121 | | - InterfaceMenu( |
122 | | - title="All Groups", |
123 | | - path=f"/objects/{InfrahubKind.GENERICGROUP}", |
124 | | - icon=_extract_node_icon(full_schema[InfrahubKind.GENERICGROUP]), |
125 | | - ), |
126 | | - InterfaceMenu( |
127 | | - title="All Profiles", |
128 | | - path=f"/objects/{InfrahubKind.PROFILE}", |
129 | | - icon=_extract_node_icon(full_schema[InfrahubKind.PROFILE]), |
130 | | - ), |
131 | | - InterfaceMenu( |
132 | | - title="Resource Manager", |
133 | | - path="/resource-manager", |
134 | | - icon=_extract_node_icon(full_schema[InfrahubKind.RESOURCEPOOL]), |
135 | | - ), |
136 | | - ], |
137 | | - ) |
138 | | - |
139 | | - unified_storage = InterfaceMenu( |
140 | | - title="Unified Storage", |
141 | | - children=[ |
142 | | - InterfaceMenu(title="Schema", path="/schema", icon="mdi:file-code"), |
143 | | - InterfaceMenu( |
144 | | - title="Repository", |
145 | | - path=f"/objects/{InfrahubKind.GENERICREPOSITORY}", |
146 | | - icon=_extract_node_icon(full_schema[InfrahubKind.GENERICREPOSITORY]), |
147 | | - ), |
148 | | - InterfaceMenu( |
149 | | - title="GraphQL Query", |
150 | | - path=f"/objects/{InfrahubKind.GRAPHQLQUERY}", |
151 | | - icon=_extract_node_icon(full_schema[InfrahubKind.GRAPHQLQUERY]), |
152 | | - ), |
153 | | - ], |
154 | | - ) |
155 | | - change_control = InterfaceMenu( |
156 | | - title="Change Control", |
157 | | - children=[ |
158 | | - InterfaceMenu(title="Branches", path="/branches", icon="mdi:layers-triple"), |
159 | | - InterfaceMenu( |
160 | | - title="Proposed Changes", |
161 | | - path="/proposed-changes", |
162 | | - icon=_extract_node_icon(full_schema[InfrahubKind.PROPOSEDCHANGE]), |
163 | | - ), |
164 | | - InterfaceMenu( |
165 | | - title="Check Definition", |
166 | | - path=f"/objects/{InfrahubKind.CHECKDEFINITION}", |
167 | | - icon=_extract_node_icon(full_schema[InfrahubKind.CHECKDEFINITION]), |
168 | | - ), |
169 | | - InterfaceMenu(title="Tasks", path="/tasks", icon="mdi:shield-check"), |
170 | | - ], |
171 | | - ) |
172 | | - deployment = InterfaceMenu( |
173 | | - title="Deployment", |
174 | | - children=[ |
175 | | - InterfaceMenu( |
176 | | - title="Artifact", |
177 | | - path=f"/objects/{InfrahubKind.ARTIFACT}", |
178 | | - icon=_extract_node_icon(full_schema[InfrahubKind.ARTIFACT]), |
179 | | - ), |
180 | | - InterfaceMenu( |
181 | | - title="Artifact Definition", |
182 | | - path=f"/objects/{InfrahubKind.ARTIFACTDEFINITION}", |
183 | | - icon=_extract_node_icon(full_schema[InfrahubKind.ARTIFACTDEFINITION]), |
184 | | - ), |
185 | | - InterfaceMenu( |
186 | | - title="Generator Definition", |
187 | | - path=f"/objects/{InfrahubKind.GENERATORDEFINITION}", |
188 | | - icon=_extract_node_icon(full_schema[InfrahubKind.GENERATORDEFINITION]), |
189 | | - ), |
190 | | - InterfaceMenu( |
191 | | - title="Generator Instance", |
192 | | - path=f"/objects/{InfrahubKind.GENERATORINSTANCE}", |
193 | | - icon=_extract_node_icon(full_schema[InfrahubKind.GENERATORINSTANCE]), |
194 | | - ), |
195 | | - InterfaceMenu( |
196 | | - title="Transformation", |
197 | | - path=f"/objects/{InfrahubKind.TRANSFORM}", |
198 | | - icon=_extract_node_icon(full_schema[InfrahubKind.TRANSFORM]), |
199 | | - ), |
200 | | - ], |
201 | | - ) |
202 | | - |
203 | | - admin = InterfaceMenu( |
204 | | - title="Admin", |
205 | | - children=[ |
206 | | - InterfaceMenu( |
207 | | - title="Role Management", |
208 | | - path="/role-management", |
209 | | - icon=_extract_node_icon(full_schema[InfrahubKind.BASEPERMISSION]), |
210 | | - ), |
211 | | - InterfaceMenu( |
212 | | - title="Credentials", |
213 | | - path=f"/objects/{InfrahubKind.CREDENTIAL}", |
214 | | - icon=_extract_node_icon(full_schema[InfrahubKind.CREDENTIAL]), |
215 | | - ), |
216 | | - InterfaceMenu( |
217 | | - title="Webhooks", |
218 | | - children=[ |
219 | | - InterfaceMenu( |
220 | | - title="Webhook", |
221 | | - path=f"/objects/{InfrahubKind.STANDARDWEBHOOK}", |
222 | | - icon=_extract_node_icon(full_schema[InfrahubKind.STANDARDWEBHOOK]), |
223 | | - ), |
224 | | - InterfaceMenu( |
225 | | - title="Custom Webhook", |
226 | | - path=f"/objects/{InfrahubKind.CUSTOMWEBHOOK}", |
227 | | - icon=_extract_node_icon(full_schema[InfrahubKind.CUSTOMWEBHOOK]), |
228 | | - ), |
229 | | - ], |
230 | | - ), |
231 | | - ], |
232 | | - ) |
233 | | - |
234 | | - menu_items = [objects] |
235 | | - if has_ipam: |
236 | | - menu_items.append(ipam) |
237 | | - menu_items.extend([groups, unified_storage, change_control, deployment, admin]) |
238 | | - |
239 | | - return menu_items |
240 | | - |
241 | | - |
242 | | -@router.get("/new") |
243 | | -async def get_new_menu( |
| 25 | +async def get_menu( |
244 | 26 | db: InfrahubDatabase = Depends(get_db), |
245 | 27 | branch: Branch = Depends(get_branch_dep), |
246 | 28 | account_session: AccountSession = Depends(get_current_user), |
247 | 29 | ) -> Menu: |
248 | | - log.info("new_menu_request", branch=branch.name) |
| 30 | + log.info("menu_request", branch=branch.name) |
249 | 31 |
|
250 | | - menu_items = await registry.manager.query(db=db, schema=CoreMenuItem, branch=branch, prefetch_relationships=True) |
| 32 | + menu_items = await registry.manager.query( |
| 33 | + db=db, schema=CoreMenuItem, branch=branch |
| 34 | + ) # , prefetch_relationships=True) |
251 | 35 | menu = await generate_menu(db=db, branch=branch, account=account_session, menu_items=menu_items) |
252 | 36 |
|
253 | 37 | return menu.to_rest() |
0 commit comments