FleetbaseFleetbase

Menu Service

Register navigation entries in the console — header items, settings panels, admin panels, organization & user menus, and custom registries — via universe.getService('menu').

Menu Service

The menu service is how your extension contributes navigation entries to the console. It exposes dedicated registrars for each major menu surface, plus a generic registrar for custom registries (auth:login, engine:fleet-ops, etc.).

// addon/extension.js
import { MenuItem, ExtensionComponent } from '@fleetbase/ember-core/contracts';

export default {
    setupExtension(app, universe) {
        const menuService = universe.getService('menu');
        // … registrations
    },
};

Registry Names

The service maintains a small set of well-known registries, addressed by colon-separated names:

RegistryHoldsRegistrar
headerHeader navigation bar items (top of console)registerHeaderMenuItem
console:accountOrganization & user dropdowns (slugs prefixed organization: or user:)registerOrganizationMenuItem, registerUserMenuItem
console:adminAdmin section — items (menu-item) and panels (menu-panel)registerAdminMenuItem, registerAdminMenuPanel
console:settingsSettings page itemsregisterSettingsMenuItem
auth:loginLogin screen extras (extra buttons, public unauth pages)registerMenuItem('auth:login', …)
engine:<name>Per-engine settings drawer (engine:fleet-ops, etc.)registerMenuItem('engine:<name>', …)
Custom (my-ext:tabs, etc.)Anything you define via registry.createRegistries(...)registerMenuItem('my-ext:tabs', …)

registerHeaderMenuItem(itemOrTitle, route?, options?)

The most-used registrar — adds an entry to the top header of the console.

menuService.registerHeaderMenuItem('Storefront', 'console.storefront', {
    icon: 'store',
    priority: 1,
    description: 'Online store management.',
    shortcuts: [
        { title: 'Products', icon: 'box-open',     route: 'console.storefront.products' },
        { title: 'Orders',   icon: 'bag-shopping', route: 'console.storefront.orders' },
        { title: 'Customers', icon: 'users',       route: 'console.storefront.customers' },
    ],
});

The shortcuts array isn't decorative — each shortcut is automatically registered as a first-class header item (with the parent's title as _parentTitle for grouping in the customizer's overflow dropdown). This means a single header registration can surface multiple discoverable entries.

You can also pass a MenuItem:

import { MenuItem } from '@fleetbase/ember-core/contracts';

menuService.registerHeaderMenuItem(
    new MenuItem({
        title: 'Storefront',
        route: 'console.storefront',
        icon: 'store',
        priority: 1,
    })
);

registerSettingsMenuItem(itemOrTitle, options?)

Adds an entry to the Settings page.

menuService.registerSettingsMenuItem(
    new MenuItem({
        title: 'My Extension',
        slug: 'my-extension',
        icon: 'gear',
        component: new ExtensionComponent('@my-org/my-engine', 'settings-panel'),
    })
);

When the MenuItem has a component, it renders inside the settings page when the user clicks the entry. If you also want a route transition, set route: 'console.settings.virtual' and use slug to identify the view.

registerAdminMenuItem(itemOrTitle, route?, options?) / registerAdminMenuPanel(panelOrTitle, items?, options?)

The admin section supports both flat items and grouped panels.

menuService.registerAdminMenuPanel(
    'Fleet-Ops Config',
    [
        new MenuItem({
            title: 'Routing',
            icon: 'route',
            component: new ExtensionComponent('@fleetbase/fleetops-engine', 'admin/routing-settings'),
        }),
        new MenuItem({
            title: 'Map',
            icon: 'map',
            component: new ExtensionComponent('@fleetbase/fleetops-engine', 'admin/map-settings'),
        }),
    ],
    { slug: 'fleet-ops' }
);

A panel is stored at console:admin → menu-panel → <slug>; its child items also fan out to console:admin → menu-item → <itemSlug> so they're discoverable individually.

registerOrganizationMenuItem(itemOrTitle, options?)

Items in the organization dropdown (top-right). Slug is auto-prefixed with organization:.

menuService.registerOrganizationMenuItem(
    new MenuItem({
        title: 'Ledger Preferences',
        icon: 'calculator',
        slug: 'ledger-preferences',
        view: 'index',
        component: new ExtensionComponent('@fleetbase/ledger-engine', 'ledger-org-settings'),
        onClick: (menuItem) => {
            const router = app.lookup('service:router');
            router?.transitionTo('console.settings.virtual', menuItem.slug);
        },
    })
);

If section isn't provided, it defaults to 'settings'.

registerUserMenuItem(itemOrTitle, options?)

Items in the user dropdown. Slug is auto-prefixed with user:.

menuService.registerUserMenuItem(
    new MenuItem({
        title: 'Help & Tours',
        icon: 'question-circle',
        onClick: () => app.lookup('service:tour')?.showTourLauncher(),
    })
);

If section isn't provided, it defaults to 'account'.

registerMenuItem(registryName, titleOrMenuItem, options?)

The generic registrar for custom registries — your own (my-ext:sidebar) or well-known engine registries (auth:login, engine:fleet-ops, fleet-ops:component:vehicle:details).

// A button on the login screen — links to your engine's own login route
menuService.registerMenuItem(
    'auth:login',
    new MenuItem({
        title: 'Partner Login',
        route: 'partner-portal.login',
        icon: 'person',
        type: 'link',
        wrapperClass: 'btn-block py-1 border dark:border-gray-700 border-gray-200 hover:opacity-50',
    })
);

// A tab on the Fleet-Ops order details panel
menuService.registerMenuItem(
    'fleet-ops:component:order:details',
    new MenuItem({
        title: 'Invoice',
        route: 'operations.orders.index.details.virtual',
        component: new ExtensionComponent('@fleetbase/ledger-engine', 'order-invoice'),
        icon: 'file-invoice-dollar',
        slug: 'invoice',
    })
);

Real example: packages/ledger/addon/extension.js:92 — registers an "Invoice" tab on the Fleet-Ops order details panel.

For component-injecting registries (where the host renders contributed UI rather than navigating to a route), use registry.registerRenderableComponent(...) instead — it's the right tool for component contributions.

Reading Items Back

MethodReturns
getHeaderMenuItems()Array of header items
getOrganizationMenuItems()Items prefixed organization:
getUserMenuItems()Items prefixed user:
getAdminMenuItems()Admin items (excluding panel children)
getAdminMenuPanels() (alias getAdminPanels)Admin panels
getSettingsMenuItems()Settings page items
getSettingsMenuPanels()Settings panels
getMenuItems(registryName)Items in any registry
getMenuPanels(registryName)Panels in any registry
getMenuItemsFromPanel(panelSlug)Items inside a specific panel
lookupMenuItem(registryName, slug, view?, section?) (alias getMenuItem)A specific item

Permission Gating

Pass permission on a MenuItem and the menu UI will hide or disable the item per the user's IAM abilities.

new MenuItem({
    title: 'Delete Driver',
    icon: 'trash',
    permission: 'fleet-ops driver delete',
    onClick: deleteDriver,
});

Real-World References

ExtensionPattern shownSource
Fleet-OpsHeader item with shortcuts + admin panelfleetops/addon/extension.js
StorefrontHeader item with shortcuts + component contributionsstorefront/addon/extension.js
PalletHeader item, component contributionspallet/addon/extension.js
LedgerHeader item, custom dashboard, Fleet-Ops order tabledger/addon/extension.js

See Also

Source

Menu Service | Fleetbase