Skip to content

PLAN: Medusa Admin Sidebar Sorting

+======================================================================+
| |
| ███████╗██╗██████╗ ███████╗██████╗ █████╗ ██████╗ |
| ██╔════╝██║██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔══██╗ |
| ███████╗██║██║ ██║█████╗ ██████╔╝███████║██████╔╝ |
| ╚════██║██║██║ ██║██╔══╝ ██╔══██╗██╔══██║██╔══██╗ |
| ███████║██║██████╔╝███████╗██████╔╝██║ ██║██║ ██║ |
| ╚══════╝╚═╝╚═════╝ ╚══════╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ |
| |
| S O R T I N G P L A N |
| |
| Magic PIM - Medusa 2.11.3 Admin Dashboard |
| 18 custom routes in de Extensions sidebar |
| |
| Status: WACHT OP AKKOORD |
| Prioriteit: Medium |
| |
+======================================================================+

De Magic PIM admin heeft 18 custom routes die allemaal in de “Extensions” sectie van de Medusa sidebar verschijnen. Er is momenteel geen sortering - de volgorde wordt bepaald door de filesystem discovery van de Vite plugin. Dit plan beschrijft 3 aanpakken om de sidebar logisch te ordenen.


RouteLabelIconCategorie
/aplt-productsAPLT ProductenShoppingBagProducten
/products-by-supplierPer LeverancierShoppingBagProducten
/technique-pricingPrint PrijzenTagProducten
/category-managerCategorieënFolderOpenProducten
/cmsCMSDocumentTextContent
/cms-modulesCMS ModulesPhotoContent
/page-managerPage ManagerDocumentTextContent
/menu-managerMenu ManagerListBulletContent
/translationsVertalingenGlobeEuropeContent
/connectorsConnectorsServerStackIntegraties
/stock-connectorsStock ConnectorsBoltIntegraties
/customersKlantenUsersVerkoop
/quotationsOffertesDocumentTextVerkoop
/license-managerLicense ManagerCreditCardSysteem
/license-calculatorLicentie CalculatorCurrencyDollarSysteem
/security-groupsSecurity GroupsShieldCheckSysteem
/tenant-updateTenant UpdateCloudArrowUpSysteem
/settings/dev-projectsDev ProjectsCogSixToothSettings
Medusa Admin Sidebar
├── Core Routes (vaste volgorde, niet aanpasbaar)
│ ├── Orders
│ ├── Products
│ ├── Inventory
│ ├── Customers
│ ├── Promotions
│ └── Price Lists
├── ─ ─ ─ ─ (dashed divider) ─ ─ ─ ─
└── Extensions (collapsible, onze 18 routes)
├── APLT Producten ← ongesorteerd
├── Per Leverancier
├── CMS
├── ... (filesystem order)
└── Tenant Update

De nested property kan routes nesten onder core routes (Orders, Products, etc.), maar niet onder andere custom routes. Beschikbare nest-posities:

type NestedRoutePosition =
| "/orders"
| "/products"
| "/inventory"
| "/customers"
| "/promotions"
| "/price-lists";

Aanpak 1: Filesystem Prefix Sorting (Eenvoudig)

Section titled “Aanpak 1: Filesystem Prefix Sorting (Eenvoudig)”

Aanpak 1: Prefix Rename

Hernoem de route directories met numerieke prefixes zodat de Vite plugin ze in de gewenste volgorde oppakt. Simpelst, geen code wijzigingen nodig behalve directory namen.

Hoe het werkt: De Medusa admin Vite plugin scant src/admin/routes/ en genereert menu items op basis van file discovery. Door directories te prefixen met nummers, sturen we de volgorde aan.

Nieuwe directory structuur:

src/admin/routes/
├── 01-aplt-products/page.tsx → /01-aplt-products
├── 02-products-by-supplier/page.tsx → /02-products-by-supplier
├── 03-category-manager/page.tsx → /03-category-manager
├── 04-technique-pricing/page.tsx → /04-technique-pricing
├── 05-customers/page.tsx → /05-customers
├── 06-quotations/page.tsx → /06-quotations
├── 07-cms/page.tsx → /07-cms
├── 08-cms-modules/page.tsx → /08-cms-modules
├── 09-page-manager/page.tsx → /09-page-manager
├── 10-menu-manager/page.tsx → /10-menu-manager
├── 11-translations/page.tsx → /11-translations
├── 12-connectors/page.tsx → /12-connectors
├── 13-stock-connectors/page.tsx → /13-stock-connectors
├── 14-license-manager/page.tsx → /14-license-manager
├── 15-license-calculator/page.tsx → /15-license-calculator
├── 16-security-groups/page.tsx → /16-security-groups
├── 17-tenant-update/page.tsx → /17-tenant-update
└── settings/
└── dev-projects/page.tsx → /settings/dev-projects
ProCon
Geen code wijzigingenURL’s veranderen (prefix in path)
Werkt directLelijke URL’s (/01-aplt-products)
Makkelijk te herschikkenGeen visuele groepering
Geen runtime overheadFilesystem sorting is niet gegarandeerd cross-platform

