Menu & Navigation Configuration

Developer guide for the Enezaframework. Part of the Developer documentation.

Table of Contents

  1. Overview
  2. App Config Attributes
  3. The menus Structure
  4. Menu Item Reference
  5. Icons with load_icon
  6. Complete Example
  7. Change History
  8. Related Guides

Overview

An app declares its presence in the ERP navigation through a menus list on its AppConfig in apps.py. Two context processors read those lists and render the navigation: sidebar_menu exposes all_app_menus / current_app_menu, and module_menu builds the top-level module list from each app's menu_verbose_name, app_entry_menu, app_icon, and menu_position.

flowchart TD
    APPCFG[AppConfig.menus]
    APPCFG --> FT1[fasttab: ap_masterdata]
    APPCFG --> FT2[fasttab: ap_setup]
    FT1 --> MI1[menuitem: Vendors]
    FT2 --> MI2[menuitem: Vendor Posting Groups]
    FT2 --> MI3[menuitem: Vendor Groups]
    FT2 --> MI4[menuitem: Vendor Price Groups]
    FT2 --> MI5[menuitem: Vendor Branches]

Menus are declared in apps.py on the AppConfig class. There is no app.py file involved.


App Config Attributes

Beyond menus, an AppConfig can carry top-level menu metadata:

Attribute Type Description
name str The Django app name, for example accountpayable.
menu_verbose_name str Human-readable app name shown in the top-level navigation.
app_entry_menu str Default landing URL name, for example myapp:myapp_dashboard. The module menu prefers the dashboard entry for the app label.
app_icon str Icon key for the app entry.
menu_position int Ordering hint for the app within the top-level menu (defaults to 99).
menus list The fast tabs and their menu items.

module_menu only includes apps that define all three of menu_verbose_name, app_icon, and app_entry_menu, then sorts them by menu_position.

Always call super().ready() if you override ready() and import app signals there.

Dashboard-first menu entries

A CLI-generated app starts with menus = [] and an app_entry_menu placeholder. The app still appears in the module menu because it defines menu_verbose_name, app_icon and app_entry_menu.

The module menu resolves the real entry URL to the dashboard app:

text
/dashboards/<app_label>/

If the module has no dashboard definition yet, Enezadashboard renders its empty state. This is the intended first screen for a fresh app; no sample dashboard view or sample menu items are generated.

Add fast tabs and menu items only after real views exist. If a project removes enezadashboard from ENEZA_APPS, set app_entry_menu to a real URL or omit the menu attributes.


The menus Structure

menus is a Python list of fast-tab dictionaries.

python
from django.apps import AppConfig

from enezaframework.utils import load_icon

name = "accountpayable"


class AccountpayableConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "accountpayable"
    menu_verbose_name = "Accounts Payable"
    app_entry_menu = "accountpayable:vendortable_list"
    app_icon = "users_icon"
    menu_position = 30

    def ready(self):
        import accountpayable.signals  # noqa: F401

    menus = [
        {
            "fasttab": "ap_masterdata",
            "name": "AP Master Data",
            "icon": load_icon("users_icon"),
            "menuitems": [
                {
                    "url": f"{name}:vendortable_list",
                    "name": "Vendors",
                    "icon": load_icon("vendor_icon"),
                },
            ],
        },
        {
            "fasttab": "ap_setup",
            "name": "AP Setup",
            "icon": load_icon("settings_icon"),
            "menuitems": [
                {
                    "url": f"{name}:vendorpostinggroup_list",
                    "name": "Vendor Posting Groups",
                    "icon": load_icon("posting_group_icon"),
                },
                {
                    "url": f"{name}:vendorgroup_list",
                    "name": "Vendor Groups",
                    "icon": load_icon("group_icon"),
                },
            ],
        },
    ]

f"{name}:vendortable_list" builds accountpayable:vendortable_list. The url value is a Django URL name (app_name:url_name), not a filesystem path. See URL Auto-Registration for how those names are generated.


Fast tab (top-level dictionary)

Key Type Required Description
fasttab str Yes Unique key identifying the group of related menu items.
name str Yes Display name of the fast tab.
icon str Yes Icon for the fast tab, via load_icon(...).
menuitems list Yes The individual links shown under the fast tab.
Key Type Required Description
url str Yes Django URL name in app_name:url_name form.
name str Yes Display name of the link.
icon str Yes Icon for the link, via load_icon(...).

For framework-generated CRUD views, the URL name is derived from the model or url_name, using the suffixes documented in URL Auto-Registration — commonly _list, _detail, _create, and _delete.


Icons with load_icon

load_icon reads an SVG and returns it marked safe for inline rendering.

python
from enezaframework.utils import load_icon

icon = load_icon("settings_icon")          # 24x24 default
big = load_icon("settings_icon", 32, 32)   # custom size

Signature: load_icon(name, width=24, height=24).

The function resolves finders.find(f"icons/{name}.svg"), so icons live in a static icons/ folder (for example static/icons/), not static/assets/icons/. If the icon cannot be found, load_icon returns a fallback placeholder SVG — verify the SVG exists and that the static files app is configured.


Complete Example

python
from django.apps import AppConfig
from enezaframework.utils import load_icon


class CrmConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "crm"

    menus = [
        {
            "fasttab": "common_setup",
            "name": "Common Setup",
            "icon": load_icon("settings_icon"),
            "menuitems": [
                {
                    "url": "crm:country_list",
                    "name": "Countries",
                    "icon": load_icon("flag_icon"),
                },
                {
                    "url": "crm:custtable_list",
                    "name": "Customers",
                    "icon": load_icon("handshake"),
                },
            ],
        },
    ]

The user is solely responsible for testing and validating navigation; the developer/agent does not run the application.


Change History

Dated changes that affect this guide, taken from docs/Release note/CHANGELOG.md and the release notes. For the complete history, see the changelog.

Date Version What changed
2026-08-23 0.2.19 Sidebar menu state persistence: the active fasttab per app is stored in localStorage, and the section containing the active page auto-opens on first visit.
2026-10-31 0.2.22 CLI-scaffolded apps keep app_entry_menu for the module menu but start with menus = []; the dashboard entry renders its empty state until a dashboard is designed.

The menus list structure and the app-level metadata attributes have no other dated changes in the 0.2.7–0.2.19 window.