Navigation
Genie renders the application’s left navigation from a single *.navbar.xml model. You describe the
tree once; the engine stores it, filters it per user, computes its badges, and ships the React UI a
ready-to-render JSON tree. The server never trusts the client to decide what a user may see.
The tree
Section titled “The tree”A *.navbar.xml file is a tree of four node kinds:
<Navbar> <Item Name="Home" Label="Home" Icon="fa fa-house" Route="/" />
<Module Name="catalog" Label="Catalog" Icon="fa fa-box-open" Route="/table/products"> <Section Label="Master Data"> <Item Name="products" Label="Products" Icon="fa fa-box" Route="/table/products" /> <Item Name="categories" Label="Categories" Route="/table/categories" /> </Section> <Divider /> <Section Label="Reports"> <Item Name="low-stock-report" Label="Low Stock" Route="/table/low-stock-report"> <CountsBadge Color="danger">SELECT COUNT(*) FROM [Inventory].[vw_LowStock]</CountsBadge> </Item> </Section> </Module>
<Module Name="admin" Label="Admin" Icon="fa fa-gear" VisibleIf="User.IsInRole('Admin')"> … </Module> <Module Name="docs" Label="Docs" Icon="fa fa-book" Route="https://github.com" Target="_blank" /></Navbar>| Kind | Role |
|---|---|
<Module> |
a top-level rail entry; may itself be a link and hold children |
<Section> |
a non-clickable grouping heading; hidden when it has no visible children |
<Item> |
a navigable link (Route); may nest child <Item>s |
<Divider> |
a decorative separator |
Routes are client-side hashes/paths that map to the UI’s GenieRouter — /table/{slug},
/view/{slug}, /form/{slug}, /wizard/{slug}, or /. An external link uses an absolute URL plus
Target="_blank".
Stored as one JSON document
Section titled “Stored as one JSON document”At model migration the whole tree is synced into a single NavbarDefinition row (DefinitionJson)
named default. The sync is a full replace — the XML is the source of truth, so removing a node
from the file removes it from the navbar on the next migration. Keep one *.navbar.xml per app.
Permission filtering (server-side)
Section titled “Permission filtering (server-side)”GET /api/v1/genie/navbar returns only what the authenticated user is allowed to see. NavbarService
loads the stored tree, then NavbarFilter prunes it against the user’s permissions:
- A leaf link is visible when the user holds List or Execute on the resource its route
targets (the resource name is extracted from the
/table|form|view|wizard/{name}route). Closed by default — an unknown resource is hidden. - A container (
Module, or anItemwith children) is visible only if it has at least one visible descendant. - A
Sectionis visible only with at least one visible child. - Dividers are kept, then leading, trailing and consecutive dividers are pruned so no dangling separators remain.
- A super-admin sees everything.
VisibleIf on a node is a server-evaluated role/expression guard (e.g.
User.IsInRole('Admin')) applied on top of the permission rules.
SQL badges
Section titled “SQL badges”An <Item> may carry one badge whose value is computed server-side from a scalar SELECT:
<CountsBadge>— a numeric count (e.g. pending records).<BulletsBadge>— an indicator dot driven by a count.
<Item Name="purchase-orders" Label="Purchase Orders" Route="/table/purchase-orders"> <BulletsBadge Color="info"> SELECT COUNT(*) FROM [Inventory].[PurchaseOrders] WHERE Status = 'Submitted' AND IsDeleted = 0 </BulletsBadge></Item>NavbarService runs each visible link’s badge query with the current session parameters
(@SessionUserId, @SessionCompanyId, …) and ships only the computed number and colour — the SQL
never leaves the server. A badge query that fails is logged and dropped; it never breaks the navbar.
| Method | Route | Returns |
|---|---|---|
GET |
/api/v1/genie/navbar |
SuccessDataResult<List<NavbarItem>> — the filtered, badged tree |
Each NavbarItem carries Name, Kind, Label, Icon, Route, Target, Order, Children, and
an optional Badge ({ Kind, Value, Color }). The UI’s GenieNavbar renders it directly.
An item’s Name is also the key a view’s <ParentView> maps to for its breadcrumb root. Worked
example: sample/Inventory/models/navbar/inventory.navbar.xml.