Geschiktheid: Snel resultaat, maar niet ideaal voor productie.


Aanpak 2: Nested Routes onder Core Sections (Medusa Native)

Section titled “Aanpak 2: Nested Routes onder Core Sections (Medusa Native)”

Aanpak 2: Nested Routes

Gebruik de nested property van defineRouteConfig om routes onder bestaande Medusa core secties te plaatsen. Dit is de enige officieel ondersteunde manier om sidebar volgorde te beinvloeden.

Hoe het werkt: Routes met nested: "/products" verschijnen als sub-items onder de Products core route in de sidebar, in plaats van in de Extensions sectie.

Configuratie wijzigingen:

aplt-products/page.tsx
export const config = defineRouteConfig({
label: "APLT Producten",
icon: ShoppingBag,
nested: "/products", // ← nest onder Products
})
// products-by-supplier/page.tsx
export const config = defineRouteConfig({
label: "Per Leverancier",
icon: ShoppingBag,
nested: "/products", // ← nest onder Products
})
// technique-pricing/page.tsx
export const config = defineRouteConfig({
label: "Print Prijzen",
icon: Tag,
nested: "/products", // ← nest onder Products
})
// category-manager/page.tsx
export const config = defineRouteConfig({
label: "Categorieën",
icon: FolderOpen,
nested: "/products", // ← nest onder Products
})
// customers/page.tsx
export const config = defineRouteConfig({
label: "Klanten",
icon: Users,
nested: "/customers", // ← nest onder Customers
})
// quotations/page.tsx
export const config = defineRouteConfig({
label: "Offertes",
icon: DocumentText,
nested: "/customers", // ← nest onder Customers (B2B context)
})

Resultaat sidebar:

Medusa Admin Sidebar
├── Orders
├── Products
│ ├── APLT Producten ← genest
│ ├── Per Leverancier ← genest
│ ├── Print Prijzen ← genest
│ └── Categorieën ← genest
├── Inventory
├── Customers
│ ├── Klanten ← genest
│ └── Offertes ← genest
├── Promotions
├── Price Lists
├── ─ ─ ─ (Extensions) ─ ─ ─
└── Extensions (overige 10 routes)
├── CMS
├── CMS Modules
├── Page Manager
├── Menu Manager
├── Vertalingen
├── Connectors
├── Stock Connectors
├── License Manager
├── Licentie Calculator
├── Security Groups
└── Tenant Update
ProCon
Officieel ondersteund door MedusaSlechts 6 nest-posities beschikbaar
Geen URL wijzigingenContent/Systeem routes kunnen niet genest worden
Logische groeperingExtensions sectie blijft ongesorteerd
Geen custom code nodigBeperkt tot core route categorieën

Geschiktheid: Goed voor product- en klant-gerelateerde routes. Lost het probleem niet volledig op voor CMS/Systeem routes.


Aanpak 3: Custom Sidebar Override via Admin Widget (Volledig Custom)

Section titled “Aanpak 3: Custom Sidebar Override via Admin Widget (Volledig Custom)”

Aanpak 3: Custom Sidebar

Overschrijf de Medusa admin sidebar met een custom React component dat volledige controle geeft over groepering, volgorde en visuele presentatie. Dit is de meest complete oplossing.

Hoe het werkt: Maak een custom sidebar component die de standaard Extensions sectie vervangt met gegroepeerde, gesorteerde navigatie. Dit vereist het patchen van de Medusa dashboard bundle of het injecteren via een admin widget.

Gewenste sidebar layout:

Medusa Admin Sidebar
├── [Searchbar]
├── CORE
│ ├── Orders
│ ├── Products
│ ├── Inventory
│ ├── Customers (Medusa)
│ ├── Promotions
│ └── Price Lists
├── PRODUCTEN
│ ├── APLT Producten
│ ├── Per Leverancier
│ ├── Categorieën
│ └── Print Prijzen
├── VERKOOP
│ ├── Klanten
│ └── Offertes
├── CONTENT
│ ├── CMS
│ ├── CMS Modules
│ ├── Page Manager
│ ├── Menu Manager
│ └── Vertalingen
├── INTEGRATIES
│ ├── Connectors
│ └── Stock Connectors
├── SYSTEEM
│ ├── License Manager
│ ├── Licentie Calculator
│ ├── Security Groups
│ └── Tenant Update
└── SETTINGS
└── Dev Projects

Implementatie:

Stap 1 - Maak een sidebar configuratie bestand:

