The Admin Shell module is the Vue admin of the Virto Commerce platform, built on vc-shell. It runs at /apps/admin-shell/ next to the AngularJS admin (VirtoCommerce.AdminAngularJs) and gradually replaces it; it can also own the site root, with or without the AngularJS admin (see Site root). Modules bring their own UI as Admin Shell plugins (Module Federation remotes) that load at runtime. AngularJS screens and platform apps that have no Vue UI yet keep working inside the shell. The menu is composed on the server per user, from the modules' defaults and the organisation's, roles' and users' changes.
Home: the section rail, the panel with Pinned and Recent, and the dashboard.
An order open beside the Orders list, with its widgets (payments, shipments, addresses) in the toolbar.
The Admin Shell Menu Editor: sections and items to reorder, rename and hide, saved as the global menu patch.
The sign-in page, with the installation's brand and a showcase of the platform.
- Module plugins: modules ship their UI in
plugins/admin-shell/. The platform lists installed plugins in the app manifest and the shell loads them at runtime, with their screens, menu items, search providers and widgets. - Seamless migration:
- menu items open Vue screens, AngularJS screens (the classic admin in a persistent embedded frame), platform apps (embedded) or external links;
- a default menu item opens its module's Vue screen once the module's Admin Shell plugin is installed, and its AngularJS screen until then, keeping its place, group, pins and user settings.
- Server-driven, layered menu: the default menu (
default-menu.json, installed apps, plugin contributions) → a global patch → role patches → each user's pins and hidden items. The result is filtered by permission, and a section or item stays visible when any role keeps it. - Admin Shell Menu Editor (Configuration › Monitoring & Tools): drag sections and items (mouse, touch or keyboard) to reorder them or move them to another section or group, rename (per language), hide, add sections and links, saved as the global patch; Edit as JSON to view, download, upload and edit the changes for backup and restore; choose what users may personalize (pin, hide, reorder: turning one off stops applying users' changes without deleting them); find the AngularJS admin's screens and add the ones the menu doesn't have.
- Nothing missing from the menu: a workspace blade that no menu entry opens is listed in More, as is a contribution to a section the menu doesn't have.
- Translated menu: section, group and item titles in 15 languages from the menu's own locale files (
App/src/locales/menu), plugin keys and the platform's server texts; renames by language from the editor. - Menu counters: menu items show what waits (new orders, returns requested, reviews to moderate). Each module registers its counter from its plugin, and the shell polls them every minute while the tab is visible.
- Recent and Pinned:
- the panel lists the pages a user opens most (frequency with a 7-day half-life);
- users can pin and hide items.
- Global search: the header box (Ctrl+K / ⌘K; a full-screen sheet on phones) searches every registered provider at once, grouped by provider.
alias: textscopes a search;- slow groups don't hold back the others;
- a group that fails or takes over 8 seconds shows Search failed with Retry.
- Platform screens in Vue: Settings, Security, Modules, Dynamic properties, Developer tools, License and the user profile ship with the host.
- Dashboard:
- the host's and the modules' widgets on a draggable, resizable grid;
- the layout is saved per browser;
- Reset layout restores the defaults.
- Desktop and phone:
- a section rail and panel on desktop;
- a top bar and drawer on phones;
- light, dark and system themes.
- Extension points for modules:
- menu contributions;
- search providers;
- menu counters;
- dashboard widgets;
- widgets on other modules' and the platform's blades;
- the sign-in page.
The module declares its app as an admin UI that can own the site root: <adminUI priority="50" /> on the admin-shell app in module.manifest (platform 3.1093.0+; older platforms ignore it and serve the shell only at /apps/admin-shell/). Which admin UI the platform serves at / follows the platform's VirtoCommerce:PlatformUI:RootApp:
| Installed | RootApp |
/ |
Admin Shell | AngularJS screens in the shell |
|---|---|---|---|---|
| Admin Shell only | empty | Admin Shell | / and /apps/admin-shell/ |
Not available; their menu items say that the AngularJS admin isn't installed, Open classic admin is hidden |
| Admin Shell + VirtoCommerce.AdminAngularJs | empty | AngularJS admin (priority 100) | /apps/admin-shell/ |
Embedded from / (as before) |
| Admin Shell + VirtoCommerce.AdminAngularJs | admin-shell |
Admin Shell | / and /apps/admin-shell/ |
Embedded from /apps/platform/ |
{ "VirtoCommerce": { "PlatformUI": { "RootApp": "admin-shell" } } }or VirtoCommerce__PlatformUI__RootApp=admin-shell.
- At
/the platform serves the shell's ownindex.html(the address stays/); the build's files keep their/apps/admin-shell/...URLs, and routing is by the URL hash, so nothing else changes. - The shell finds the AngularJS admin in
GET /api/platform/common/ui/context(adminUIs, app idplatform) once per page; on platforms without that list it embeds/as before, and a failed request is asked again next time. - The platform's password-reset email links to the AngularJS admin's reset page; when the shell is the only admin UI, the shell takes that link (
#!/resetpassword/{userId}/{token}) and opens its own reset page.
See the platform's Admin UI.
| Setting | Type | Default | Description |
|---|---|---|---|
AdminShell.Menu.Global |
Json | {} |
Global menu patch for everyone: add, rename, move, reorder or hide sections and items |
AdminShell.Menu.AllowPin |
Boolean | true |
Users may pin menu items; off, their pins stop showing until it's on again |
AdminShell.Menu.AllowHide |
Boolean | true |
Users may hide menu items; off, the items they hid show again until it's on again |
AdminShell.Menu.AllowReorder |
Boolean | true |
Users' own order of menu items applies |
AdminShell.Menu.Role |
Json (per role) | {} |
A role's menu patch; an item is hidden only if every role of the user hides it |
AdminShell.Menu.User |
Json (per user, hidden) | {} |
The user's pinned and hidden items, set from the shell (and an item order, API only) |
AdminShell.Menu.Recent |
Json (per user, hidden) | [] |
Usage scores behind Recent, recorded by the shell |
AdminShell.UI.Appearance |
ShortText (per user) | dark |
Light, dark or the system's appearance; set in the user menu or the profile, and follows the user to every browser |
AdminShell.UI.Theme |
ShortText (per user) | virto |
The color theme: Virto, Warm, Blue or Indigo; set like the appearance |
A setting that isn't valid JSON is ignored, so one typo can't take the menu down. See Menu layers.
| Permission | Description |
|---|---|
admin-shell:menu:manage |
Read and change the global and role menu layers through the API |
Who may open the Admin Shell is the platform's admin UI access policy, VirtoCommerce:PlatformUI:Access in the platform's appsettings (administrators, required permissions, account types, allowed and denied permission masks; VirtoCommerce/vc-platform#3092), the same rules as the AngularJS admin. A user it denies sees an Access denied page with a button to sign in with another account.
The module hosts the Admin Shell app and composes its menu; the platform serves the app and the plugin manifest, and each module serves its own plugin:
┌──────────────────────────────────────────────────────────────────────┐
│ Host app (Vue 3, vc-shell) — Content/admin-shell → /apps/admin-shell │
│ layout · menu · global search · dashboard · platform screens │
├──────────────────┬──────────────────────┬─────────────────────────────┤
│ Module plugins │ AngularJS admin │ Platform apps │
│ (MF remotes) │ (embedded frame) │ (embedded frames) │
├──────────────────┴──────────────────────┴─────────────────────────────┤
│ Web Layer (menu API, default menu builder, module initialization) │
├───────────────────────────────────────────────────────────────────────┤
│ Core Layer (menu model, menu composer, settings, permissions) │
├───────────────────────────────────────────────────────────────────────┤
│ Platform (app hosting, plugin manifest, settings, security) │
└───────────────────────────────────────────────────────────────────────┘
- The browser opens
/apps/admin-shell/, or/when the shell owns the site root. The platform serves the host app;index.htmlisn't cached (at either address), so a new build is picked up at once. - The host loads the current user, installs vc-shell, the platform screens and the global search registry, and mounts.
- In parallel it reads the plugin manifest (
GET /api/apps/admin-shell/manifest, platform). It installs each module's plugin as soon as it loads; a failing plugin is skipped. - The shell loads the user's menu (
GET /api/admin-shell/menu). - A deep link opened directly is applied once the plugins have registered their routes.
DefaultMenuBuilderbuilds the default menu on every request:Content/default-menu.json, without items of modules that aren't installed;- installed apps with
MainMenuplacement; contributions.menufrom each module'splugins/admin-shell/plugin.json.
MenuComposerapplies replacements: an item takes the place of the item itreplaces, and old ids (replaced ones and an item'saliases) are mapped to new ones.- The global patch and the role patches are applied; hiding is a union over the user's roles.
- The user's preferences are applied; items and sections without permission are removed.
- The result is sorted, grouped, and returned with Pinned and Recent.
| Project | Layer | Purpose |
|---|---|---|
VirtoCommerce.AdminShell.Core |
Core | Menu model, menu composer (pure, unit-tested), module constants, settings and permissions |
VirtoCommerce.AdminShell.Web |
Web | Menu API, default menu builder, settings storage, module initialization, Content/default-menu.json |
VirtoCommerce.AdminShell.Web/App |
Client | The host app: layout, menu, global search, dashboard, platform screens; built into Content/admin-shell |
VirtoCommerce.AdminShell.Tests |
Tests | Menu composition tests |
| Service | Responsibility |
|---|---|
MenuComposer |
Composes the effective menu from the default menu, patches, user preferences and permissions; ranks Recent |
DefaultMenuBuilder |
Builds the default menu from default-menu.json, installed apps and plugin contributions |
AdminMenuService |
Reads and writes the menu layers in platform settings (JSON, per platform, role and user) and resolves the user's effective menu |
AppIndexNoCacheStartupFilter |
Serves the host's index.html with Cache-Control: no-cache, also when the platform serves it at / |
| Extension point | API | Guide |
|---|---|---|
| Plugins | Module Federation remote in {module}/plugins/admin-shell/ |
plugins.md |
| Menu contributions | contributions.menu in plugin.json |
menu-contributions.md |
| Global search | app.config.globalProperties.$globalSearch |
global-search.md |
| Menu counters | app.config.globalProperties.$menuCounters |
menu-counters.md |
| Dashboard widgets | registerDashboardWidget |
dashboard-widgets.md |
| Blade widgets | registerExternalWidget |
blade-widgets.md |
| AngularJS screens | legacy menu targets, $globalSearch.openLegacy |
legacy-screens.md |
| Embedded apps | <app> with MainMenu placement |
embedded-apps.md |
| Sign-in page | useExtensionPoint("auth:after-form") |
sign-in-page.md |
Base route: api/admin-shell/menu
| Method | Endpoint | Description |
|---|---|---|
GET |
/ |
Get the current user's effective menu (sections, pinned, recent, hidden) |
GET |
/me/prefs |
Get the current user's menu preferences |
PUT |
/me/prefs |
Save the current user's menu preferences |
POST |
/me/recent/{itemId} |
Record a use of a menu item for Recent |
GET |
/default |
Get the default menu before any patch (admin-shell:menu:manage) |
GET |
/global |
Get the global menu patch (admin-shell:menu:manage) |
PUT |
/global |
Save the global menu patch (admin-shell:menu:manage) |
GET |
/roles/{roleId} |
Get a role's menu patch (admin-shell:menu:manage) |
PUT |
/roles/{roleId} |
Save a role's menu patch (admin-shell:menu:manage) |
- Server:
dotnet build. - Host app: in
src/VirtoCommerce.AdminShell.Web/App, runyarn installandyarn build:app, then copydistto../Content/admin-shell; vc-build'sBuildCustomAppdoes this in CI. Unit tests of the host app's scripts:yarn test(Node's test runner, no browser). - The host applies one fix to
@vc-shell/framework2.7.0 through a Yarn patch inApp/.yarn/patches: the phone back button is one named button, not a button inside a button.
Copyright (c) Virto Solutions LTD. All rights reserved.
This software is licensed under the Virto Commerce Open Software License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://virtocommerce.com/opensourcelicense.
Unless required by the applicable law or agreed to in written form, the software distributed under the License is provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.



