Skip to content

Add menus

What you're doing

Putting your pages in the ERP's navigation. A menu is a tree of nodes, each pointing at a route. One file under spk-assembly/metadata/menu/.

There is a second, easy-to-miss step: a master menu scaffold file that some deployments keep as the merged sidenav. If your plugin's module belongs to a larger application (e.g. HCM), you update that too — see below.

The complete example

spk-assembly/metadata/menu/office-equipment-menu.jsonreal file:

json
{
  "name": "office-equipment-menu",
  "description": "Navigation contributed by the Office Equipment plugin.",
  "definition": {
    "contractVersion": 1,
    "name": "office-equipment-menu",
    "nodes": [
      {
        "id": "office-equipment.equipment",
        "name": "equipment",
        "displayName": "Office Equipment",
        "sequence": 0,
        "navigation": { "route": null, "openMode": "current-tab" },
        "visibility": { "visible": true, "enabled": true, "devices": [] },
        "color": null,
        "children": [
          {
            "id": "office-equipment.equipment.equipment-register",
            "name": "equipment-register",
            "displayName": "Equipment Register",
            "sequence": 0,
            "children": [],
            "navigation": { "route": "/office-equipment/equipment-register", "openMode": "current-tab" },
            "visibility": { "visible": true, "enabled": true, "devices": [] },
            "color": null
          },
          {
            "id": "office-equipment.equipment.equipment-catalog",
            "name": "equipment-catalog",
            "displayName": "Equipment Catalog",
            "sequence": 1,
            "children": [],
            "navigation": { "route": "/office-equipment/equipment-catalog", "openMode": "current-tab" },
            "visibility": { "visible": true, "enabled": true, "devices": [] },
            "color": null
          },
          {
            "id": "office-equipment.equipment.equipment-checkout",
            "name": "equipment-checkout",
            "displayName": "Equipment Checkout",
            "sequence": 2,
            "children": [],
            "navigation": { "route": "/office-equipment/equipment-checkout", "openMode": "current-tab" },
            "visibility": { "visible": true, "enabled": true, "devices": [] },
            "color": null
          }
        ]
      }
    ]
  },
  "modules": ["office-equipment"]
}

Line by line

  • nodes — the tree. A parent node with navigation.route: null is a group header; its children are the clickable items.
  • id — dotted, unique, conventionally <pluginId>.<group>.<page>.
  • name — a short slug.
  • displayName — the label shown. (For a translated label use displayNameKey with an i18n key instead.)
  • sequence — sort order among siblings.
  • navigation.route — the page's route.pattern, exactly. This is the internal routing key, not the browser URL.
  • visibility.devices[] means all devices; ["mobile"] restricts.
  • modules — the module id(s) this menu contributes to. Match your pages' modules.

Scaffold with the CLI

bash
erp menu create office-equipment office-equipment-menu \
  --display-name "Equipment Register" --route /office-equipment/equipment-register --icon devices

produces a valid one-node menu you then flesh out. (Run it from PowerShell on Windows, or the leading / in --route gets mangled by Git Bash.)

The master-scaffold sync note

Some applications (the HCM suite is the canonical case) keep a single hand-maintained "master menu" file — e.g. hcm-foundation-main-menu.json — that is the merged sidenav shown whether or not a given plugin is installed. If your module attaches to such an application, a new page needs its node added in two places:

  1. your own metadata/menu/<plugin>-menu.json (above), and
  2. the application's master menu scaffold.

Skipping (2) means the item is missing from the merged sidenav for anyone who sees the app but hasn't installed your plugin. A standalone plugin that ships its own metadata/application/*.json (like the tutorial) has no master scaffold to sync — one menu file is enough.

Ground yourself first

bash
erp schema pull menu

How to verify it worked

bash
erp schema validate spk-assembly/metadata/menu/office-equipment-menu.json --schema menu
OK — ... matches schema "menu"

After publishing, open the ERP and confirm the group and its items appear in the sidenav under your application, and each item navigates to the right page.

Common mistakes

SymptomCauseFix
menu item 404snavigation.route doesn't match the page's route.patterncopy it exactly
item appears but page is blankpage's modules array doesn't include this modulealign them
item missing from the merged app sidenavdidn't sync the master menu scaffoldadd the node there too
erp menu create route is a Windows pathGit Bash / manglingrun from PowerShell / MSYS_NO_PATHCONV=1