src/admin/config/sidebar-order.ts
export type SidebarGroup = {
label: string
items: { path: string; label: string; icon: string }[]
}
export const sidebarGroups: SidebarGroup[] = [
{
label: "Producten",
items: [
{ path: "/aplt-products", label: "APLT Producten", icon: "ShoppingBag" },
{ path: "/products-by-supplier", label: "Per Leverancier", icon: "ShoppingBag" },
{ path: "/category-manager", label: "Categorieën", icon: "FolderOpen" },
{ path: "/technique-pricing", label: "Print Prijzen", icon: "Tag" },
],
},
{
label: "Verkoop",
items: [
{ path: "/customers", label: "Klanten", icon: "Users" },
{ path: "/quotations", label: "Offertes", icon: "DocumentText" },
],
},
{
label: "Content",
items: [
{ path: "/cms", label: "CMS", icon: "DocumentText" },
{ path: "/cms-modules", label: "CMS Modules", icon: "Photo" },
{ path: "/page-manager", label: "Page Manager", icon: "DocumentText" },
{ path: "/menu-manager", label: "Menu Manager", icon: "ListBullet" },
{ path: "/translations", label: "Vertalingen", icon: "GlobeEurope" },
],
},
{
label: "Integraties",
items: [
{ path: "/connectors", label: "Connectors", icon: "ServerStack" },
{ path: "/stock-connectors", label: "Stock Connectors", icon: "Bolt" },
],
},
{
label: "Systeem",
items: [
{ path: "/license-manager", label: "License Manager", icon: "CreditCard" },
{ path: "/license-calculator", label: "Licentie Calculator", icon: "CurrencyDollar" },
{ path: "/security-groups", label: "Security Groups", icon: "ShieldCheck" },
{ path: "/tenant-update", label: "Tenant Update", icon: "CloudArrowUp" },
],
},
]

Stap 2 - Injecteer via CSS + JS in de admin build:

src/admin/widgets/sidebar-sort.tsx
// Widget that re-orders the Extensions section via DOM manipulation
// after Medusa renders the default sidebar
import { defineWidgetConfig } from "@medusajs/admin-sdk"
import { useEffect } from "react"
import { sidebarGroups } from "../config/sidebar-order"
const SidebarSortWidget = () => {
useEffect(() => {
// Re-order extension nav items based on sidebarGroups config
const reorder = () => {
const extensionNav = document.querySelector(
'[class*="flex flex-col gap-y-0.5 py-1 pb-4"]'
)
if (!extensionNav) return
const items = Array.from(extensionNav.children) as HTMLElement[]
const orderedPaths = sidebarGroups.flatMap(g => g.items.map(i => i.path))
// Sort items based on config order
const sorted = orderedPaths
.map(path => items.find(el => el.querySelector(`a[href="${path}"]`)))
.filter(Boolean) as HTMLElement[]
// Re-append in order (moves existing DOM nodes)
sorted.forEach(item => extensionNav.appendChild(item))
}
// Run after Medusa renders
const timer = setTimeout(reorder, 500)
return () => clearTimeout(timer)
}, [])
return null // invisible widget
}
export const config = defineWidgetConfig({
zone: "order.list.before", // any zone to ensure it loads
})
export default SidebarSortWidget
ProCon
Volledige controle over volgordeVereist custom code
Visuele groepering met headersDOM manipulation is fragiel
Geen URL wijzigingenKan breken bij Medusa updates
Schaalbaar (config-driven)Complexer dan aanpak 1 en 2
Mooiste eindresultaatMoet getest worden na elke Medusa upgrade

Geschiktheid: Beste resultaat, maar meeste werk. Ideaal als langetermijn oplossing.


  1. Fase 1: Nested Routes (30 minuten)

    Voeg nested toe aan 6 routes die logisch onder core secties vallen:

    • aplt-productsnested: "/products"
    • products-by-suppliernested: "/products"
    • technique-pricingnested: "/products"
    • category-managernested: "/products"
    • customersnested: "/customers"
    • quotationsnested: "/customers"

    Dit verplaatst 6 van de 18 routes uit de Extensions sectie naar logische plekken.

  2. Fase 2: Evalueer (1 week gebruiken)

    Gebruik de admin een week met de nested routes. Bepaal of de overige 12 routes in Extensions voldoende zijn, of dat groepering nodig is.

  3. Fase 3: Custom Sidebar (optioneel, 1-2 dagen)

    Als groepering gewenst is, implementeer de custom sidebar config met gegroepeerde navigatie voor de overige CMS, Integraties en Systeem routes.


Wijzigingen aan defineRouteConfig vereisen:

  1. Code aanpassen in /mnt/data/magic_pim/backend/src/admin/routes/*/page.tsx
  2. npx medusa build uitvoeren
  3. PM2 restart (sudo -u adminwayne pm2 restart magic-pim-backend)
  4. Voor tenants: distribueren via Tenant Update of Brinxx Code Sync