@judo/app-shell 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +277 -0
- package/README.md +186 -0
- package/dist/AppShell.d.ts +15 -0
- package/dist/AppShell.d.ts.map +1 -0
- package/dist/actors/ActorSelector.d.ts +8 -0
- package/dist/actors/ActorSelector.d.ts.map +1 -0
- package/dist/errors/AppErrorBoundary.d.ts +20 -0
- package/dist/errors/AppErrorBoundary.d.ts.map +1 -0
- package/dist/hooks/use-navigation-badge.d.ts +8 -0
- package/dist/hooks/use-navigation-badge.d.ts.map +1 -0
- package/dist/hooks/use-theme.d.ts +33 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2068 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/AppBar.d.ts +19 -0
- package/dist/layout/AppBar.d.ts.map +1 -0
- package/dist/layout/AppShellLayout.d.ts +14 -0
- package/dist/layout/AppShellLayout.d.ts.map +1 -0
- package/dist/layout/Breadcrumbs.d.ts +8 -0
- package/dist/layout/Breadcrumbs.d.ts.map +1 -0
- package/dist/layout/Footer.d.ts +9 -0
- package/dist/layout/Footer.d.ts.map +1 -0
- package/dist/layout/PageDialogHost.d.ts +9 -0
- package/dist/layout/PageDialogHost.d.ts.map +1 -0
- package/dist/layout/layout-constants.d.ts +8 -0
- package/dist/layout/layout-constants.d.ts.map +1 -0
- package/dist/locale/LocaleSwitcher.d.ts +16 -0
- package/dist/locale/LocaleSwitcher.d.ts.map +1 -0
- package/dist/navigation/HorizontalNavigation.d.ts +14 -0
- package/dist/navigation/HorizontalNavigation.d.ts.map +1 -0
- package/dist/navigation/HorizontalNavigationItem.d.ts +20 -0
- package/dist/navigation/HorizontalNavigationItem.d.ts.map +1 -0
- package/dist/navigation/NavigationDrawer.d.ts +13 -0
- package/dist/navigation/NavigationDrawer.d.ts.map +1 -0
- package/dist/navigation/NavigationItemRenderer.d.ts +19 -0
- package/dist/navigation/NavigationItemRenderer.d.ts.map +1 -0
- package/dist/navigation/dashboard-utils.d.ts +8 -0
- package/dist/navigation/dashboard-utils.d.ts.map +1 -0
- package/dist/navigation/navigation-utils.d.ts +41 -0
- package/dist/navigation/navigation-utils.d.ts.map +1 -0
- package/dist/navigation/use-menu-operation-dispatch.d.ts +26 -0
- package/dist/navigation/use-menu-operation-dispatch.d.ts.map +1 -0
- package/dist/routes/DefaultGuestPage.d.ts +10 -0
- package/dist/routes/DefaultGuestPage.d.ts.map +1 -0
- package/dist/routes/DefaultSettingsPage.d.ts +9 -0
- package/dist/routes/DefaultSettingsPage.d.ts.map +1 -0
- package/dist/routes/PageRoute.d.ts +13 -0
- package/dist/routes/PageRoute.d.ts.map +1 -0
- package/dist/routes/RedirectPage.d.ts +12 -0
- package/dist/routes/RedirectPage.d.ts.map +1 -0
- package/dist/routes/generate-routes.d.ts +24 -0
- package/dist/routes/generate-routes.d.ts.map +1 -0
- package/dist/runtime/DefaultErrorScreen.d.ts +11 -0
- package/dist/runtime/DefaultErrorScreen.d.ts.map +1 -0
- package/dist/runtime/DefaultLoadingScreen.d.ts +5 -0
- package/dist/runtime/DefaultLoadingScreen.d.ts.map +1 -0
- package/dist/runtime/JudoRuntime.d.ts +27 -0
- package/dist/runtime/JudoRuntime.d.ts.map +1 -0
- package/dist/runtime/PrincipalBridge.d.ts +14 -0
- package/dist/runtime/PrincipalBridge.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +5 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/types.d.ts +308 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/theme/ThemeProvider.d.ts +21 -0
- package/dist/theme/ThemeProvider.d.ts.map +1 -0
- package/dist/theme/ThemeToggle.d.ts +11 -0
- package/dist/theme/ThemeToggle.d.ts.map +1 -0
- package/dist/theme/density.d.ts +19 -0
- package/dist/theme/density.d.ts.map +1 -0
- package/dist/theme/judo-theme-factory.d.ts +29 -0
- package/dist/theme/judo-theme-factory.d.ts.map +1 -0
- package/dist/theme/presets.d.ts +51 -0
- package/dist/theme/presets.d.ts.map +1 -0
- package/dist/user/DefaultHeroComponent.d.ts +11 -0
- package/dist/user/DefaultHeroComponent.d.ts.map +1 -0
- package/dist/user/UserMenu.d.ts +8 -0
- package/dist/user/UserMenu.d.ts.map +1 -0
- package/package.json +99 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["targets: string[]","overrides: Record<string, unknown>","REACT_ELEMENT_TYPE","REACT_FRAGMENT_TYPE","REACT_PROFILER_TYPE","REACT_STRICT_MODE_TYPE","REACT_SUSPENSE_TYPE","REACT_SUSPENSE_LIST_TYPE","REACT_VIEW_TRANSITION_TYPE","REACT_CONTEXT_TYPE","REACT_FORWARD_REF_TYPE","REACT_LAZY_TYPE","REACT_MEMO_TYPE","REACT_CONSUMER_TYPE","REACT_PORTAL_TYPE","REACT_CLIENT_REFERENCE","themePresets: Record<ThemePresetName, ThemePreset>","applications: Application[]","resolvedMuiProComponents: Record<string, ComponentType<any>>","mode: PaletteMode"],"sources":["../src/hooks/use-theme.ts","../src/hooks/use-navigation-badge.ts","../src/navigation/navigation-utils.ts","../src/navigation/NavigationItemRenderer.tsx","../src/navigation/use-menu-operation-dispatch.ts","../src/navigation/NavigationDrawer.tsx","../src/navigation/dashboard-utils.ts","../src/actors/ActorSelector.tsx","../src/locale/LocaleSwitcher.tsx","../src/navigation/HorizontalNavigationItem.tsx","../src/navigation/HorizontalNavigation.tsx","../src/theme/ThemeToggle.tsx","../src/user/DefaultHeroComponent.tsx","../src/layout/AppBar.tsx","../src/layout/Breadcrumbs.tsx","../src/layout/Footer.tsx","../src/layout/PageDialogHost.tsx","../src/layout/layout-constants.ts","../src/layout/AppShellLayout.tsx","../src/runtime/PrincipalBridge.tsx","../src/routes/DefaultGuestPage.tsx","../src/routes/DefaultSettingsPage.tsx","../src/routes/PageRoute.tsx","../src/routes/RedirectPage.tsx","../src/routes/generate-routes.tsx","../../../node_modules/.pnpm/react-is@19.2.4/node_modules/react-is/cjs/react-is.production.js","../../../node_modules/.pnpm/react-is@19.2.4/node_modules/react-is/cjs/react-is.development.js","../../../node_modules/.pnpm/react-is@19.2.4/node_modules/react-is/index.js","../../../node_modules/.pnpm/@mui+utils@7.3.8_@types+react@19.2.14_react@19.2.4/node_modules/@mui/utils/esm/deepmerge/deepmerge.js","../src/theme/density.ts","../src/theme/judo-theme-factory.ts","../src/theme/presets.ts","../src/theme/ThemeProvider.tsx","../src/runtime/DefaultErrorScreen.tsx","../src/runtime/DefaultLoadingScreen.tsx","../src/runtime/JudoRuntime.tsx","../src/errors/AppErrorBoundary.tsx","../src/AppShell.tsx","../src/user/UserMenu.tsx"],"sourcesContent":["import type { ThemeConfig } from \"@judo/model-api\";\nimport { useCallback, useSyncExternalStore } from \"react\";\n\nconst THEME_MODE_KEY = \"theme-mode\";\nconst THEME_SYSTEM_KEY = \"theme-system\";\n\n// Get initial mode from localStorage or system preference\nexport function getInitialMode(): \"light\" | \"dark\" {\n\tif (typeof window === \"undefined\") return \"light\";\n\tconst stored = localStorage.getItem(THEME_MODE_KEY);\n\tif (stored === \"light\" || stored === \"dark\") return stored;\n\t// Check matchMedia exists (may not be available in test environments)\n\tif (typeof window.matchMedia === \"function\") {\n\t\treturn window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n\t}\n\treturn \"light\";\n}\n\n// Check if user previously selected system preference mode\nfunction getStoredSystemPreference(): boolean {\n\tif (typeof window === \"undefined\") return false;\n\treturn localStorage.getItem(THEME_SYSTEM_KEY) === \"true\";\n}\n\n/**\n * Shared theme store.\n * Uses the subscribe/getSnapshot pattern for useSyncExternalStore.\n * Tracks OS/browser preference when in 'system' mode.\n */\nclass LocalThemeStore {\n\tprivate config: ThemeConfig = { mode: getInitialMode(), isSystemMode: getStoredSystemPreference() };\n\tprivate listeners = new Set<() => void>();\n\tprivate useSystemPreference = getStoredSystemPreference();\n\tprivate mediaQuery: MediaQueryList | null = null;\n\tprivate mediaQueryListener: ((e: MediaQueryListEvent) => void) | null = null;\n\n\tconstructor() {\n\t\tif (typeof window !== \"undefined\" && typeof window.matchMedia === \"function\") {\n\t\t\tthis.mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\t\t\t// If system preference was previously stored, start tracking\n\t\t\tif (this.useSystemPreference) {\n\t\t\t\tthis.startSystemPreferenceTracking();\n\t\t\t}\n\t\t}\n\t}\n\n\tsubscribe = (listener: () => void): (() => void) => {\n\t\tthis.listeners.add(listener);\n\t\treturn () => this.listeners.delete(listener);\n\t};\n\n\tgetSnapshot = (): ThemeConfig => {\n\t\treturn this.config;\n\t};\n\n\tprivate getSystemPreference(): \"light\" | \"dark\" {\n\t\tif (this.mediaQuery?.matches) {\n\t\t\treturn \"dark\";\n\t\t}\n\t\treturn \"light\";\n\t}\n\n\tprivate startSystemPreferenceTracking(): void {\n\t\tif (!this.mediaQuery || this.mediaQueryListener) return;\n\n\t\tthis.mediaQueryListener = (e: MediaQueryListEvent) => {\n\t\t\tif (this.useSystemPreference) {\n\t\t\t\tconst newMode = e.matches ? \"dark\" : \"light\";\n\t\t\t\tthis.config = { ...this.config, mode: newMode };\n\t\t\t\tfor (const listener of this.listeners) {\n\t\t\t\t\tlistener();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.mediaQuery.addEventListener(\"change\", this.mediaQueryListener);\n\t}\n\n\tprivate stopSystemPreferenceTracking(): void {\n\t\tif (this.mediaQuery && this.mediaQueryListener) {\n\t\t\tthis.mediaQuery.removeEventListener(\"change\", this.mediaQueryListener);\n\t\t\tthis.mediaQueryListener = null;\n\t\t}\n\t}\n\n\tsetTheme = (update: Partial<ThemeConfig>): void => {\n\t\t// Check if we should track system preference\n\t\tconst _shouldTrackSystem = (update as any).__useSystemPreference;\n\n\t\tif ((update as any).__useSystemPreference !== undefined) {\n\t\t\tthis.useSystemPreference = (update as any).__useSystemPreference;\n\t\t\t(update as any).__useSystemPreference = undefined;\n\n\t\t\tif (this.useSystemPreference) {\n\t\t\t\tthis.startSystemPreferenceTracking();\n\t\t\t\t// Set mode to current system preference\n\t\t\t\tupdate.mode = this.getSystemPreference();\n\t\t\t\tupdate.isSystemMode = true;\n\t\t\t\t// Persist system preference flag\n\t\t\t\tlocalStorage.setItem(THEME_SYSTEM_KEY, \"true\");\n\t\t\t\tlocalStorage.removeItem(THEME_MODE_KEY);\n\t\t\t} else {\n\t\t\t\tthis.stopSystemPreferenceTracking();\n\t\t\t\tupdate.isSystemMode = false;\n\t\t\t\t// Clear system preference flag\n\t\t\t\tlocalStorage.removeItem(THEME_SYSTEM_KEY);\n\t\t\t}\n\t\t}\n\n\t\tthis.config = { ...this.config, ...update };\n\n\t\t// Persist mode to localStorage if not using system preference\n\t\tif (update.mode && !this.useSystemPreference) {\n\t\t\tlocalStorage.setItem(THEME_MODE_KEY, update.mode);\n\t\t}\n\n\t\tfor (const listener of this.listeners) {\n\t\t\tlistener();\n\t\t}\n\t};\n\n\tcleanup = (): void => {\n\t\tthis.stopSystemPreferenceTracking();\n\t};\n}\n\n// Singleton instance\nlet localStore = new LocalThemeStore();\n\n/**\n * Check if user has a saved theme preference (either mode or system preference)\n */\nexport function hasUserThemePreference(): boolean {\n\tif (typeof window === \"undefined\") return false;\n\treturn localStorage.getItem(THEME_MODE_KEY) !== null || localStorage.getItem(THEME_SYSTEM_KEY) !== null;\n}\n\n/**\n * Initialize the theme store with runtime configuration.\n * Should be called by JudoRuntime before rendering the app.\n *\n * IMPORTANT: If user has already saved a preference (in localStorage), this\n * function will only apply non-mode properties (colors, muiThemeOptions).\n * The user's saved mode preference is preserved.\n *\n * @param config - Theme configuration\n * @param useSystemPreference - Whether to track OS/browser preference (when defaultMode is 'system')\n */\nexport function initializeThemeStore(config: Partial<ThemeConfig>, useSystemPreference = false): void {\n\t// Check if user has already saved a preference\n\tconst userHasPreference = hasUserThemePreference();\n\n\tif (userHasPreference) {\n\t\t// User has saved preference - only apply non-mode config (colors, etc.)\n\t\t// Don't override their mode/system preference choice\n\t\tconst { mode: _mode, ...nonModeConfig } = config;\n\t\tlocalStore.setTheme(nonModeConfig);\n\t} else {\n\t\t// No saved preference - apply the full config including mode\n\t\tlocalStore.setTheme({ ...config, __useSystemPreference: useSystemPreference } as any);\n\t}\n}\n\n/**\n * Reset the local theme store to initial state.\n * Only exported for testing purposes.\n */\nexport function resetLocalThemeStore(): void {\n\tlocalStore = new LocalThemeStore();\n}\n\n/**\n * Hook to get and set theme configuration.\n *\n * Currently using local store only.\n */\nexport function useTheme() {\n\tconst config = useSyncExternalStore(localStore.subscribe, localStore.getSnapshot, localStore.getSnapshot);\n\n\tconst setTheme = useCallback((update: Partial<ThemeConfig>) => {\n\t\tlocalStore.setTheme(update);\n\t}, []);\n\n\treturn { config, setTheme };\n}\n","import type { BadgeInfo } from \"@judo/model-api\";\n\n/**\n * Hook to get badge info for a navigation item.\n *\n * Need to implement a new badge service provider pattern.\n */\nexport function useNavigationBadge(_itemId: string): BadgeInfo | null {\n\treturn null;\n}\n","import type { Action, NavigationController, NavigationItem, PageContainer, PageDefinition } from \"@judo/model-api\";\nimport { PageContainerType } from \"@judo/model-api\";\n\n/**\n * Filter navigation items by search query (recursive).\n */\nexport function filterNavigationItems(items: NavigationItem[], query: string): NavigationItem[] {\n\tconst lowerQuery = query.toLowerCase();\n\n\treturn items.filter((item) => {\n\t\tconst matchesSelf = (item.label ?? item.name).toLowerCase().includes(lowerQuery);\n\n\t\tconst matchesChildren = item.items ? filterNavigationItems(item.items, query).length > 0 : false;\n\n\t\treturn matchesSelf || matchesChildren;\n\t});\n}\n\n/**\n * Get the container type suffix for routes.\n * Uses the container's type property which is always present after parsing\n * (EMF defaults to TABLE when not explicitly set).\n */\nfunction getContainerTypeSuffix(container: PageContainer): string {\n\tswitch (container.type) {\n\t\tcase PageContainerType.TABLE:\n\t\t\treturn \"table\";\n\t\tcase PageContainerType.FORM:\n\t\t\treturn \"form\";\n\t\tcase PageContainerType.VIEW:\n\t\t\treturn \"view\";\n\t\tdefault:\n\t\t\t// Fallback for safety, but type should always be present\n\t\t\treturn \"table\";\n\t}\n}\n\n/**\n * Check if a PageDefinition has a resolved container (object vs string reference).\n */\nfunction hasResolvedContainer(page: PageDefinition): page is PageDefinition & { container: PageContainer } {\n\treturn page.container !== null && typeof page.container === \"object\";\n}\n\n/**\n * Get the base path from a page name (strips the page type suffix).\n * \"Customer::orders::AccessTablePage\" -> \"customer/orders\"\n * \"God::God::galaxies::AccessFormPage\" -> \"god/god/galaxies\"\n * \"View::Galaxy::matter::RelationTablePage\" -> \"view/galaxy/matter\"\n */\nfunction getBasePathFromName(name: string): string {\n\treturn name\n\t\t.replace(/::Access(Table|Form|View)Page$/, \"\") // Strip Access*Page suffix\n\t\t.replace(/::Relation(Table|Form|View)Page$/, \"\") // Strip Relation*Page suffix\n\t\t.replace(/::/g, \"/\")\n\t\t.toLowerCase();\n}\n\n/**\n * Get route path for a page definition.\n * Uses the resolved container to determine the page type suffix.\n */\nexport function getRouteForPage(pageRef: unknown): string {\n\t// Handle resolved PageDefinition objects with container\n\tif (pageRef && typeof pageRef === \"object\") {\n\t\tconst page = pageRef as PageDefinition;\n\n\t\t// If we have a resolved container, use its type for the route suffix\n\t\tif (hasResolvedContainer(page) && page.name) {\n\t\t\tconst basePath = getBasePathFromName(page.name);\n\t\t\tconst typeSuffix = getContainerTypeSuffix(page.container);\n\t\t\treturn `/${basePath}/${typeSuffix}`;\n\t\t}\n\n\t\t// Try to get the name and fall back to string-based routing\n\t\tif (typeof page.name === \"string\") {\n\t\t\treturn getRouteFromString(page.name);\n\t\t}\n\n\t\t// Try xmi:id as fallback\n\t\tconst xmiId = (page as unknown as Record<string, unknown>)[\"xmi:id\"];\n\t\tif (typeof xmiId === \"string\") {\n\t\t\treturn getRouteFromString(xmiId);\n\t\t}\n\n\t\t// Last resort: return root\n\t\treturn \"/\";\n\t}\n\n\t// Handle string references\n\tif (typeof pageRef === \"string\") {\n\t\treturn getRouteFromString(pageRef);\n\t}\n\n\treturn \"/\";\n}\n\n/**\n * Get route pattern for React Router (includes parameter placeholders).\n * VIEW pages and RelationTablePages get an optional :signedIdentifier parameter\n * for bookmarkability and parent transfer context.\n */\nexport function getRoutePattern(page: PageDefinition): string {\n\tconst basePath = getRouteForPage(page);\n\n\t// VIEW pages always need :signedIdentifier parameter\n\tconst container = page.container as PageContainer | undefined;\n\tif (container?.type === PageContainerType.VIEW) {\n\t\treturn `${basePath}/:signedIdentifier?`;\n\t}\n\n\t// RelationTablePages need :signedIdentifier to identify parent transfer\n\tif (page.name?.includes(\"::Relation\")) {\n\t\treturn `${basePath}/:signedIdentifier?`;\n\t}\n\n\treturn basePath;\n}\n\n/**\n * Generate route from string reference (page name or xmi:id).\n * Fallback for unresolved references.\n */\nfunction getRouteFromString(ref: string): string {\n\t// Handle XMI ID format: \"Actor/(esm/_xxx)/SomePageDefinition\"\n\tif (ref.includes(\"/(esm/\")) {\n\t\tconst match = ref.match(/^([^/]+)\\/.*\\/(.*)PageDefinition$/);\n\t\tif (match) {\n\t\t\tconst [, actor, pageType] = match;\n\t\t\t// Extract page type suffix from PageDefinition name\n\t\t\tconst accessMatch = pageType.match(/^Access(Table|Form|View)$/);\n\t\t\tif (accessMatch) {\n\t\t\t\treturn `/${actor.toLowerCase()}/${accessMatch[1].toLowerCase()}`;\n\t\t\t}\n\t\t\t// Other PageDefinitions keep the full type\n\t\t\treturn `/${actor.toLowerCase()}/${pageType.toLowerCase()}`;\n\t\t}\n\t\t// Fallback: just use the actor name\n\t\treturn `/${ref.split(\"/\")[0].toLowerCase()}`;\n\t}\n\n\t// Handle page name format: \"Customer::orders::AccessTablePage\"\n\tconst accessPageMatch = ref.match(/(.*)::Access(Table|Form|View)Page$/);\n\tif (accessPageMatch) {\n\t\tconst [, basePath, pageType] = accessPageMatch;\n\t\treturn `/${basePath.replace(/::/g, \"/\").toLowerCase()}/${pageType.toLowerCase()}`;\n\t}\n\n\t// Handle relation page name format: \"View::Galaxy::matter::RelationTablePage\"\n\tconst relationPageMatch = ref.match(/(.*)::Relation(Table|Form|View)Page$/);\n\tif (relationPageMatch) {\n\t\tconst [, basePath, pageType] = relationPageMatch;\n\t\treturn `/${basePath.replace(/::/g, \"/\").toLowerCase()}/${pageType.toLowerCase()}`;\n\t}\n\n\t// Fallback for other formats\n\treturn `/${ref.replace(/::/g, \"/\").toLowerCase()}`;\n}\n\n/**\n * Get expanded state storage key.\n */\nexport function getNavExpandedStorageKey(): string {\n\treturn \"nav-expanded\";\n}\n\n/**\n * Load expanded navigation items from localStorage.\n */\nexport function loadExpandedItems(): Set<string> {\n\ttry {\n\t\tconst saved = localStorage.getItem(getNavExpandedStorageKey());\n\t\tif (saved) {\n\t\t\treturn new Set(JSON.parse(saved));\n\t\t}\n\t} catch {\n\t\t// Ignore localStorage errors\n\t}\n\treturn new Set();\n}\n\n/**\n * Save expanded navigation items to localStorage.\n */\nexport function saveExpandedItems(items: Set<string>): void {\n\ttry {\n\t\tlocalStorage.setItem(getNavExpandedStorageKey(), JSON.stringify([...items]));\n\t} catch {\n\t\t// Ignore localStorage errors\n\t}\n}\n\n/**\n * Find the Action in NavigationController.actions that matches a NavigationItem's actionDefinition.\n *\n * Menu operation items (MenuItemOperation) have an embedded actionDefinition, and the\n * NavigationController.actions array has corresponding Action entries with runtime metadata\n * (targetPageDefinition, targetDataElement, ownerDataElement, isMenuAction).\n *\n * @param controller - The NavigationController containing the actions array\n * @param item - The NavigationItem with an actionDefinition to match\n * @returns The matching Action, or undefined if no match is found\n */\nexport function findActionForNavigationItem(\n\tcontroller: NavigationController,\n\titem: NavigationItem\n): Action | undefined {\n\tif (!item.actionDefinition || !controller.actions) {\n\t\treturn undefined;\n\t}\n\n\tconst targetDefId = item.actionDefinition[\"xmi:id\"];\n\tif (!targetDefId) {\n\t\treturn undefined;\n\t}\n\n\treturn controller.actions.find((action) => {\n\t\tconst actionDef = action.actionDefinition;\n\t\t// Handle resolved object references (after model-loader resolution)\n\t\tif (typeof actionDef === \"object\" && actionDef !== null) {\n\t\t\treturn actionDef[\"xmi:id\"] === targetDefId;\n\t\t}\n\t\t// Handle unresolved string references (raw XMI ID before resolution)\n\t\tif (typeof actionDef === \"string\") {\n\t\t\treturn actionDef === targetDefId;\n\t\t}\n\t\treturn false;\n\t});\n}\n","import { IconRenderer } from \"@judo/components\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Action, NavigationItem } from \"@judo/model-api\";\nimport { getNavItemTestId } from \"@judo/test-ids\";\nimport ExpandLessIcon from \"@mui/icons-material/ExpandLess\";\nimport ExpandMoreIcon from \"@mui/icons-material/ExpandMore\";\nimport FolderIcon from \"@mui/icons-material/Folder\";\nimport { Badge, Collapse, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Tooltip } from \"@mui/material\";\nimport { useLocation, useNavigate } from \"react-router\";\nimport { useNavigationBadge } from \"../hooks/use-navigation-badge\";\nimport { getRouteForPage } from \"./navigation-utils\";\n\nexport interface NavigationItemRendererProps {\n\titem: NavigationItem;\n\tcollapsed: boolean;\n\texpanded: boolean;\n\tonToggleExpanded: () => void;\n\tdepth: number;\n\texpandedItems: Set<string>;\n\tonItemExpand: (itemId: string) => void;\n\t/** Actions from NavigationController for resolving menu operations */\n\tnavigationActions?: Action[];\n\t/** Callback to dispatch a menu operation action */\n\tonMenuAction?: (action: Action) => Promise<void>;\n}\n\n/**\n * Renders a navigation menu item with support for nested items.\n */\nexport function NavigationItemRenderer({\n\titem,\n\tcollapsed,\n\texpanded,\n\tonToggleExpanded,\n\tdepth,\n\texpandedItems,\n\tonItemExpand,\n\tnavigationActions,\n\tonMenuAction,\n}: NavigationItemRendererProps) {\n\tconst navigate = useNavigate();\n\tconst location = useLocation();\n\tconst badge = useNavigationBadge(item[\"xmi:id\"] ?? \"\");\n\tconst { label } = useModelLabel(item);\n\n\tconst hasChildren = item.items && item.items.length > 0;\n\t// item.target is now a resolved PageDefinition\n\tconst targetRoute = item.target ? getRouteForPage(item.target) : undefined;\n\tconst isMenuOperation = !!item.actionDefinition;\n\tconst isActive = targetRoute && location.pathname.includes(targetRoute);\n\tconst testId = getNavItemTestId(item);\n\n\tconst handleClick = () => {\n\t\tif (hasChildren) {\n\t\t\tonToggleExpanded();\n\t\t} else if (isMenuOperation && onMenuAction && navigationActions) {\n\t\t\t// Find the matching Action from navigationActions by actionDefinition xmi:id\n\t\t\tconst targetDefId = item.actionDefinition?.[\"xmi:id\"];\n\t\t\tif (targetDefId) {\n\t\t\t\tconst action = navigationActions.find((a) => {\n\t\t\t\t\tconst actionDef = a.actionDefinition;\n\t\t\t\t\tif (typeof actionDef === \"object\" && actionDef !== null) {\n\t\t\t\t\t\treturn actionDef[\"xmi:id\"] === targetDefId;\n\t\t\t\t\t}\n\t\t\t\t\treturn typeof actionDef === \"string\" && actionDef === targetDefId;\n\t\t\t\t});\n\t\t\t\tif (action) {\n\t\t\t\t\tonMenuAction(action);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (targetRoute) {\n\t\t\tnavigate(targetRoute);\n\t\t}\n\t};\n\n\tconst content = (\n\t\t<ListItem disablePadding sx={{ pl: depth * 2 }} data-testid={testId}>\n\t\t\t<ListItemButton\n\t\t\t\tonClick={handleClick}\n\t\t\t\tselected={!!isActive}\n\t\t\t\tsx={{\n\t\t\t\t\tminHeight: 48,\n\t\t\t\t\tjustifyContent: collapsed ? \"center\" : \"initial\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{/* Icon with Badge */}\n\t\t\t\t<ListItemIcon\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tminWidth: 0,\n\t\t\t\t\t\tmr: collapsed ? 0 : 2,\n\t\t\t\t\t\tjustifyContent: \"center\",\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Badge\n\t\t\t\t\t\tbadgeContent={badge?.count}\n\t\t\t\t\t\tcolor={badge?.color ?? \"primary\"}\n\t\t\t\t\t\tmax={badge?.max ?? 99}\n\t\t\t\t\t\tinvisible={!badge}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.icon ? <IconRenderer icon={item.icon} size=\"medium\" /> : <FolderIcon />}\n\t\t\t\t\t</Badge>\n\t\t\t\t</ListItemIcon>\n\n\t\t\t\t{/* Label (hidden when collapsed) */}\n\t\t\t\t{!collapsed && (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<ListItemText primary={label} />\n\t\t\t\t\t\t{hasChildren && (expanded ? <ExpandLessIcon /> : <ExpandMoreIcon />)}\n\t\t\t\t\t</>\n\t\t\t\t)}\n\t\t\t</ListItemButton>\n\t\t</ListItem>\n\t);\n\n\t// Wrap in tooltip when collapsed\n\tconst wrappedContent = collapsed ? (\n\t\t<Tooltip title={label} placement=\"right\">\n\t\t\t{content}\n\t\t</Tooltip>\n\t) : (\n\t\tcontent\n\t);\n\n\treturn (\n\t\t<>\n\t\t\t{wrappedContent}\n\n\t\t\t{/* Nested Items */}\n\t\t\t{hasChildren && !collapsed && (\n\t\t\t\t<Collapse in={expanded} timeout=\"auto\" unmountOnExit>\n\t\t\t\t\t<List component=\"div\" disablePadding>\n\t\t\t\t\t\t{item.items?.map((child) => {\n\t\t\t\t\t\t\tconst childId = child[\"xmi:id\"] ?? \"\";\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<NavigationItemRenderer\n\t\t\t\t\t\t\t\t\tkey={childId}\n\t\t\t\t\t\t\t\t\titem={child}\n\t\t\t\t\t\t\t\t\tcollapsed={collapsed}\n\t\t\t\t\t\t\t\t\texpanded={expandedItems.has(childId)}\n\t\t\t\t\t\t\t\t\tonToggleExpanded={() => onItemExpand(childId)}\n\t\t\t\t\t\t\t\t\tdepth={depth + 1}\n\t\t\t\t\t\t\t\t\texpandedItems={expandedItems}\n\t\t\t\t\t\t\t\t\tonItemExpand={onItemExpand}\n\t\t\t\t\t\t\t\t\tnavigationActions={navigationActions}\n\t\t\t\t\t\t\t\t\tonMenuAction={onMenuAction}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t})}\n\t\t\t\t\t</List>\n\t\t\t\t</Collapse>\n\t\t\t)}\n\t\t</>\n\t);\n}\n","import { useActionDispatcher, useApi } from \"@judo/actions\";\nimport { useApplication, useDataStore, useNavigation } from \"@judo/core\";\nimport { useNotifications } from \"@judo/feedback\";\nimport type { Action } from \"@judo/model-api\";\n\n/**\n * Result of useMenuOperationDispatch hook.\n */\nexport interface UseMenuOperationDispatchResult {\n\t/**\n\t * Dispatch an Action resolved from a menu operation item.\n\t * Called by the NavigationItemRenderer after it looks up the matching\n\t * Action from the NavigationController.actions array.\n\t */\n\tdispatchMenuAction: (action: Action) => Promise<void>;\n}\n\n/**\n * Hook providing dispatch capability for menu operation items.\n *\n * Menu operation items (MenuItemOperation) are NavigationItems that have an\n * actionDefinition instead of a target page. They trigger custom operations\n * such as parameterless API calls or opening operation input forms/selectors.\n *\n * This hook wires up the action dispatching infrastructure\n * to enable these operations from the navigation menu.\n *\n * @returns Object with dispatchMenuAction function\n */\nexport function useMenuOperationDispatch(): UseMenuOperationDispatchResult {\n\tconst navigation = useNavigation();\n\tconst dataStore = useDataStore();\n\tconst application = useApplication();\n\tconst api = useApi();\n\tconst notifications = useNotifications();\n\n\tconst { dispatch } = useActionDispatcher({\n\t\tnavigation,\n\t\tdata: dataStore,\n\t\tregistry: application,\n\t\tapi,\n\t\tnotifications,\n\t});\n\n\treturn {\n\t\tdispatchMenuAction: dispatch,\n\t};\n}\n","import { useCustomizationsOptional } from \"@judo/core\";\nimport type { NavigationController } from \"@judo/model-api\";\nimport ChevronLeftIcon from \"@mui/icons-material/ChevronLeft\";\nimport ChevronRightIcon from \"@mui/icons-material/ChevronRight\";\nimport SearchIcon from \"@mui/icons-material/Search\";\nimport { Box, Divider, Drawer, IconButton, InputAdornment, List, TextField } from \"@mui/material\";\nimport { useEffect, useMemo, useState } from \"react\";\nimport { NavigationItemRenderer } from \"./NavigationItemRenderer\";\nimport { filterNavigationItems, loadExpandedItems, saveExpandedItems } from \"./navigation-utils\";\nimport { useMenuOperationDispatch } from \"./use-menu-operation-dispatch\";\n\nexport interface NavigationDrawerProps {\n\topen: boolean;\n\tcollapsed: boolean;\n\tonCollapse: () => void;\n\twidth: number;\n\tnavigationController?: NavigationController;\n}\n\n/**\n * Navigation drawer with search and multi-level menu support.\n */\nexport function NavigationDrawer({ open, collapsed, onCollapse, width, navigationController }: NavigationDrawerProps) {\n\tconst [searchQuery, setSearchQuery] = useState(\"\");\n\tconst [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());\n\n\t// Load expanded state from localStorage\n\tuseEffect(() => {\n\t\tsetExpandedItems(loadExpandedItems());\n\t}, []);\n\n\t// Toggle expanded state for an item\n\tconst toggleExpanded = (itemId: string) => {\n\t\tsetExpandedItems((prev) => {\n\t\t\tconst next = new Set(prev);\n\t\t\tif (next.has(itemId)) {\n\t\t\t\tnext.delete(itemId);\n\t\t\t} else {\n\t\t\t\tnext.add(itemId);\n\t\t\t}\n\t\t\tsaveExpandedItems(next);\n\t\t\treturn next;\n\t\t});\n\t};\n\n\t// Apply menu customizer from customizations\n\tconst menuCustomizer = useCustomizationsOptional()?.getMenuCustomizer();\n\tconst items = useMemo(() => {\n\t\tconst raw = navigationController?.items ?? [];\n\t\treturn menuCustomizer ? menuCustomizer(raw) : raw;\n\t}, [navigationController?.items, menuCustomizer]);\n\n\t// Filter items by search query\n\tconst filteredItems = useMemo(() => {\n\t\tif (!searchQuery) return items;\n\t\treturn filterNavigationItems(items, searchQuery);\n\t}, [items, searchQuery]);\n\n\t// Menu operation dispatch for items with actionDefinition\n\tconst { dispatchMenuAction } = useMenuOperationDispatch();\n\tconst navigationActions = navigationController?.actions;\n\n\treturn (\n\t\t<Drawer\n\t\t\tvariant=\"persistent\"\n\t\t\topen={open}\n\t\t\tsx={{\n\t\t\t\twidth,\n\t\t\t\tflexShrink: 0,\n\t\t\t\t\"& .MuiDrawer-paper\": {\n\t\t\t\t\twidth,\n\t\t\t\t\tboxSizing: \"border-box\",\n\t\t\t\t\ttransition: \"width 0.2s\",\n\t\t\t\t},\n\t\t\t}}\n\t\t\tdata-testid=\"navigation-drawer\"\n\t\t>\n\t\t\t{/* Collapse Toggle */}\n\t\t\t<Box\n\t\t\t\tsx={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\talignItems: \"center\",\n\t\t\t\t\tjustifyContent: \"flex-end\",\n\t\t\t\t\tminHeight: { xs: 56, sm: 64 },\n\t\t\t\t\tpx: 1,\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<IconButton onClick={onCollapse} data-testid=\"navigation-drawer::collapse\">\n\t\t\t\t\t{collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}\n\t\t\t\t</IconButton>\n\t\t\t</Box>\n\n\t\t\t<Divider />\n\n\t\t\t{/* Search (hidden when collapsed) */}\n\t\t\t{!collapsed && (\n\t\t\t\t<Box sx={{ p: 1 }}>\n\t\t\t\t\t<TextField\n\t\t\t\t\t\tsize=\"small\"\n\t\t\t\t\t\tplaceholder=\"Search menu...\"\n\t\t\t\t\t\tvalue={searchQuery}\n\t\t\t\t\t\tonChange={(e) => setSearchQuery(e.target.value)}\n\t\t\t\t\t\tfullWidth\n\t\t\t\t\t\tdata-testid=\"navigation-drawer::search\"\n\t\t\t\t\t\tslotProps={{\n\t\t\t\t\t\t\tinput: {\n\t\t\t\t\t\t\t\tstartAdornment: (\n\t\t\t\t\t\t\t\t\t<InputAdornment position=\"start\">\n\t\t\t\t\t\t\t\t\t\t<SearchIcon />\n\t\t\t\t\t\t\t\t\t</InputAdornment>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</Box>\n\t\t\t)}\n\n\t\t\t{/* Navigation Items */}\n\t\t\t<List data-testid=\"navigation-drawer::items\">\n\t\t\t\t{filteredItems.map((item) => {\n\t\t\t\t\tconst itemId = item[\"xmi:id\"] ?? \"\";\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<NavigationItemRenderer\n\t\t\t\t\t\t\tkey={itemId}\n\t\t\t\t\t\t\titem={item}\n\t\t\t\t\t\t\tcollapsed={collapsed}\n\t\t\t\t\t\t\texpanded={expandedItems.has(itemId)}\n\t\t\t\t\t\t\tonToggleExpanded={() => toggleExpanded(itemId)}\n\t\t\t\t\t\t\tdepth={0}\n\t\t\t\t\t\t\texpandedItems={expandedItems}\n\t\t\t\t\t\t\tonItemExpand={toggleExpanded}\n\t\t\t\t\t\t\tnavigationActions={navigationActions}\n\t\t\t\t\t\t\tonMenuAction={dispatchMenuAction}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</List>\n\t\t</Drawer>\n\t);\n}\n","import type { Application, NavigationItem } from \"@judo/model-api\";\nimport { getRouteForPage } from \"./navigation-utils\";\n\n/**\n * Recursively find all page targets from navigation items.\n */\nfunction getNavigationTargets(items: NavigationItem[]): string[] {\n\tconst targets: string[] = [];\n\n\tfor (const item of items) {\n\t\tif (item.target) {\n\t\t\t// target is now a resolved PageDefinition, so extract the name\n\t\t\ttargets.push(item.target.name);\n\t\t}\n\t\tif (item.items) {\n\t\t\ttargets.push(...getNavigationTargets(item.items));\n\t\t}\n\t}\n\n\treturn targets;\n}\n\n/**\n * Get the dashboard route for an application.\n * Returns the route for the first page marked as dashboard that is also in the navigation tree,\n * or \"/\" if none found.\n */\nexport function getDashboardRoute(application: Application): string {\n\t// Get all page targets referenced in navigation\n\tconst navigationTargets = application.navigationController\n\t\t? getNavigationTargets(application.navigationController.items)\n\t\t: [];\n\n\t// Find dashboard page that's in the navigation tree\n\tconst dashboardPage = application.pages.find(\n\t\t(page) => page.dashboard === true && navigationTargets.includes(page.name)\n\t);\n\n\treturn dashboardPage ? getRouteForPage(dashboardPage) : \"/\";\n}\n","import { ActorSwitchDialog, useActorSwitch } from \"@judo/auth\";\nimport { useApplication } from \"@judo/core\";\nimport type { Application } from \"@judo/model-api\";\nimport { getActorSelectorTestId } from \"@judo/test-ids\";\nimport { FormControl, InputLabel, MenuItem, Select } from \"@mui/material\";\nimport { useCallback } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { getDashboardRoute } from \"../navigation/dashboard-utils\";\n\nexport interface ActorSelectorProps {\n\tclassName?: string;\n}\n\n/**\n * Actor/application selector for multi-actor applications.\n */\nexport function ActorSelector({ className }: ActorSelectorProps) {\n\tconst { application, applications, actorName, switchActorWithNavigation } = useApplication();\n\tconst navigate = useNavigate();\n\n\t// Create helper functions for useActorSwitch\n\tconst getApplication = useCallback(\n\t\t(name: string) => {\n\t\t\tconst app = applications.find((a) => a.name === name || a.actor?.name === name);\n\t\t\tif (!app) {\n\t\t\t\tthrow new Error(`Application for actor '${name}' not found`);\n\t\t\t}\n\t\t\treturn app;\n\t\t},\n\t\t[applications]\n\t);\n\n\t// Navigate to dashboard after switching\n\tconst handleSwitchComplete = useCallback(\n\t\t(name: string) => {\n\t\t\tswitchActorWithNavigation(name, (newApp: Application) => {\n\t\t\t\tconst dashboardRoute = getDashboardRoute(newApp);\n\t\t\t\tnavigate(dashboardRoute);\n\t\t\t});\n\t\t},\n\t\t[switchActorWithNavigation, navigate]\n\t);\n\n\tconst {\n\t\tswitchActor: initiateSwitch,\n\t\tpendingSwitch,\n\t\tconfirmSwitch,\n\t\tcancelSwitch,\n\t} = useActorSwitch(application, getApplication, handleSwitchComplete);\n\n\tconst testId = getActorSelectorTestId(actorName);\n\n\t// Don't show selector if only one application\n\tif (applications.length <= 1) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t<FormControl\n\t\t\t\tsize=\"small\"\n\t\t\t\tsx={(theme) => ({\n\t\t\t\t\tminWidth: 200,\n\t\t\t\t\t\"& .MuiInputLabel-root\": {\n\t\t\t\t\t\tcolor: theme.palette.common.white,\n\t\t\t\t\t\t\"&.Mui-focused\": { color: theme.palette.common.white },\n\t\t\t\t\t},\n\t\t\t\t\t\"& .MuiOutlinedInput-root\": {\n\t\t\t\t\t\tcolor: theme.palette.common.white,\n\t\t\t\t\t\t\"& fieldset\": { borderColor: \"rgba(255, 255, 255, 0.5)\" },\n\t\t\t\t\t\t\"&:hover fieldset\": { borderColor: \"rgba(255, 255, 255, 0.7)\" },\n\t\t\t\t\t\t\"&.Mui-focused fieldset\": { borderColor: theme.palette.common.white },\n\t\t\t\t\t},\n\t\t\t\t\t\"& .MuiSelect-select\": {\n\t\t\t\t\t\tcolor: theme.palette.common.white,\n\t\t\t\t\t},\n\t\t\t\t\t\"& .MuiSvgIcon-root\": { color: theme.palette.common.white },\n\t\t\t\t})}\n\t\t\t\tclassName={className}\n\t\t\t>\n\t\t\t\t<InputLabel id=\"actor-selector-label\">Application</InputLabel>\n\t\t\t\t<Select\n\t\t\t\t\tlabelId=\"actor-selector-label\"\n\t\t\t\t\tvalue={actorName}\n\t\t\t\t\tonChange={(e) => initiateSwitch(e.target.value)}\n\t\t\t\t\tlabel=\"Application\"\n\t\t\t\t\tdata-testid={testId}\n\t\t\t\t>\n\t\t\t\t\t{applications.map((app) => (\n\t\t\t\t\t\t<MenuItem key={app.name} value={app.name}>\n\t\t\t\t\t\t\t{app.name}\n\t\t\t\t\t\t</MenuItem>\n\t\t\t\t\t))}\n\t\t\t\t</Select>\n\t\t\t</FormControl>\n\n\t\t\t{/* Confirmation dialog for realm change */}\n\t\t\t<ActorSwitchDialog\n\t\t\t\topen={!!pendingSwitch}\n\t\t\t\tcurrentActor={actorName}\n\t\t\t\ttargetActor={pendingSwitch?.targetActor ?? \"\"}\n\t\t\t\tcurrentRealm={application.authentication?.realm}\n\t\t\t\ttargetRealm={pendingSwitch?.targetRealm}\n\t\t\t\tonConfirm={confirmSwitch}\n\t\t\t\tonCancel={cancelSwitch}\n\t\t\t/>\n\t\t</>\n\t);\n}\n","/**\n * LocaleSwitcher — optional AppBar dropdown for changing the active locale.\n *\n * Only renders when more than one locale is configured. Uses the locale context\n * from `@judo/i18n` to get/set the active locale.\n */\n\nimport LanguageIcon from \"@mui/icons-material/Language\";\nimport { IconButton, Menu, MenuItem, Tooltip, Typography } from \"@mui/material\";\nimport { useCallback, useState } from \"react\";\nimport type { MouseEvent } from \"react\";\n\nimport { useLocaleOptional } from \"@judo/i18n\";\n\n/**\n * Locale switcher dropdown for the application bar.\n *\n * Renders a globe icon button that opens a dropdown of available locales.\n * Only renders if there are 2+ locales configured in the I18nProvider.\n * If used outside I18nProvider, renders nothing.\n */\nexport function LocaleSwitcher() {\n\tconst localeCtx = useLocaleOptional();\n\tconst [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n\n\tconst handleOpen = useCallback((event: MouseEvent<HTMLElement>) => {\n\t\tsetAnchorEl(event.currentTarget);\n\t}, []);\n\n\tconst handleClose = useCallback(() => {\n\t\tsetAnchorEl(null);\n\t}, []);\n\n\tconst handleSelect = useCallback(\n\t\tasync (locale: string) => {\n\t\t\tsetAnchorEl(null);\n\t\t\tif (localeCtx) {\n\t\t\t\tawait localeCtx.setLocale(locale);\n\t\t\t}\n\t\t},\n\t\t[localeCtx]\n\t);\n\n\t// Don't render if no locale context or only one locale\n\tif (!localeCtx) return null;\n\tconst localeEntries = Object.entries(localeCtx.locales);\n\tif (localeEntries.length < 2) return null;\n\n\tconst currentLabel = localeCtx.locales[localeCtx.locale] ?? localeCtx.locale;\n\n\treturn (\n\t\t<>\n\t\t\t<Tooltip title={currentLabel}>\n\t\t\t\t<IconButton color=\"inherit\" onClick={handleOpen} data-testid=\"locale-switcher\" aria-label=\"Change locale\">\n\t\t\t\t\t<LanguageIcon />\n\t\t\t\t</IconButton>\n\t\t\t</Tooltip>\n\t\t\t<Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose} data-testid=\"locale-switcher::menu\">\n\t\t\t\t{localeEntries.map(([code, label]) => (\n\t\t\t\t\t<MenuItem\n\t\t\t\t\t\tkey={code}\n\t\t\t\t\t\tselected={code === localeCtx.locale}\n\t\t\t\t\t\tonClick={() => handleSelect(code)}\n\t\t\t\t\t\tdata-testid={`locale-switcher::option::${code}`}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Typography variant=\"body2\">{label}</Typography>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t))}\n\t\t\t</Menu>\n\t\t</>\n\t);\n}\n\nexport type LocaleSwitcherProps = Record<string, never>;\n","import { IconRenderer } from \"@judo/components\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { Action, NavigationItem } from \"@judo/model-api\";\nimport { getNavItemTestId } from \"@judo/test-ids\";\nimport ExpandMoreIcon from \"@mui/icons-material/ExpandMore\";\nimport FolderIcon from \"@mui/icons-material/Folder\";\nimport { Badge, Button, ListItemIcon, ListItemText, Menu, MenuItem } from \"@mui/material\";\nimport { type MouseEvent, useState } from \"react\";\nimport { useLocation, useNavigate } from \"react-router\";\nimport { useNavigationBadge } from \"../hooks/use-navigation-badge\";\nimport { getRouteForPage } from \"./navigation-utils\";\n\nexport interface HorizontalNavigationItemProps {\n\t/** The navigation item model object */\n\titem: NavigationItem;\n\t/** Depth of this item in the menu tree (0 = top-level) */\n\tdepth: number;\n\t/** Actions from NavigationController for resolving menu operations */\n\tnavigationActions?: Action[];\n\t/** Callback to dispatch a menu operation action */\n\tonMenuAction?: (action: Action) => Promise<void>;\n}\n\n/**\n * Renders a single item in the horizontal navigation bar.\n *\n * Top-level items (depth 0) render as buttons in the toolbar.\n * Nested items render as menu items in dropdown menus.\n * Supports N-deep nesting via cascading sub-menus.\n */\nexport function HorizontalNavigationItem({\n\titem,\n\tdepth,\n\tnavigationActions,\n\tonMenuAction,\n}: HorizontalNavigationItemProps) {\n\tconst navigate = useNavigate();\n\tconst location = useLocation();\n\tconst badge = useNavigationBadge(item[\"xmi:id\"] ?? \"\");\n\tconst { label } = useModelLabel(item);\n\n\tconst [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n\tconst open = Boolean(anchorEl);\n\n\tconst hasChildren = item.items && item.items.length > 0;\n\tconst targetRoute = item.target ? getRouteForPage(item.target) : undefined;\n\tconst isMenuOperation = !!item.actionDefinition;\n\tconst isActive = targetRoute ? location.pathname.includes(targetRoute) : false;\n\tconst testId = getNavItemTestId(item);\n\n\tconst handleOpen = (event: MouseEvent<HTMLElement>) => {\n\t\tsetAnchorEl(event.currentTarget);\n\t};\n\n\tconst handleClose = () => {\n\t\tsetAnchorEl(null);\n\t};\n\n\tconst handleNavigate = () => {\n\t\tif (isMenuOperation && onMenuAction && navigationActions) {\n\t\t\tconst targetDefId = item.actionDefinition?.[\"xmi:id\"];\n\t\t\tif (targetDefId) {\n\t\t\t\tconst action = navigationActions.find((a) => {\n\t\t\t\t\tconst actionDef = a.actionDefinition;\n\t\t\t\t\tif (typeof actionDef === \"object\" && actionDef !== null) {\n\t\t\t\t\t\treturn actionDef[\"xmi:id\"] === targetDefId;\n\t\t\t\t\t}\n\t\t\t\t\treturn typeof actionDef === \"string\" && actionDef === targetDefId;\n\t\t\t\t});\n\t\t\t\tif (action) {\n\t\t\t\t\tonMenuAction(action);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (targetRoute) {\n\t\t\tnavigate(targetRoute);\n\t\t}\n\t\thandleClose();\n\t};\n\n\tconst iconElement = (\n\t\t<Badge badgeContent={badge?.count} color={badge?.color ?? \"primary\"} max={badge?.max ?? 99} invisible={!badge}>\n\t\t\t{item.icon ? <IconRenderer icon={item.icon} size=\"small\" /> : <FolderIcon fontSize=\"small\" />}\n\t\t</Badge>\n\t);\n\n\t// Top-level items render as toolbar buttons\n\tif (depth === 0) {\n\t\tif (hasChildren) {\n\t\t\treturn (\n\t\t\t\t<>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tcolor=\"inherit\"\n\t\t\t\t\t\tonClick={handleOpen}\n\t\t\t\t\t\tstartIcon={iconElement}\n\t\t\t\t\t\tendIcon={<ExpandMoreIcon />}\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\ttextTransform: \"none\",\n\t\t\t\t\t\t\tfontWeight: isActive ? 700 : 400,\n\t\t\t\t\t\t\topacity: isActive ? 1 : 0.85,\n\t\t\t\t\t\t}}\n\t\t\t\t\t\tdata-testid={testId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{label}\n\t\t\t\t\t</Button>\n\t\t\t\t\t<Menu\n\t\t\t\t\t\tanchorEl={anchorEl}\n\t\t\t\t\t\topen={open}\n\t\t\t\t\t\tonClose={handleClose}\n\t\t\t\t\t\tanchorOrigin={{ vertical: \"bottom\", horizontal: \"left\" }}\n\t\t\t\t\t\ttransformOrigin={{ vertical: \"top\", horizontal: \"left\" }}\n\t\t\t\t\t\tdata-testid={`${testId}::menu`}\n\t\t\t\t\t>\n\t\t\t\t\t\t{item.items?.map((child) => (\n\t\t\t\t\t\t\t<HorizontalNavigationSubItem\n\t\t\t\t\t\t\t\tkey={child[\"xmi:id\"] ?? child.name}\n\t\t\t\t\t\t\t\titem={child}\n\t\t\t\t\t\t\t\tonCloseAll={handleClose}\n\t\t\t\t\t\t\t\tnavigationActions={navigationActions}\n\t\t\t\t\t\t\t\tonMenuAction={onMenuAction}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Menu>\n\t\t\t\t</>\n\t\t\t);\n\t\t}\n\n\t\treturn (\n\t\t\t<Button\n\t\t\t\tcolor=\"inherit\"\n\t\t\t\tonClick={handleNavigate}\n\t\t\t\tstartIcon={iconElement}\n\t\t\t\tsx={{\n\t\t\t\t\ttextTransform: \"none\",\n\t\t\t\t\tfontWeight: isActive ? 700 : 400,\n\t\t\t\t\topacity: isActive ? 1 : 0.85,\n\t\t\t\t}}\n\t\t\t\tdata-testid={testId}\n\t\t\t>\n\t\t\t\t{label}\n\t\t\t</Button>\n\t\t);\n\t}\n\n\t// depth > 0: shouldn't happen at this level, use HorizontalNavigationSubItem\n\treturn null;\n}\n\n// --- Sub-item for nested dropdown levels ---\n\ninterface HorizontalNavigationSubItemProps {\n\titem: NavigationItem;\n\tonCloseAll: () => void;\n\t/** Actions from NavigationController for resolving menu operations */\n\tnavigationActions?: Action[];\n\t/** Callback to dispatch a menu operation action */\n\tonMenuAction?: (action: Action) => Promise<void>;\n}\n\n/**\n * Renders a nested navigation item inside a dropdown menu.\n * Supports N-deep nesting by opening a sub-menu on hover/click.\n */\nfunction HorizontalNavigationSubItem({\n\titem,\n\tonCloseAll,\n\tnavigationActions,\n\tonMenuAction,\n}: HorizontalNavigationSubItemProps) {\n\tconst navigate = useNavigate();\n\tconst location = useLocation();\n\tconst badge = useNavigationBadge(item[\"xmi:id\"] ?? \"\");\n\tconst { label } = useModelLabel(item);\n\n\tconst [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n\tconst open = Boolean(anchorEl);\n\n\tconst hasChildren = item.items && item.items.length > 0;\n\tconst targetRoute = item.target ? getRouteForPage(item.target) : undefined;\n\tconst isMenuOperation = !!item.actionDefinition;\n\tconst isActive = targetRoute ? location.pathname.includes(targetRoute) : false;\n\tconst testId = getNavItemTestId(item);\n\n\tconst handleOpen = (event: MouseEvent<HTMLElement>) => {\n\t\tsetAnchorEl(event.currentTarget);\n\t};\n\n\tconst handleClose = () => {\n\t\tsetAnchorEl(null);\n\t};\n\n\tconst handleNavigate = () => {\n\t\tif (isMenuOperation && onMenuAction && navigationActions) {\n\t\t\tconst targetDefId = item.actionDefinition?.[\"xmi:id\"];\n\t\t\tif (targetDefId) {\n\t\t\t\tconst action = navigationActions.find((a) => {\n\t\t\t\t\tconst actionDef = a.actionDefinition;\n\t\t\t\t\tif (typeof actionDef === \"object\" && actionDef !== null) {\n\t\t\t\t\t\treturn actionDef[\"xmi:id\"] === targetDefId;\n\t\t\t\t\t}\n\t\t\t\t\treturn typeof actionDef === \"string\" && actionDef === targetDefId;\n\t\t\t\t});\n\t\t\t\tif (action) {\n\t\t\t\t\tonMenuAction(action);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (targetRoute) {\n\t\t\tnavigate(targetRoute);\n\t\t}\n\t\tonCloseAll();\n\t};\n\n\tconst iconElement = (\n\t\t<Badge badgeContent={badge?.count} color={badge?.color ?? \"primary\"} max={badge?.max ?? 99} invisible={!badge}>\n\t\t\t{item.icon ? <IconRenderer icon={item.icon} size=\"small\" /> : <FolderIcon fontSize=\"small\" />}\n\t\t</Badge>\n\t);\n\n\tif (hasChildren) {\n\t\treturn (\n\t\t\t<>\n\t\t\t\t<MenuItem onClick={handleOpen} selected={isActive} data-testid={testId}>\n\t\t\t\t\t<ListItemIcon>{iconElement}</ListItemIcon>\n\t\t\t\t\t<ListItemText>{label}</ListItemText>\n\t\t\t\t\t<ExpandMoreIcon fontSize=\"small\" sx={{ ml: 1, transform: \"rotate(-90deg)\" }} />\n\t\t\t\t</MenuItem>\n\t\t\t\t<Menu\n\t\t\t\t\tanchorEl={anchorEl}\n\t\t\t\t\topen={open}\n\t\t\t\t\tonClose={handleClose}\n\t\t\t\t\tanchorOrigin={{ vertical: \"top\", horizontal: \"right\" }}\n\t\t\t\t\ttransformOrigin={{ vertical: \"top\", horizontal: \"left\" }}\n\t\t\t\t\tdata-testid={`${testId}::menu`}\n\t\t\t\t>\n\t\t\t\t\t{item.items?.map((child) => (\n\t\t\t\t\t\t<HorizontalNavigationSubItem\n\t\t\t\t\t\t\tkey={child[\"xmi:id\"] ?? child.name}\n\t\t\t\t\t\t\titem={child}\n\t\t\t\t\t\t\tonCloseAll={() => {\n\t\t\t\t\t\t\t\thandleClose();\n\t\t\t\t\t\t\t\tonCloseAll();\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\tnavigationActions={navigationActions}\n\t\t\t\t\t\t\tonMenuAction={onMenuAction}\n\t\t\t\t\t\t/>\n\t\t\t\t\t))}\n\t\t\t\t</Menu>\n\t\t\t</>\n\t\t);\n\t}\n\n\treturn (\n\t\t<MenuItem onClick={handleNavigate} selected={isActive} data-testid={testId}>\n\t\t\t<ListItemIcon>{iconElement}</ListItemIcon>\n\t\t\t<ListItemText>{label}</ListItemText>\n\t\t</MenuItem>\n\t);\n}\n","import { useCustomizationsOptional } from \"@judo/core\";\nimport type { NavigationController } from \"@judo/model-api\";\nimport { Box } from \"@mui/material\";\nimport { useMemo } from \"react\";\nimport { HorizontalNavigationItem } from \"./HorizontalNavigationItem\";\nimport { useMenuOperationDispatch } from \"./use-menu-operation-dispatch\";\n\nexport interface HorizontalNavigationProps {\n\t/** The navigation controller from the application model */\n\tnavigationController?: NavigationController;\n}\n\n/**\n * Horizontal navigation bar rendering menu items as a row of buttons\n * in the application toolbar.\n *\n * Supports N-deep menus via cascading dropdown sub-menus.\n * Does not include search functionality (search is only for vertical/drawer mode).\n */\nexport function HorizontalNavigation({ navigationController }: HorizontalNavigationProps) {\n\tconst menuCustomizer = useCustomizationsOptional()?.getMenuCustomizer();\n\tconst items = useMemo(() => {\n\t\tconst raw = navigationController?.items ?? [];\n\t\treturn menuCustomizer ? menuCustomizer(raw) : raw;\n\t}, [navigationController?.items, menuCustomizer]);\n\n\t// Menu operation dispatch for items with actionDefinition\n\tconst { dispatchMenuAction } = useMenuOperationDispatch();\n\tconst navigationActions = navigationController?.actions;\n\n\treturn (\n\t\t<Box\n\t\t\tcomponent=\"nav\"\n\t\t\tsx={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tgap: 0.5,\n\t\t\t\tflexWrap: \"wrap\",\n\t\t\t}}\n\t\t\tdata-testid=\"horizontal-navigation\"\n\t\t>\n\t\t\t{items.map((item) => (\n\t\t\t\t<HorizontalNavigationItem\n\t\t\t\t\tkey={item[\"xmi:id\"] ?? item.name}\n\t\t\t\t\titem={item}\n\t\t\t\t\tdepth={0}\n\t\t\t\t\tnavigationActions={navigationActions}\n\t\t\t\t\tonMenuAction={dispatchMenuAction}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</Box>\n\t);\n}\n","import DarkModeIcon from \"@mui/icons-material/DarkMode\";\nimport LightModeIcon from \"@mui/icons-material/LightMode\";\nimport SettingsBrightnessIcon from \"@mui/icons-material/SettingsBrightness\";\nimport { IconButton, Tooltip } from \"@mui/material\";\nimport { useTheme } from \"../hooks/use-theme\";\n\nexport interface ThemeToggleProps {\n\tclassName?: string;\n}\n\n/**\n * Theme toggle button cycling through light/dark/system modes.\n * - Light: Forces light mode\n * - Dark: Forces dark mode\n * - System: Follows OS/browser preference\n */\nexport function ThemeToggle({ className }: ThemeToggleProps) {\n\tconst { config, setTheme } = useTheme();\n\tconst { mode, isSystemMode } = config;\n\n\tconst toggleMode = () => {\n\t\t// Cycle: light -> dark -> system -> light\n\t\tif (isSystemMode) {\n\t\t\t// From system mode -> light mode\n\t\t\tsetTheme({ mode: \"light\", __useSystemPreference: false } as any);\n\t\t} else if (mode === \"light\") {\n\t\t\t// From light -> dark\n\t\t\tsetTheme({ mode: \"dark\", __useSystemPreference: false } as any);\n\t\t} else {\n\t\t\t// From dark -> system mode\n\t\t\t// Determine system preference\n\t\t\tconst systemMode =\n\t\t\t\ttypeof window !== \"undefined\" &&\n\t\t\t\ttypeof window.matchMedia === \"function\" &&\n\t\t\t\twindow.matchMedia(\"(prefers-color-scheme: dark)\").matches\n\t\t\t\t\t? \"dark\"\n\t\t\t\t\t: \"light\";\n\t\t\tsetTheme({ mode: systemMode, __useSystemPreference: true } as any);\n\t\t}\n\t};\n\n\tconst getTooltip = () => {\n\t\tif (isSystemMode) return \"Switch to light mode\";\n\t\tif (mode === \"light\") return \"Switch to dark mode\";\n\t\treturn \"Switch to system preference\";\n\t};\n\n\tconst getIcon = () => {\n\t\t// Show next mode icon (what clicking will activate)\n\t\tif (isSystemMode) return <LightModeIcon />;\n\t\tif (mode === \"light\") return <DarkModeIcon />;\n\t\treturn <SettingsBrightnessIcon />;\n\t};\n\n\treturn (\n\t\t<Tooltip title={getTooltip()}>\n\t\t\t<IconButton color=\"inherit\" onClick={toggleMode} className={className} data-testid=\"theme-toggle\">\n\t\t\t\t{getIcon()}\n\t\t\t</IconButton>\n\t\t</Tooltip>\n\t);\n}\n","import type { HeroComponentProps } from \"@judo/model-api\";\nimport { getUserMenuTestId } from \"@judo/test-ids\";\nimport LogoutIcon from \"@mui/icons-material/Logout\";\nimport PersonIcon from \"@mui/icons-material/Person\";\nimport SettingsIcon from \"@mui/icons-material/Settings\";\nimport {\n\tAvatar,\n\tBox,\n\tDivider,\n\tIconButton,\n\tListItemIcon,\n\tListItemText,\n\tMenu,\n\tMenuItem,\n\tTypography,\n} from \"@mui/material\";\nimport { useState } from \"react\";\nimport { useTranslation } from \"react-i18next\";\n\n/**\n * Default hero component rendered in the AppBar for authenticated actors.\n *\n * Displays the principal's avatar button that opens a dropdown with\n * profile info and sign-out.\n *\n * Can be replaced via `CustomizationsConfig.heroComponent`.\n */\nexport function DefaultHeroComponent({\n\tprincipal,\n\tactorName: _actorName,\n\tsignOut,\n\tonNavigateToProfile,\n\tonNavigateToSettings,\n\tprofilePictureUrl,\n}: HeroComponentProps) {\n\tconst { t } = useTranslation();\n\tconst [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n\tconst displayName = principal?.preferredUsername ?? principal?.name ?? \"User\";\n\tconst initial = (displayName[0] ?? \"?\").toUpperCase();\n\n\tconst handleLogout = () => {\n\t\tsetAnchorEl(null);\n\t\tsignOut();\n\t};\n\n\tconst handleProfile = () => {\n\t\tsetAnchorEl(null);\n\t\tonNavigateToProfile?.();\n\t};\n\n\tconst handleSettings = () => {\n\t\tsetAnchorEl(null);\n\t\tonNavigateToSettings();\n\t};\n\n\tconst triggerTestId = getUserMenuTestId(\"trigger\");\n\n\treturn (\n\t\t<>\n\t\t\t<IconButton onClick={(e) => setAnchorEl(e.currentTarget)} color=\"inherit\" data-testid={triggerTestId}>\n\t\t\t\t<Avatar src={profilePictureUrl} sx={{ width: 32, height: 32 }}>\n\t\t\t\t\t{initial}\n\t\t\t\t</Avatar>\n\t\t\t</IconButton>\n\n\t\t\t<Menu\n\t\t\t\tanchorEl={anchorEl}\n\t\t\t\topen={!!anchorEl}\n\t\t\t\tonClose={() => setAnchorEl(null)}\n\t\t\t\tdata-testid={getUserMenuTestId(\"menu\")}\n\t\t\t>\n\t\t\t\t{/* User Info Header */}\n\t\t\t\t<Box sx={{ px: 2, py: 1 }}>\n\t\t\t\t\t<Typography variant=\"subtitle1\">{displayName}</Typography>\n\t\t\t\t\t{principal?.email && (\n\t\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t\t{principal.email}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t)}\n\t\t\t\t</Box>\n\n\t\t\t\t<Divider />\n\n\t\t\t\t{/* Profile Link */}\n\t\t\t\t{onNavigateToProfile && (\n\t\t\t\t\t<MenuItem onClick={handleProfile} data-testid={getUserMenuTestId(\"profile\")}>\n\t\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t\t<PersonIcon fontSize=\"small\" />\n\t\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t\t<ListItemText>{t(\"system.auth.profile\", { defaultValue: \"Profile\" })}</ListItemText>\n\t\t\t\t\t</MenuItem>\n\t\t\t\t)}\n\n\t\t\t\t{/* Settings Link — always visible */}\n\t\t\t\t<MenuItem onClick={handleSettings} data-testid={getUserMenuTestId(\"settings\")}>\n\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t<SettingsIcon fontSize=\"small\" />\n\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t<ListItemText>{t(\"system.common.settings\", { defaultValue: \"Settings\" })}</ListItemText>\n\t\t\t\t</MenuItem>\n\n\t\t\t\t<Divider />\n\n\t\t\t\t{/* Logout */}\n\t\t\t\t<MenuItem onClick={handleLogout} data-testid={getUserMenuTestId(\"logout\")}>\n\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t<LogoutIcon fontSize=\"small\" />\n\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t<ListItemText>{t(\"system.auth.logout\", { defaultValue: \"Log Out\" })}</ListItemText>\n\t\t\t\t</MenuItem>\n\t\t\t</Menu>\n\t\t</>\n\t);\n}\n","import { useAuth } from \"@judo/auth\";\nimport { useApplication, useCustomizationsOptional } from \"@judo/core\";\nimport type { AttributeType, MenuLayout, NavigationController } from \"@judo/model-api\";\nimport { MenuLayout as MenuLayoutEnum } from \"@judo/model-api\";\nimport MenuIcon from \"@mui/icons-material/Menu\";\nimport { Box, IconButton, AppBar as MuiAppBar, Toolbar, Typography } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\nimport { useCallback, useMemo } from \"react\";\nimport { useNavigate } from \"react-router\";\nimport { ActorSelector } from \"../actors/ActorSelector\";\nimport { LocaleSwitcher } from \"../locale/LocaleSwitcher\";\nimport { HorizontalNavigation } from \"../navigation/HorizontalNavigation\";\nimport { getRouteForPage } from \"../navigation/navigation-utils\";\nimport { ThemeToggle } from \"../theme/ThemeToggle\";\nimport { DefaultHeroComponent } from \"../user/DefaultHeroComponent\";\n\nexport interface AppBarProps {\n\tdrawerWidth: number;\n\t/** Click handler for the hamburger menu button. When undefined, the button is hidden (horizontal mode). */\n\tonMenuClick?: () => void;\n\tlogo?: ReactNode;\n\textra?: ReactNode;\n\t/** Current menu layout mode */\n\tmenuLayout?: MenuLayout;\n\t/** Navigation controller for horizontal menu rendering */\n\tnavigationController?: NavigationController;\n}\n\n/**\n * Application header bar with navigation toggle, actor selector, and user menu.\n * In horizontal mode, embeds the navigation items directly in the toolbar.\n */\nexport function AppBar({ drawerWidth, onMenuClick, logo, extra, menuLayout, navigationController }: AppBarProps) {\n\tconst { application, applications } = useApplication();\n\tconst { requiresAuth, principal, actorName, signoutRedirect } = useAuth();\n\tconst customizations = useCustomizationsOptional();\n\tconst HeroComponent = customizations?.getHeroComponent();\n\tconst hasMultipleActors = applications.length > 1;\n\tconst isHorizontal = menuLayout === MenuLayoutEnum.HORIZONTAL;\n\tconst navigate = useNavigate();\n\n\t// Resolve profile navigation from the model's profilePage\n\tconst profileRoute = useMemo(\n\t\t() => (application.profilePage ? getRouteForPage(application.profilePage) : undefined),\n\t\t[application.profilePage]\n\t);\n\n\tconst onNavigateToProfile = useCallback(() => {\n\t\tif (profileRoute) {\n\t\t\tnavigate(profileRoute);\n\t\t}\n\t}, [navigate, profileRoute]);\n\n\t// Settings navigation — always enabled (route is always registered)\n\tconst onNavigateToSettings = useCallback(() => {\n\t\tnavigate(\"/settings\");\n\t}, [navigate]);\n\n\t// Resolve profile picture URL from the principal ClassType's isProfilePicture attribute\n\tconst profilePictureUrl = useMemo(() => {\n\t\tconst principalType = application.principal;\n\t\tif (!principalType?.attributes || !principal) return undefined;\n\n\t\tconst pictureAttr = principalType.attributes.find(\n\t\t\t(attr: AttributeType) => String(attr.isProfilePicture) === \"true\"\n\t\t);\n\t\tif (!pictureAttr) return undefined;\n\n\t\tconst value = principal[pictureAttr.name];\n\t\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n\t}, [application.principal, principal]);\n\n\tconst heroProps = {\n\t\tprincipal,\n\t\tactorName,\n\t\tsignOut: signoutRedirect,\n\t\tonNavigateToSettings,\n\t\tprofilePictureUrl,\n\t\t...(profileRoute ? { onNavigateToProfile } : {}),\n\t};\n\n\treturn (\n\t\t<MuiAppBar\n\t\t\tposition=\"fixed\"\n\t\t\tsx={{\n\t\t\t\twidth: `calc(100% - ${drawerWidth}px)`,\n\t\t\t\tml: `${drawerWidth}px`,\n\t\t\t\ttransition: \"width 0.2s, margin 0.2s\",\n\t\t\t}}\n\t\t\tdata-testid=\"app-bar\"\n\t\t>\n\t\t\t<Toolbar>\n\t\t\t\t{/* Menu Toggle (hidden in horizontal mode) */}\n\t\t\t\t{onMenuClick && (\n\t\t\t\t\t<IconButton\n\t\t\t\t\t\tedge=\"start\"\n\t\t\t\t\t\tcolor=\"inherit\"\n\t\t\t\t\t\tonClick={onMenuClick}\n\t\t\t\t\t\tsx={{ mr: 2 }}\n\t\t\t\t\t\tdata-testid=\"app-bar::menu-toggle\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<MenuIcon />\n\t\t\t\t\t</IconButton>\n\t\t\t\t)}\n\n\t\t\t\t{/* Logo */}\n\t\t\t\t{logo ?? (\n\t\t\t\t\t<Typography variant=\"h6\" noWrap component=\"div\">\n\t\t\t\t\t\t{application.name}\n\t\t\t\t\t</Typography>\n\t\t\t\t)}\n\n\t\t\t\t{/* Actor Selector (if multi-actor) */}\n\t\t\t\t{hasMultipleActors && (\n\t\t\t\t\t<Box sx={{ ml: 2 }}>\n\t\t\t\t\t\t<ActorSelector />\n\t\t\t\t\t</Box>\n\t\t\t\t)}\n\n\t\t\t\t{/* Horizontal Navigation (between logo/actor and spacer) */}\n\t\t\t\t{isHorizontal && (\n\t\t\t\t\t<Box sx={{ ml: 2 }}>\n\t\t\t\t\t\t<HorizontalNavigation navigationController={navigationController} />\n\t\t\t\t\t</Box>\n\t\t\t\t)}\n\n\t\t\t\t{/* Spacer */}\n\t\t\t\t<Box sx={{ flexGrow: 1 }} />\n\n\t\t\t\t{/* Extra items */}\n\t\t\t\t{extra}\n\n\t\t\t\t{/* Locale Switcher */}\n\t\t\t\t<LocaleSwitcher />\n\n\t\t\t\t{/* Theme Toggle */}\n\t\t\t\t<ThemeToggle />\n\n\t\t\t\t{/* Hero Component (only if auth required) */}\n\t\t\t\t{requiresAuth && (HeroComponent ? <HeroComponent {...heroProps} /> : <DefaultHeroComponent {...heroProps} />)}\n\t\t\t</Toolbar>\n\t\t</MuiAppBar>\n\t);\n}\n","import { usePageTitle } from \"@judo/components\";\nimport { useNavigation } from \"@judo/core\";\nimport { useModelLabel } from \"@judo/i18n\";\nimport type { PageDefinition } from \"@judo/model-api\";\nimport { getBreadcrumbTestId } from \"@judo/test-ids\";\nimport { Link, Breadcrumbs as MuiBreadcrumbs, Typography } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\nimport { useNavigate } from \"react-router\";\n\nexport interface BreadcrumbsProps {\n\tclassName?: string;\n}\n\n/**\n * Breadcrumb navigation showing page stack.\n */\nexport function Breadcrumbs({ className }: BreadcrumbsProps) {\n\tconst { pageStack, currentPage, goBack } = useNavigation();\n\tconst navigate = useNavigate();\n\tconst { t } = useTranslation();\n\n\tif (pageStack.length === 0 && !currentPage) {\n\t\treturn null;\n\t}\n\n\tconst testId = getBreadcrumbTestId(0);\n\n\treturn (\n\t\t<MuiBreadcrumbs sx={{ mb: 2 }} className={className} data-testid={testId}>\n\t\t\t{/* Home link */}\n\t\t\t<Link\n\t\t\t\tcomponent=\"button\"\n\t\t\t\tvariant=\"body2\"\n\t\t\t\tonClick={() => navigate(\"/\")}\n\t\t\t\tunderline=\"hover\"\n\t\t\t\tdata-testid={`${testId}::home`}\n\t\t\t>\n\t\t\t\t{t(\"system.nav.home\", { defaultValue: \"Home\" })}\n\t\t\t</Link>\n\n\t\t\t{/* Stack pages */}\n\t\t\t{pageStack.map((entry, index) => (\n\t\t\t\t<BreadcrumbLink\n\t\t\t\t\tkey={entry.pageDefinition[\"xmi:id\"]}\n\t\t\t\t\tpageDefinition={entry.pageDefinition}\n\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t// Navigate back to this point in stack\n\t\t\t\t\t\tconst stepsBack = pageStack.length - 1 - index;\n\t\t\t\t\t\tfor (let i = 0; i < stepsBack; i++) {\n\t\t\t\t\t\t\tgoBack();\n\t\t\t\t\t\t}\n\t\t\t\t\t}}\n\t\t\t\t\ttestId={`${testId}::${entry.pageDefinition.name}`}\n\t\t\t\t/>\n\t\t\t))}\n\n\t\t\t{/* Current page */}\n\t\t\t{currentPage && <BreadcrumbCurrent pageDefinition={currentPage} testId={`${testId}::current`} />}\n\t\t</MuiBreadcrumbs>\n\t);\n}\n\n/** Helper component to render a breadcrumb link with translated label. */\nfunction BreadcrumbLink({\n\tpageDefinition,\n\tonClick,\n\ttestId,\n}: {\n\tpageDefinition: PageDefinition;\n\tonClick: () => void;\n\ttestId: string;\n}) {\n\tconst { label } = useModelLabel(pageDefinition);\n\treturn (\n\t\t<Link component=\"button\" variant=\"body2\" onClick={onClick} underline=\"hover\" data-testid={testId}>\n\t\t\t{label}\n\t\t</Link>\n\t);\n}\n\n/** Helper component to render the current breadcrumb with dynamic title support. */\nfunction BreadcrumbCurrent({ pageDefinition, testId }: { pageDefinition: PageDefinition; testId: string }) {\n\tconst { title } = usePageTitle(pageDefinition);\n\treturn (\n\t\t<Typography color=\"text.primary\" variant=\"body2\" data-testid={testId}>\n\t\t\t{title}\n\t\t</Typography>\n\t);\n}\n","import { useApplicationOptional, useCustomizationsOptional } from \"@judo/core\";\nimport { Box, Typography } from \"@mui/material\";\n\n/**\n * Application footer rendered at the bottom of the shell layout.\n *\n * By default shows \"© {year} {modelName}\".\n * When `footerText` is configured in `CustomizationsConfig`, uses that instead.\n * Supports static strings and dynamic functions.\n */\nexport function Footer() {\n\tconst footerText = useCustomizationsOptional()?.getFooterText();\n\tconst modelName = useApplicationOptional()?.application?.modelName;\n\n\tconst resolvedText =\n\t\tfooterText !== undefined\n\t\t\t? typeof footerText === \"function\"\n\t\t\t\t? footerText()\n\t\t\t\t: footerText\n\t\t\t: `© ${new Date().getFullYear()} ${modelName ?? \"\"}`.trim();\n\n\treturn (\n\t\t<Box\n\t\t\tcomponent=\"footer\"\n\t\t\tsx={{\n\t\t\t\tpy: 1.5,\n\t\t\t\tpx: 3,\n\t\t\t\ttextAlign: \"center\",\n\t\t\t\tborderTop: 1,\n\t\t\t\tborderColor: \"divider\",\n\t\t\t\tbgcolor: \"background.default\",\n\t\t\t}}\n\t\t\tdata-testid=\"app-shell-footer\"\n\t\t>\n\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t{resolvedText}\n\t\t\t</Typography>\n\t\t</Box>\n\t);\n}\n","import { useActionDispatcher, useApi } from \"@judo/actions\";\nimport { ButtonGroupRenderer, PageRenderer, usePageTitle } from \"@judo/components\";\nimport {\n\ttype DialogCloseResult,\n\tDispatchProvider,\n\tPageActionOverridesProvider,\n\tPageProvider,\n\tSelectorSelectionProvider,\n\tValidationProvider,\n\tVisualPropertiesProvider,\n\tuseApplication,\n\tuseDataStore,\n\tuseNavigation,\n\tuseResolvedPageActionOverrides,\n\tuseSelectorSelectionOptional,\n\tuseValidationContextOptional,\n} from \"@judo/core\";\nimport { useNotifications } from \"@judo/feedback\";\nimport type { ButtonGroup as ButtonGroupElement, PageContainer } from \"@judo/model-api\";\nimport { DialogSize, PageContainerType, type PageDefinition } from \"@judo/model-api\";\nimport { Box, Dialog, DialogActions, DialogContent, DialogTitle } from \"@mui/material\";\nimport { useCallback, useMemo } from \"react\";\n\n/**\n * Map DialogSize enum to MUI maxWidth prop.\n */\nfunction getMaxWidth(size: DialogSize): \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\" {\n\tswitch (size) {\n\t\tcase DialogSize.XS:\n\t\t\treturn \"xs\";\n\t\tcase DialogSize.SM:\n\t\t\treturn \"sm\";\n\t\tcase DialogSize.MD:\n\t\t\treturn \"md\";\n\t\tcase DialogSize.LG:\n\t\t\treturn \"lg\";\n\t\tcase DialogSize.XL:\n\t\t\treturn \"xl\";\n\t\tdefault:\n\t\t\treturn \"md\";\n\t}\n}\n\n/**\n * Generate a stable transfer ID for a dialog page based on its definition and params.\n */\nfunction generateDialogEntityId(pageId: string, params?: Record<string, unknown>): string {\n\t// For CREATE forms, use a stable ID based on pageId\n\t// We don't use Date.now() to ensure the ID stays consistent across re-renders\n\tif (params?.isCreate) {\n\t\treturn `dialog::create::${pageId}`;\n\t}\n\n\t// For VIEW/EDIT forms, use the transfer's signed identifier if available\n\tconst transfer = params?.transfer as { __signedIdentifier?: string } | undefined;\n\tif (transfer?.__signedIdentifier) {\n\t\treturn `dialog::transfer::${transfer.__signedIdentifier}`;\n\t}\n\n\t// Fallback\n\treturn `dialog::${pageId}`;\n}\n\n/**\n * Props for DialogContentWithValidation component.\n */\ninterface DialogContentWithValidationProps {\n\tpageDefinition: PageDefinition;\n\ttransferId: string | null;\n\tparams?: Record<string, unknown>;\n\tactionButtonGroups: ButtonGroupElement[];\n\tnavigation: ReturnType<typeof useNavigation>;\n\tdataStore: ReturnType<typeof useDataStore>;\n\tapplication: ReturnType<typeof useApplication>;\n\tapi: ReturnType<typeof useApi>;\n\tnotifications: ReturnType<typeof useNotifications>;\n\ttransfer?: Record<string, unknown>;\n\tcloseDialog: (result?: DialogCloseResult) => void;\n\tisCreate: boolean;\n\tisEager: boolean;\n\trelation?: unknown;\n\townerTransfer?: unknown;\n\t/** Parent transfer ID for eager creates (where to add created transfer) */\n\tparentTransferId?: string;\n\t/** Relation name for eager creates (which property to add to) */\n\trelationName?: string;\n}\n\n/**\n * Inner component that has access to ValidationContext.\n * This pattern allows us to pass validation to the action dispatcher.\n */\nfunction DialogContentWithValidation({\n\tpageDefinition,\n\ttransferId,\n\tparams: _params,\n\tactionButtonGroups,\n\tnavigation,\n\tdataStore,\n\tapplication,\n\tapi,\n\tnotifications,\n\ttransfer,\n\tcloseDialog,\n\tisCreate,\n\tisEager,\n\trelation,\n\townerTransfer,\n\tparentTransferId,\n\trelationName,\n}: DialogContentWithValidationProps) {\n\t// Get validation context (now available from ValidationProvider)\n\tconst validation = useValidationContextOptional();\n\n\t// Create validation object that matches the expected interface\n\tconst validationContext = useMemo(() => {\n\t\tif (!validation) return undefined;\n\t\treturn {\n\t\t\tsetError: validation.setError,\n\t\t\tsetErrors: (errors: Record<string, string>) => {\n\t\t\t\tvalidation.setErrors(errors);\n\t\t\t\t// Touch all fields that have errors so they display\n\t\t\t\tfor (const fieldId of Object.keys(errors)) {\n\t\t\t\t\tvalidation.touch(fieldId);\n\t\t\t\t}\n\t\t\t},\n\t\t\tclearErrors: validation.clearErrors,\n\t\t\tclearError: validation.clearError,\n\t\t};\n\t}, [validation]);\n\n\t// Get resolved page action overrides from customizations\n\tconst actionOverrides = useResolvedPageActionOverrides();\n\n\t// Set up action dispatcher with validation context\n\tconst { dispatch } = useActionDispatcher({\n\t\tnavigation,\n\t\tdata: dataStore,\n\t\tregistry: application,\n\t\tapi,\n\t\ttransfer,\n\t\tcloseDialog,\n\t\tnotifications,\n\t\tactionOverrides,\n\t\tadditionalContext: {\n\t\t\tpageTransferId: transferId,\n\t\t\tpageType: \"FORM\",\n\t\t\tisEditMode: true,\n\t\t\tisEager,\n\t\t\tvalidation: validationContext,\n\t\t\t// Always pass parentTransferId and relationName at top level for eager contexts.\n\t\t\t// useUpdateActionHandler needs these to write changes back to the parent transfer's\n\t\t\t// relation array instead of making REST calls.\n\t\t\t...(isEager && parentTransferId && { parentTransferId }),\n\t\t\t...(isEager && relationName && { relationName }),\n\t\t\t// Pass create dialog context for CreateActionHandler\n\t\t\tcreateDialog: isCreate\n\t\t\t\t? {\n\t\t\t\t\t\trelation,\n\t\t\t\t\t\townerTransfer,\n\t\t\t\t\t\tisEager,\n\t\t\t\t\t\t// For eager creates, include parent context\n\t\t\t\t\t\tparentTransferId,\n\t\t\t\t\t\trelationName,\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t\t},\n\t});\n\n\t// Access selector selection context to inject selected transfers into dispatch\n\tconst selectorSelection = useSelectorSelectionOptional();\n\n\t// Create a wrapper dispatch for page-level actions (dialog footer buttons)\n\t// For selector dialogs, inject ownerTransfer and selectedEntities from the selection context\n\tconst pageActionDispatch = useCallback(\n\t\t(action: Parameters<typeof dispatch>[0]) => {\n\t\t\tconst overrides: Record<string, unknown> = { isPageAction: true };\n\t\t\tif (selectorSelection) {\n\t\t\t\toverrides.ownerTransfer = selectorSelection.ownerTransfer;\n\t\t\t\tconst selected = selectorSelection.selectedTransfersRef.current;\n\t\t\t\toverrides.selectedEntities = selected;\n\t\t\t\t// Also inject singular selectedEntity for handlers that expect a single selection\n\t\t\t\t// (e.g., InputSelectorCallOperationActionHandler, AutocompleteSetActionHandler)\n\t\t\t\toverrides.selectedEntity = selected[0];\n\t\t\t}\n\t\t\treturn dispatch(action, overrides);\n\t\t},\n\t\t[dispatch, selectorSelection]\n\t);\n\n\t// Only VIEW pages use the edit-mode filter to show Save/Cancel when there\n\t// are unsaved changes. FORM pages (create dialogs) and TABLE pages (selector\n\t// dialogs) don't have edit-mode toggling - their buttons should always be visible.\n\tconst container = pageDefinition.container as PageContainer | undefined;\n\tconst isViewPage = container?.type === PageContainerType.VIEW;\n\n\treturn (\n\t\t<DispatchProvider dispatch={dispatch}>\n\t\t\t<DialogContent dividers sx={{ flex: 1, overflow: \"auto\" }}>\n\t\t\t\t<PageRenderer page={pageDefinition} />\n\t\t\t</DialogContent>\n\n\t\t\t{/* Dialog Actions (Footer) */}\n\t\t\t{actionButtonGroups.length > 0 && (\n\t\t\t\t<DialogActions data-testid={`page-dialog::${pageDefinition[\"xmi:id\"]}::actions`}>\n\t\t\t\t\t<Box sx={{ display: \"flex\", gap: 1, justifyContent: \"flex-end\" }}>\n\t\t\t\t\t\t{actionButtonGroups.map((group) => (\n\t\t\t\t\t\t\t<ButtonGroupRenderer\n\t\t\t\t\t\t\t\tkey={group[\"xmi:id\"]}\n\t\t\t\t\t\t\t\telement={group}\n\t\t\t\t\t\t\t\tpage={pageDefinition}\n\t\t\t\t\t\t\t\teditMode={isViewPage}\n\t\t\t\t\t\t\t\tonDispatch={pageActionDispatch}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t))}\n\t\t\t\t\t</Box>\n\t\t\t\t</DialogActions>\n\t\t\t)}\n\t\t</DispatchProvider>\n\t);\n}\n\n/**\n * PageDialogHost renders the dialog stack from NavigationContext.\n * Place this component near the root of your application layout.\n *\n * Renders ALL dialogs in the stack so that lower dialogs stay mounted\n * (preserving React state and data), while only the topmost is interactive.\n */\nexport function PageDialogHost() {\n\tconst navigation = useNavigation();\n\tconst { dialogStack, closeDialog } = navigation;\n\n\tif (dialogStack.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<>\n\t\t\t{dialogStack.map((dialogEntry, index) => (\n\t\t\t\t<SinglePageDialog\n\t\t\t\t\tkey={`${dialogEntry.pageDefinition[\"xmi:id\"]}::${index}`}\n\t\t\t\t\tdialog={dialogEntry}\n\t\t\t\t\tisTopmost={index === dialogStack.length - 1}\n\t\t\t\t\tnavigation={navigation}\n\t\t\t\t\tcloseDialog={closeDialog}\n\t\t\t\t/>\n\t\t\t))}\n\t\t</>\n\t);\n}\n\n/**\n * Props for SinglePageDialog.\n */\ninterface SinglePageDialogProps {\n\tdialog: {\n\t\tpageDefinition: PageDefinition;\n\t\tsize: DialogSize;\n\t\tparams?: Record<string, unknown>;\n\t};\n\tisTopmost: boolean;\n\tnavigation: ReturnType<typeof useNavigation>;\n\tcloseDialog: ReturnType<typeof useNavigation>[\"closeDialog\"];\n}\n\n/**\n * Renders a single dialog from the stack.\n * Non-topmost dialogs are rendered but visually hidden to preserve state.\n */\nfunction SinglePageDialog({ dialog, isTopmost, navigation, closeDialog }: SinglePageDialogProps) {\n\tconst application = useApplication();\n\tconst api = useApi();\n\tconst dataStore = useDataStore();\n\tconst notifications = useNotifications();\n\n\tconst { pageDefinition, size, params } = dialog;\n\n\t// Generate transfer ID for the dialog page\n\tconst transferId = useMemo(() => {\n\t\treturn generateDialogEntityId(pageDefinition[\"xmi:id\"], params);\n\t}, [pageDefinition, params]);\n\n\t// Extract transfer from dialog params (passed by openDialog callers)\n\tconst transfer = useMemo(() => {\n\t\tif (!params?.transfer) return undefined;\n\t\treturn params.transfer as Record<string, unknown>;\n\t}, [params?.transfer]);\n\n\t// Extract create dialog context from params\n\tconst isCreate = params?.isCreate === true;\n\tconst isEager = params?.isEager === true;\n\tconst relation = params?.relation;\n\tconst ownerTransfer = params?.ownerTransfer;\n\t// For eager creates, extract parent context to know where to add created transfer\n\tconst parentTransferId = params?.parentTransferId as string | undefined;\n\tconst relationName = params?.relationName as string | undefined;\n\n\t// Wrapper for MUI Dialog onClose - treat backdrop/escape clicks as cancellation\n\t// Only the topmost dialog should respond to backdrop/escape\n\tconst handleDialogClose = useCallback(() => {\n\t\tif (isTopmost) {\n\t\t\tcloseDialog({ type: \"cancelled\" });\n\t\t}\n\t}, [closeDialog, isTopmost]);\n\n\tconst maxWidth = getMaxWidth(size);\n\tconst container = pageDefinition.container as PageContainer;\n\tconst actionButtonGroups = container?.actionButtonGroups ?? [];\n\tconst isSelectorDialog = String(pageDefinition.isSelector) === \"true\";\n\n\t// Wrap content in SelectorSelectionProvider for selector dialogs\n\t// This enables the dialog footer buttons (Add/Set) to access the table selection\n\tconst wrapWithSelectorSelection = (children: React.ReactNode) =>\n\t\tisSelectorDialog ? (\n\t\t\t<SelectorSelectionProvider ownerTransfer={ownerTransfer}>{children}</SelectorSelectionProvider>\n\t\t) : (\n\t\t\tchildren\n\t\t);\n\n\treturn (\n\t\t<Dialog\n\t\t\topen={true}\n\t\t\tonClose={handleDialogClose}\n\t\t\tmaxWidth={maxWidth}\n\t\t\tfullWidth\n\t\t\tscroll=\"paper\"\n\t\t\tdata-testid={`page-dialog::${pageDefinition[\"xmi:id\"]}`}\n\t\t\t// Non-topmost dialogs are hidden but stay mounted to preserve React state\n\t\t\tsx={!isTopmost ? { visibility: \"hidden\", pointerEvents: \"none\" } : undefined}\n\t\t\t// Disable backdrop for non-topmost dialogs\n\t\t\tslotProps={!isTopmost ? { backdrop: { sx: { display: \"none\" } } } : undefined}\n\t\t\tPaperProps={{\n\t\t\t\tsx: {\n\t\t\t\t\tmaxHeight: \"90vh\",\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\tflexDirection: \"column\",\n\t\t\t\t},\n\t\t\t}}\n\t\t>\n\t\t\t{/* Dialog Title */}\n\t\t\t<TranslatedDialogTitle pageDefinition={pageDefinition} transferId={transferId} />\n\n\t\t\t{/* Content wrapped in PageProvider and ValidationProvider */}\n\t\t\t<PageProvider pageDefinition={pageDefinition} transferId={transferId} params={params} isDialog>\n\t\t\t\t<PageActionOverridesProvider>\n\t\t\t\t\t<VisualPropertiesProvider>\n\t\t\t\t\t\t<ValidationProvider>\n\t\t\t\t\t\t\t{wrapWithSelectorSelection(\n\t\t\t\t\t\t\t\t<DialogContentWithValidation\n\t\t\t\t\t\t\t\t\tpageDefinition={pageDefinition}\n\t\t\t\t\t\t\t\t\ttransferId={transferId}\n\t\t\t\t\t\t\t\t\tparams={params}\n\t\t\t\t\t\t\t\t\tactionButtonGroups={actionButtonGroups}\n\t\t\t\t\t\t\t\t\tnavigation={navigation}\n\t\t\t\t\t\t\t\t\tdataStore={dataStore}\n\t\t\t\t\t\t\t\t\tapplication={application}\n\t\t\t\t\t\t\t\t\tapi={api}\n\t\t\t\t\t\t\t\t\tnotifications={notifications}\n\t\t\t\t\t\t\t\t\ttransfer={transfer}\n\t\t\t\t\t\t\t\t\tcloseDialog={closeDialog}\n\t\t\t\t\t\t\t\t\tisCreate={isCreate}\n\t\t\t\t\t\t\t\t\tisEager={isEager}\n\t\t\t\t\t\t\t\t\trelation={relation}\n\t\t\t\t\t\t\t\t\townerTransfer={ownerTransfer}\n\t\t\t\t\t\t\t\t\tparentTransferId={parentTransferId}\n\t\t\t\t\t\t\t\t\trelationName={relationName}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</ValidationProvider>\n\t\t\t\t\t</VisualPropertiesProvider>\n\t\t\t\t</PageActionOverridesProvider>\n\t\t\t</PageProvider>\n\t\t</Dialog>\n\t);\n}\n\n/** Helper to render a translated dialog title, supporting dynamic titles from transfer attribute data. */\nfunction TranslatedDialogTitle({\n\tpageDefinition,\n\ttransferId,\n}: {\n\tpageDefinition: PageDefinition;\n\ttransferId: string | null;\n}) {\n\tconst { title } = usePageTitle(pageDefinition, transferId);\n\tif (!title) return null;\n\treturn <DialogTitle data-testid={`page-dialog::${pageDefinition[\"xmi:id\"]}::title`}>{title}</DialogTitle>;\n}\n","/**\n * Layout dimension constants for the application shell.\n * Separated from component files to preserve HMR boundaries.\n * See: specs/HMR.md — Standard I: Single-Authority Export Mandate\n */\n\nexport const DRAWER_WIDTH_EXPANDED = 280;\nexport const DRAWER_WIDTH_COLLAPSED = 64;\n","import { useApplication } from \"@judo/core\";\nimport { MenuLayout } from \"@judo/model-api\";\nimport { Box } from \"@mui/material\";\nimport { type ReactNode, useState } from \"react\";\nimport { NavigationDrawer } from \"../navigation/NavigationDrawer\";\nimport { AppBar } from \"./AppBar\";\nimport { Breadcrumbs } from \"./Breadcrumbs\";\nimport { Footer } from \"./Footer\";\nimport { PageDialogHost } from \"./PageDialogHost\";\nimport { DRAWER_WIDTH_COLLAPSED, DRAWER_WIDTH_EXPANDED } from \"./layout-constants\";\n\nexport interface AppShellLayoutProps {\n\tchildren: ReactNode;\n\tlogo?: ReactNode;\n\tappBarExtra?: ReactNode;\n\t/** Override the menu layout from the model. When not set, uses Application.defaultMenuLayout (falls back to VERTICAL). */\n\tmenuLayout?: MenuLayout;\n}\n\n/**\n * Main application shell layout with drawer (vertical) or horizontal app bar navigation.\n */\nexport function AppShellLayout({ children, logo, appBarExtra, menuLayout }: AppShellLayoutProps) {\n\tconst [drawerOpen, setDrawerOpen] = useState(true);\n\tconst [drawerCollapsed, setDrawerCollapsed] = useState(false);\n\tconst { application } = useApplication();\n\n\tconst effectiveLayout = menuLayout ?? application.defaultMenuLayout ?? MenuLayout.VERTICAL;\n\tconst isHorizontal = effectiveLayout === MenuLayout.HORIZONTAL;\n\n\tconst drawerWidth = drawerCollapsed ? DRAWER_WIDTH_COLLAPSED : DRAWER_WIDTH_EXPANDED;\n\tconst activeDrawerWidth = isHorizontal ? 0 : drawerOpen ? drawerWidth : 0;\n\n\treturn (\n\t\t<Box sx={{ display: \"flex\", minHeight: \"100vh\" }} data-testid=\"app-shell-layout\">\n\t\t\t{/* App Bar */}\n\t\t\t<AppBar\n\t\t\t\tdrawerWidth={activeDrawerWidth}\n\t\t\t\tonMenuClick={isHorizontal ? undefined : () => setDrawerOpen(!drawerOpen)}\n\t\t\t\tlogo={logo}\n\t\t\t\textra={appBarExtra}\n\t\t\t\tmenuLayout={effectiveLayout}\n\t\t\t\tnavigationController={application.navigationController}\n\t\t\t/>\n\n\t\t\t{/* Navigation Drawer (vertical mode only) */}\n\t\t\t{!isHorizontal && (\n\t\t\t\t<NavigationDrawer\n\t\t\t\t\topen={drawerOpen}\n\t\t\t\t\tcollapsed={drawerCollapsed}\n\t\t\t\t\tonCollapse={() => setDrawerCollapsed(!drawerCollapsed)}\n\t\t\t\t\twidth={drawerOpen ? drawerWidth : 0}\n\t\t\t\t\tnavigationController={application.navigationController}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Content column: main + footer stacked vertically */}\n\t\t\t<Box\n\t\t\t\tsx={{\n\t\t\t\t\tdisplay: \"flex\",\n\t\t\t\t\tflexDirection: \"column\",\n\t\t\t\t\tflexGrow: 1,\n\t\t\t\t\tminHeight: \"100vh\",\n\t\t\t\t\twidth: `calc(100% - ${activeDrawerWidth}px)`,\n\t\t\t\t\ttransition: \"width 0.2s\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t{/* Main Content */}\n\t\t\t\t<Box\n\t\t\t\t\tcomponent=\"main\"\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tflexGrow: 1,\n\t\t\t\t\t\tp: 3,\n\t\t\t\t\t\tmt: 8, // AppBar height\n\t\t\t\t\t}}\n\t\t\t\t\tdata-testid=\"app-shell-layout::main\"\n\t\t\t\t>\n\t\t\t\t\t{/* Breadcrumbs */}\n\t\t\t\t\t<Breadcrumbs />\n\n\t\t\t\t\t{/* Page Content */}\n\t\t\t\t\t{children}\n\t\t\t\t</Box>\n\n\t\t\t\t{/* Footer */}\n\t\t\t\t<Footer />\n\t\t\t</Box>\n\n\t\t\t{/* Page Dialog Host - renders pages opened as dialogs */}\n\t\t\t<PageDialogHost />\n\t\t</Box>\n\t);\n}\n","import { type ReactNode, useCallback } from \"react\";\n\nimport { useApi } from \"@judo/actions\";\nimport { PrincipalProvider } from \"@judo/auth\";\nimport { useApplication } from \"@judo/core\";\n\n/**\n * Bridge that wires PrincipalProvider with the API client.\n * Rendered inside ActorAuthBoundary + ApiProvider so useApi() is available.\n *\n * The `~principal` endpoint is only available for authenticated actors\n * (those whose Application model defines an `authentication` block).\n * When authentication is absent, the provider is still rendered (so\n * `usePrincipalOptional()` returns a context) but no fetch is performed.\n */\nexport function PrincipalBridge({ children }: { children: ReactNode }) {\n\tconst api = useApi();\n\tconst { application } = useApplication();\n\n\tconst fetchPrincipal = useCallback(async () => {\n\t\tconst response = await api.getPrincipal();\n\t\treturn response.data as Record<string, unknown>;\n\t}, [api]);\n\n\t// ~principal requires an authenticated actor — skip the fetch otherwise.\n\tconst effectiveFetch = application.authentication ? fetchPrincipal : undefined;\n\n\treturn <PrincipalProvider fetchPrincipal={effectiveFetch}>{children}</PrincipalProvider>;\n}\n","import { Box, Button, Paper, Typography } from \"@mui/material\";\nimport type { GuestPageProps } from \"@judo/model-api\";\n\n/**\n * Default guest page displayed when `Application.supportGuestAccess` is true\n * and the user is not authenticated.\n *\n * Shows the application title and a \"Sign In\" button that triggers OIDC login.\n * Can be replaced via `CustomizationsConfig.guestComponent`.\n */\nexport function DefaultGuestPage({ application, signIn }: GuestPageProps) {\n\treturn (\n\t\t<Box display=\"flex\" justifyContent=\"center\" alignItems=\"center\" minHeight=\"100vh\" data-testid=\"guest-page\">\n\t\t\t<Paper\n\t\t\t\televation={3}\n\t\t\t\tsx={{\n\t\t\t\t\tp: 4,\n\t\t\t\t\tmaxWidth: 400,\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\ttextAlign: \"center\",\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<Typography variant=\"h4\" gutterBottom data-testid=\"guest-page-title\">\n\t\t\t\t\t{application.title ?? application.name}\n\t\t\t\t</Typography>\n\t\t\t\t<Typography variant=\"body1\" color=\"text.secondary\" sx={{ mb: 3 }}>\n\t\t\t\t\tSign in to access the application.\n\t\t\t\t</Typography>\n\t\t\t\t<Button variant=\"contained\" size=\"large\" onClick={signIn} data-testid=\"guest-page-sign-in\">\n\t\t\t\t\tSign In\n\t\t\t\t</Button>\n\t\t\t</Paper>\n\t\t</Box>\n\t);\n}\n","import SettingsIcon from \"@mui/icons-material/Settings\";\nimport { Box, Paper, Typography } from \"@mui/material\";\nimport { useTranslation } from \"react-i18next\";\n\n/**\n * Built-in placeholder settings page rendered at `/settings`\n * when no custom `CustomizationsConfig.settingsPage` is provided.\n *\n * Displays a minimal informational message indicating that the\n * settings page can be implemented by the application.\n */\nexport function DefaultSettingsPage() {\n\tconst { t } = useTranslation();\n\n\treturn (\n\t\t<Box\n\t\t\tsx={{ display: \"flex\", justifyContent: \"center\", alignItems: \"center\", minHeight: \"60vh\" }}\n\t\t\tdata-testid=\"default-settings-page\"\n\t\t>\n\t\t\t<Paper sx={{ p: 4, textAlign: \"center\", maxWidth: 480 }} elevation={2}>\n\t\t\t\t<SettingsIcon sx={{ fontSize: 48, color: \"text.secondary\", mb: 2 }} />\n\t\t\t\t<Typography variant=\"h5\" gutterBottom>\n\t\t\t\t\t{t(\"system.common.settings\", { defaultValue: \"Settings\" })}\n\t\t\t\t</Typography>\n\t\t\t\t<Typography variant=\"body1\" color=\"text.secondary\">\n\t\t\t\t\t{t(\"system.common.settingsPlaceholder\", {\n\t\t\t\t\t\tdefaultValue: \"This page can be customized by providing a settingsPage component.\",\n\t\t\t\t\t})}\n\t\t\t\t</Typography>\n\t\t\t</Paper>\n\t\t</Box>\n\t);\n}\n","import { PageRenderer } from \"@judo/components\";\nimport { PageActionOverridesProvider, PageProvider, VisualPropertiesProvider } from \"@judo/core\";\nimport type { PageContainer, PageDefinition } from \"@judo/model-api\";\nimport { useMemo } from \"react\";\nimport { useParams } from \"react-router\";\n\nexport interface PageRouteProps {\n\tpage: PageDefinition;\n}\n\n/**\n * Generate a stable transfer ID for a page based on its definition.\n * For table pages, this ID is used to store list data in the data store.\n */\nfunction generatePageEntityId(page: PageDefinition): string | null {\n\tconst container = page.container as PageContainer | undefined;\n\n\t// For TABLE type containers, generate an transfer ID based on the page\n\tif (container?.type === \"TABLE\") {\n\t\treturn `page::${page[\"xmi:id\"]}`;\n\t}\n\n\t// For other page types, the transfer ID is usually passed via navigation params\n\t// (e.g., when viewing a specific transfer)\n\treturn null;\n}\n\n/**\n * Route component that renders a page from its definition.\n * Wraps the page in PageProvider to provide page context to all child components.\n *\n * For TABLE type pages, a stable transfer ID is generated to store list data.\n * For VIEW type pages, the signedIdentifier from the URL is used as the transfer ID.\n */\nexport function PageRoute({ page }: PageRouteProps) {\n\tconst { signedIdentifier } = useParams<{ signedIdentifier?: string }>();\n\n\t// Generate transfer ID\n\tconst transferId = useMemo(() => {\n\t\tconst container = page.container as PageContainer | undefined;\n\n\t\t// For VIEW pages, use signedIdentifier from URL if available\n\t\tif (container?.type === \"VIEW\" && signedIdentifier) {\n\t\t\tconst decodedId = decodeURIComponent(signedIdentifier);\n\t\t\treturn `transfer::${decodedId}`;\n\t\t}\n\n\t\t// For TABLE pages with signedIdentifier (relation tables), use it as transfer ID\n\t\t// This enables the table to know its parent transfer for relation operations\n\t\tif (container?.type === \"TABLE\" && signedIdentifier) {\n\t\t\tconst decodedId = decodeURIComponent(signedIdentifier);\n\t\t\treturn `transfer::${decodedId}`;\n\t\t}\n\n\t\t// For TABLE pages without signedIdentifier, generate stable transfer ID\n\t\treturn generatePageEntityId(page);\n\t}, [page, signedIdentifier]);\n\n\t// Store signedIdentifier in params for data loading\n\tconst params = useMemo(() => {\n\t\tif (signedIdentifier) {\n\t\t\tconst decodedId = decodeURIComponent(signedIdentifier);\n\t\t\treturn { signedIdentifier: decodedId };\n\t\t}\n\t\treturn undefined;\n\t}, [signedIdentifier]);\n\n\treturn (\n\t\t<PageProvider pageDefinition={page} transferId={transferId} params={params}>\n\t\t\t<PageActionOverridesProvider>\n\t\t\t\t<VisualPropertiesProvider>\n\t\t\t\t\t<PageRenderer page={page} />\n\t\t\t\t</VisualPropertiesProvider>\n\t\t\t</PageActionOverridesProvider>\n\t\t</PageProvider>\n\t);\n}\n","import { useCustomizationsOptional } from \"@judo/core\";\n\n/**\n * Page rendered at the `/_redirect` route.\n *\n * Looks up the `redirectHandler` from customizations and renders it.\n * Because the handler is a React component (not a plain function),\n * it has full access to React hooks including react-router hooks\n * like `useSearchParams()`, `useNavigate()`, etc.\n *\n * If no redirect handler is registered, renders a simple fallback message.\n */\nexport function RedirectPage() {\n\tconst customizations = useCustomizationsOptional();\n\tconst RedirectHandler = customizations?.getRedirectHandler();\n\n\tif (RedirectHandler) {\n\t\treturn <RedirectHandler />;\n\t}\n\n\treturn (\n\t\t<div data-testid=\"redirect-no-handler\">\n\t\t\t<p>No redirect handler configured.</p>\n\t\t</div>\n\t);\n}\n","import type { Application } from \"@judo/model-api\";\nimport type { ComponentType, ReactElement } from \"react\";\nimport { Route, Routes } from \"react-router\";\nimport { DefaultSettingsPage } from \"./DefaultSettingsPage\";\nimport { getRoutePattern } from \"../navigation/navigation-utils\";\nimport { PageRoute } from \"./PageRoute\";\nimport { RedirectPage } from \"./RedirectPage\";\n\nexport interface GenerateRoutesProps {\n\tapplication: Application;\n\tDashboardPage?: React.ComponentType<{ application: Application }>;\n\tNotFoundPage?: React.ComponentType;\n\t/** Additional custom routes injected after model-derived routes and before the 404 catch-all. */\n\tcustomRoutes?: Array<{ path: string; element: ReactElement }>;\n\t/**\n\t * Custom settings page component rendered at the `/settings` route.\n\t * When not provided, the built-in `DefaultSettingsPage` placeholder is used.\n\t */\n\tSettingsPage?: ComponentType;\n}\n\n/**\n * Generate React Router routes from PageDefinitions.\n */\nexport function generateRoutes({\n\tapplication,\n\tDashboardPage,\n\tNotFoundPage,\n\tcustomRoutes,\n\tSettingsPage,\n}: GenerateRoutesProps): ReactElement {\n\t// Build page routes with their patterns (including :signedIdentifier? for VIEW pages)\n\tconst pageRoutes = application.pages.map((page) => ({\n\t\tpage,\n\t\troute: getRoutePattern(page),\n\t}));\n\n\t// Check if model defines a root \"/\" route\n\tconst hasModelDashboard = pageRoutes.some(({ route }) => route === \"/\");\n\n\treturn (\n\t\t<Routes>\n\t\t\t{/* Synthesize dashboard only if model doesn't define one */}\n\t\t\t{!hasModelDashboard && (\n\t\t\t\t<Route\n\t\t\t\t\tpath=\"/\"\n\t\t\t\t\telement={\n\t\t\t\t\t\tDashboardPage ? <DashboardPage application={application} /> : <DefaultDashboard application={application} />\n\t\t\t\t\t}\n\t\t\t\t/>\n\t\t\t)}\n\n\t\t\t{/* Page routes */}\n\t\t\t{pageRoutes.map(({ page, route }) => (\n\t\t\t\t<Route key={page[\"xmi:id\"]} path={route} element={<PageRoute page={page} />} />\n\t\t\t))}\n\n\t\t\t{/* Redirect route — renders customizable RedirectHandler component */}\n\t\t\t<Route path=\"/_redirect\" element={<RedirectPage />} />\n\n\t\t\t{/* Settings route — always registered; uses custom or built-in placeholder */}\n\t\t\t<Route path=\"/settings\" element={SettingsPage ? <SettingsPage /> : <DefaultSettingsPage />} />\n\n\t\t\t{/* Custom routes from customizations */}\n\t\t\t{customRoutes?.map(({ path, element }) => (\n\t\t\t\t<Route key={path} path={path} element={element} />\n\t\t\t))}\n\n\t\t\t{/* 404 */}\n\t\t\t<Route path=\"*\" element={NotFoundPage ? <NotFoundPage /> : <DefaultNotFound />} />\n\t\t</Routes>\n\t);\n}\n\nfunction DefaultDashboard({ application }: { application: Application }) {\n\treturn (\n\t\t<div data-testid=\"dashboard\">\n\t\t\t<h1>Welcome to {application.name}</h1>\n\t\t</div>\n\t);\n}\n\nfunction DefaultNotFound() {\n\treturn (\n\t\t<div data-testid=\"not-found\">\n\t\t\t<h1>404 - Page Not Found</h1>\n\t\t</div>\n\t);\n}\n","/**\n * @license React\n * react-is.production.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\nvar REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_VIEW_TRANSITION_TYPE = Symbol.for(\"react.view_transition\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\");\nfunction typeOf(object) {\n if (\"object\" === typeof object && null !== object) {\n var $$typeof = object.$$typeof;\n switch ($$typeof) {\n case REACT_ELEMENT_TYPE:\n switch (((object = object.type), object)) {\n case REACT_FRAGMENT_TYPE:\n case REACT_PROFILER_TYPE:\n case REACT_STRICT_MODE_TYPE:\n case REACT_SUSPENSE_TYPE:\n case REACT_SUSPENSE_LIST_TYPE:\n case REACT_VIEW_TRANSITION_TYPE:\n return object;\n default:\n switch (((object = object && object.$$typeof), object)) {\n case REACT_CONTEXT_TYPE:\n case REACT_FORWARD_REF_TYPE:\n case REACT_LAZY_TYPE:\n case REACT_MEMO_TYPE:\n return object;\n case REACT_CONSUMER_TYPE:\n return object;\n default:\n return $$typeof;\n }\n }\n case REACT_PORTAL_TYPE:\n return $$typeof;\n }\n }\n}\nexports.ContextConsumer = REACT_CONSUMER_TYPE;\nexports.ContextProvider = REACT_CONTEXT_TYPE;\nexports.Element = REACT_ELEMENT_TYPE;\nexports.ForwardRef = REACT_FORWARD_REF_TYPE;\nexports.Fragment = REACT_FRAGMENT_TYPE;\nexports.Lazy = REACT_LAZY_TYPE;\nexports.Memo = REACT_MEMO_TYPE;\nexports.Portal = REACT_PORTAL_TYPE;\nexports.Profiler = REACT_PROFILER_TYPE;\nexports.StrictMode = REACT_STRICT_MODE_TYPE;\nexports.Suspense = REACT_SUSPENSE_TYPE;\nexports.SuspenseList = REACT_SUSPENSE_LIST_TYPE;\nexports.isContextConsumer = function (object) {\n return typeOf(object) === REACT_CONSUMER_TYPE;\n};\nexports.isContextProvider = function (object) {\n return typeOf(object) === REACT_CONTEXT_TYPE;\n};\nexports.isElement = function (object) {\n return (\n \"object\" === typeof object &&\n null !== object &&\n object.$$typeof === REACT_ELEMENT_TYPE\n );\n};\nexports.isForwardRef = function (object) {\n return typeOf(object) === REACT_FORWARD_REF_TYPE;\n};\nexports.isFragment = function (object) {\n return typeOf(object) === REACT_FRAGMENT_TYPE;\n};\nexports.isLazy = function (object) {\n return typeOf(object) === REACT_LAZY_TYPE;\n};\nexports.isMemo = function (object) {\n return typeOf(object) === REACT_MEMO_TYPE;\n};\nexports.isPortal = function (object) {\n return typeOf(object) === REACT_PORTAL_TYPE;\n};\nexports.isProfiler = function (object) {\n return typeOf(object) === REACT_PROFILER_TYPE;\n};\nexports.isStrictMode = function (object) {\n return typeOf(object) === REACT_STRICT_MODE_TYPE;\n};\nexports.isSuspense = function (object) {\n return typeOf(object) === REACT_SUSPENSE_TYPE;\n};\nexports.isSuspenseList = function (object) {\n return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;\n};\nexports.isValidElementType = function (type) {\n return \"string\" === typeof type ||\n \"function\" === typeof type ||\n type === REACT_FRAGMENT_TYPE ||\n type === REACT_PROFILER_TYPE ||\n type === REACT_STRICT_MODE_TYPE ||\n type === REACT_SUSPENSE_TYPE ||\n type === REACT_SUSPENSE_LIST_TYPE ||\n (\"object\" === typeof type &&\n null !== type &&\n (type.$$typeof === REACT_LAZY_TYPE ||\n type.$$typeof === REACT_MEMO_TYPE ||\n type.$$typeof === REACT_CONTEXT_TYPE ||\n type.$$typeof === REACT_CONSUMER_TYPE ||\n type.$$typeof === REACT_FORWARD_REF_TYPE ||\n type.$$typeof === REACT_CLIENT_REFERENCE ||\n void 0 !== type.getModuleId))\n ? !0\n : !1;\n};\nexports.typeOf = typeOf;\n","/**\n * @license React\n * react-is.development.js\n *\n * Copyright (c) Meta Platforms, Inc. and affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n\"use strict\";\n\"production\" !== process.env.NODE_ENV &&\n (function () {\n function typeOf(object) {\n if (\"object\" === typeof object && null !== object) {\n var $$typeof = object.$$typeof;\n switch ($$typeof) {\n case REACT_ELEMENT_TYPE:\n switch (((object = object.type), object)) {\n case REACT_FRAGMENT_TYPE:\n case REACT_PROFILER_TYPE:\n case REACT_STRICT_MODE_TYPE:\n case REACT_SUSPENSE_TYPE:\n case REACT_SUSPENSE_LIST_TYPE:\n case REACT_VIEW_TRANSITION_TYPE:\n return object;\n default:\n switch (((object = object && object.$$typeof), object)) {\n case REACT_CONTEXT_TYPE:\n case REACT_FORWARD_REF_TYPE:\n case REACT_LAZY_TYPE:\n case REACT_MEMO_TYPE:\n return object;\n case REACT_CONSUMER_TYPE:\n return object;\n default:\n return $$typeof;\n }\n }\n case REACT_PORTAL_TYPE:\n return $$typeof;\n }\n }\n }\n var REACT_ELEMENT_TYPE = Symbol.for(\"react.transitional.element\"),\n REACT_PORTAL_TYPE = Symbol.for(\"react.portal\"),\n REACT_FRAGMENT_TYPE = Symbol.for(\"react.fragment\"),\n REACT_STRICT_MODE_TYPE = Symbol.for(\"react.strict_mode\"),\n REACT_PROFILER_TYPE = Symbol.for(\"react.profiler\"),\n REACT_CONSUMER_TYPE = Symbol.for(\"react.consumer\"),\n REACT_CONTEXT_TYPE = Symbol.for(\"react.context\"),\n REACT_FORWARD_REF_TYPE = Symbol.for(\"react.forward_ref\"),\n REACT_SUSPENSE_TYPE = Symbol.for(\"react.suspense\"),\n REACT_SUSPENSE_LIST_TYPE = Symbol.for(\"react.suspense_list\"),\n REACT_MEMO_TYPE = Symbol.for(\"react.memo\"),\n REACT_LAZY_TYPE = Symbol.for(\"react.lazy\"),\n REACT_VIEW_TRANSITION_TYPE = Symbol.for(\"react.view_transition\"),\n REACT_CLIENT_REFERENCE = Symbol.for(\"react.client.reference\");\n exports.ContextConsumer = REACT_CONSUMER_TYPE;\n exports.ContextProvider = REACT_CONTEXT_TYPE;\n exports.Element = REACT_ELEMENT_TYPE;\n exports.ForwardRef = REACT_FORWARD_REF_TYPE;\n exports.Fragment = REACT_FRAGMENT_TYPE;\n exports.Lazy = REACT_LAZY_TYPE;\n exports.Memo = REACT_MEMO_TYPE;\n exports.Portal = REACT_PORTAL_TYPE;\n exports.Profiler = REACT_PROFILER_TYPE;\n exports.StrictMode = REACT_STRICT_MODE_TYPE;\n exports.Suspense = REACT_SUSPENSE_TYPE;\n exports.SuspenseList = REACT_SUSPENSE_LIST_TYPE;\n exports.isContextConsumer = function (object) {\n return typeOf(object) === REACT_CONSUMER_TYPE;\n };\n exports.isContextProvider = function (object) {\n return typeOf(object) === REACT_CONTEXT_TYPE;\n };\n exports.isElement = function (object) {\n return (\n \"object\" === typeof object &&\n null !== object &&\n object.$$typeof === REACT_ELEMENT_TYPE\n );\n };\n exports.isForwardRef = function (object) {\n return typeOf(object) === REACT_FORWARD_REF_TYPE;\n };\n exports.isFragment = function (object) {\n return typeOf(object) === REACT_FRAGMENT_TYPE;\n };\n exports.isLazy = function (object) {\n return typeOf(object) === REACT_LAZY_TYPE;\n };\n exports.isMemo = function (object) {\n return typeOf(object) === REACT_MEMO_TYPE;\n };\n exports.isPortal = function (object) {\n return typeOf(object) === REACT_PORTAL_TYPE;\n };\n exports.isProfiler = function (object) {\n return typeOf(object) === REACT_PROFILER_TYPE;\n };\n exports.isStrictMode = function (object) {\n return typeOf(object) === REACT_STRICT_MODE_TYPE;\n };\n exports.isSuspense = function (object) {\n return typeOf(object) === REACT_SUSPENSE_TYPE;\n };\n exports.isSuspenseList = function (object) {\n return typeOf(object) === REACT_SUSPENSE_LIST_TYPE;\n };\n exports.isValidElementType = function (type) {\n return \"string\" === typeof type ||\n \"function\" === typeof type ||\n type === REACT_FRAGMENT_TYPE ||\n type === REACT_PROFILER_TYPE ||\n type === REACT_STRICT_MODE_TYPE ||\n type === REACT_SUSPENSE_TYPE ||\n type === REACT_SUSPENSE_LIST_TYPE ||\n (\"object\" === typeof type &&\n null !== type &&\n (type.$$typeof === REACT_LAZY_TYPE ||\n type.$$typeof === REACT_MEMO_TYPE ||\n type.$$typeof === REACT_CONTEXT_TYPE ||\n type.$$typeof === REACT_CONSUMER_TYPE ||\n type.$$typeof === REACT_FORWARD_REF_TYPE ||\n type.$$typeof === REACT_CLIENT_REFERENCE ||\n void 0 !== type.getModuleId))\n ? !0\n : !1;\n };\n exports.typeOf = typeOf;\n })();\n","'use strict';\n\nif (process.env.NODE_ENV === 'production') {\n module.exports = require('./cjs/react-is.production.js');\n} else {\n module.exports = require('./cjs/react-is.development.js');\n}\n","import * as React from 'react';\nimport { isValidElementType } from 'react-is';\n\n// https://github.com/sindresorhus/is-plain-obj/blob/main/index.js\nexport function isPlainObject(item) {\n if (typeof item !== 'object' || item === null) {\n return false;\n }\n const prototype = Object.getPrototypeOf(item);\n return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in item) && !(Symbol.iterator in item);\n}\nfunction deepClone(source) {\n if (/*#__PURE__*/React.isValidElement(source) || isValidElementType(source) || !isPlainObject(source)) {\n return source;\n }\n const output = {};\n Object.keys(source).forEach(key => {\n output[key] = deepClone(source[key]);\n });\n return output;\n}\n\n/**\n * Merge objects deeply.\n * It will shallow copy React elements.\n *\n * If `options.clone` is set to `false` the source object will be merged directly into the target object.\n *\n * @example\n * ```ts\n * deepmerge({ a: { b: 1 }, d: 2 }, { a: { c: 2 }, d: 4 });\n * // => { a: { b: 1, c: 2 }, d: 4 }\n * ````\n *\n * @param target The target object.\n * @param source The source object.\n * @param options The merge options.\n * @param options.clone Set to `false` to merge the source object directly into the target object.\n * @returns The merged object.\n */\nexport default function deepmerge(target, source, options = {\n clone: true\n}) {\n const output = options.clone ? {\n ...target\n } : target;\n if (isPlainObject(target) && isPlainObject(source)) {\n Object.keys(source).forEach(key => {\n if (/*#__PURE__*/React.isValidElement(source[key]) || isValidElementType(source[key])) {\n output[key] = source[key];\n } else if (isPlainObject(source[key]) &&\n // Avoid prototype pollution\n Object.prototype.hasOwnProperty.call(target, key) && isPlainObject(target[key])) {\n // Since `output` is a clone of `target` and we have narrowed `target` in this block we can cast to the same type.\n output[key] = deepmerge(target[key], source[key], options);\n } else if (options.clone) {\n output[key] = isPlainObject(source[key]) ? deepClone(source[key]) : source[key];\n } else {\n output[key] = source[key];\n }\n });\n }\n return output;\n}","/**\n * Density levels for semantic spacing/sizing.\n *\n * - `compact` — Tight spacing, smaller font sizes; optimized for data-heavy views.\n * - `comfortable` — Default MUI sizing; balanced between readability and density.\n * - `standard` — Generous spacing, slightly larger touch targets; relaxed feel.\n */\nexport type DensityLevel = \"compact\" | \"comfortable\" | \"standard\";\n\n/**\n * Returns MUI `ThemeOptions` that implement the requested density level.\n *\n * The returned options cover spacing factor, default component props (size/margin),\n * and typography scaling so that a single `density` knob adjusts the whole UI.\n *\n * Merge the result as a **base** layer — caller-supplied `muiThemeOptions` should\n * be applied on top so they can override individual values.\n */\nexport function createDensityThemeOptions(density: DensityLevel): Record<string, unknown> {\n\tswitch (density) {\n\t\tcase \"compact\":\n\t\t\treturn {\n\t\t\t\tspacing: 6,\n\t\t\t\ttypography: {\n\t\t\t\t\tfontSize: 13,\n\t\t\t\t},\n\t\t\t\tcomponents: {\n\t\t\t\t\tMuiButton: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiTextField: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\", margin: \"dense\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiFormControl: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\", margin: \"dense\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiInputBase: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiInputLabel: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiSelect: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\", margin: \"dense\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiIconButton: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiToolbar: {\n\t\t\t\t\t\tdefaultProps: { variant: \"dense\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiTable: {\n\t\t\t\t\t\tdefaultProps: { size: \"small\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiTableCell: {\n\t\t\t\t\t\tstyleOverrides: {\n\t\t\t\t\t\t\troot: { padding: \"4px 8px\" },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMuiCardContent: {\n\t\t\t\t\t\tstyleOverrides: {\n\t\t\t\t\t\t\troot: { padding: \"12px\" },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMuiDataGrid: {\n\t\t\t\t\t\tdefaultProps: { density: \"compact\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiDataGridPro: {\n\t\t\t\t\t\tdefaultProps: { density: \"compact\" },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\n\t\tcase \"standard\":\n\t\t\treturn {\n\t\t\t\tspacing: 10,\n\t\t\t\ttypography: {\n\t\t\t\t\tfontSize: 15,\n\t\t\t\t},\n\t\t\t\tcomponents: {\n\t\t\t\t\tMuiButton: {\n\t\t\t\t\t\tdefaultProps: { size: \"large\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiTextField: {\n\t\t\t\t\t\tdefaultProps: { size: \"medium\", margin: \"normal\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiFormControl: {\n\t\t\t\t\t\tdefaultProps: { size: \"medium\", margin: \"normal\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiToolbar: {\n\t\t\t\t\t\tdefaultProps: { variant: \"regular\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiTableCell: {\n\t\t\t\t\t\tstyleOverrides: {\n\t\t\t\t\t\t\troot: { padding: \"12px 16px\" },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMuiCardContent: {\n\t\t\t\t\t\tstyleOverrides: {\n\t\t\t\t\t\t\troot: { padding: \"20px\" },\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tMuiDataGrid: {\n\t\t\t\t\t\tdefaultProps: { density: \"comfortable\" },\n\t\t\t\t\t},\n\t\t\t\t\tMuiDataGridPro: {\n\t\t\t\t\t\tdefaultProps: { density: \"comfortable\" },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\n\t\tcase \"comfortable\":\n\t\tdefault:\n\t\t\t// \"comfortable\" is plain MUI defaults — return empty options\n\t\t\treturn {};\n\t}\n}\n","/**\n * JUDO Theme Factory\n *\n * Creates polished MUI `ThemeOptions` from primary + secondary colors.\n * The result is designed for enterprise/ERP UIs: information-dense, modern,\n * and driven by the two supplied brand colors.\n *\n * This function does NOT call `createTheme()` — it returns a plain options\n * object that the ThemeProvider merges with density and user overrides.\n */\n\n/**\n * Derive an alpha variant of a hex color.\n */\nfunction hexAlpha(hex: string, alpha: number): string {\n\tconst a = Math.round(alpha * 255)\n\t\t.toString(16)\n\t\t.padStart(2, \"0\");\n\treturn `${hex}${a}`;\n}\n\nexport interface JudoThemeFactoryOptions {\n\tprimaryColor: string;\n\tsecondaryColor: string;\n\tmode: \"light\" | \"dark\";\n\tlightBackground?: string;\n\tdarkBackground?: string;\n}\n\n/**\n * Build modern MUI ThemeOptions driven by primary & secondary colors.\n *\n * Design goals:\n * - Compact but not cramped — enterprise users need information density\n * - Modern aesthetic: subtle shadows, refined border-radius, crisp typography\n * - Primary color drives AppBar, buttons, active states\n * - Secondary color provides accent on FABs, toggles, highlights\n * - Clean separation of surfaces with subtle elevation\n */\nexport function createJudoThemeOptions(options: JudoThemeFactoryOptions): Record<string, unknown> {\n\tconst { primaryColor, secondaryColor, mode, lightBackground, darkBackground } = options;\n\n\tconst isLight = mode === \"light\";\n\n\treturn {\n\t\tpalette: {\n\t\t\tmode,\n\t\t\tprimary: { main: primaryColor },\n\t\t\tsecondary: { main: secondaryColor },\n\t\t\tbackground: isLight\n\t\t\t\t? {\n\t\t\t\t\t\tdefault: lightBackground ?? \"#F5F6FA\",\n\t\t\t\t\t\tpaper: \"#FFFFFF\",\n\t\t\t\t\t}\n\t\t\t\t: {\n\t\t\t\t\t\tdefault: darkBackground ?? \"#0A1929\",\n\t\t\t\t\t\tpaper: \"#132F4C\",\n\t\t\t\t\t},\n\t\t\tdivider: isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\",\n\t\t},\n\n\t\tshape: {\n\t\t\tborderRadius: 8,\n\t\t},\n\n\t\ttypography: {\n\t\t\tfontFamily: ['\"Inter\"', '\"Segoe UI\"', '\"Roboto\"', '\"Helvetica Neue\"', \"Arial\", \"sans-serif\"].join(\",\"),\n\t\t\th1: { fontWeight: 700, letterSpacing: \"-0.02em\" },\n\t\t\th2: { fontWeight: 700, letterSpacing: \"-0.01em\" },\n\t\t\th3: { fontWeight: 600 },\n\t\t\th4: { fontWeight: 600 },\n\t\t\th5: { fontWeight: 600 },\n\t\t\th6: { fontWeight: 600 },\n\t\t\tsubtitle1: { fontWeight: 500 },\n\t\t\tsubtitle2: { fontWeight: 500 },\n\t\t\tbutton: { fontWeight: 600, textTransform: \"none\" as const },\n\t\t},\n\n\t\tshadows: createModernShadows(isLight),\n\n\t\tcomponents: {\n\t\t\t// ---------- Global ----------\n\t\t\tMuiCssBaseline: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\t\"*, *::before, *::after\": {\n\t\t\t\t\t\tboxSizing: \"border-box\",\n\t\t\t\t\t},\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tWebkitFontSmoothing: \"antialiased\",\n\t\t\t\t\t\tMozOsxFontSmoothing: \"grayscale\",\n\t\t\t\t\t},\n\t\t\t\t\t// Keyframe animations for page/component entrance\n\t\t\t\t\t\"@keyframes judoFadeInUp\": {\n\t\t\t\t\t\tfrom: {\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\ttransform: \"translateY(8px)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tto: {\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\ttransform: \"translateY(0)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t\"@keyframes judoFadeIn\": {\n\t\t\t\t\t\tfrom: { opacity: 0 },\n\t\t\t\t\t\tto: { opacity: 1 },\n\t\t\t\t\t},\n\t\t\t\t\t// Subtle, minimal scrollbars\n\t\t\t\t\t\"*::-webkit-scrollbar\": {\n\t\t\t\t\t\twidth: 6,\n\t\t\t\t\t\theight: 6,\n\t\t\t\t\t},\n\t\t\t\t\t\"*::-webkit-scrollbar-track\": {\n\t\t\t\t\t\tbackground: \"transparent\",\n\t\t\t\t\t},\n\t\t\t\t\t\"*::-webkit-scrollbar-thumb\": {\n\t\t\t\t\t\tbackground: isLight ? \"rgba(0,0,0,0.15)\" : \"rgba(255,255,255,0.15)\",\n\t\t\t\t\t\tborderRadius: 3,\n\t\t\t\t\t},\n\t\t\t\t\t\"*::-webkit-scrollbar-thumb:hover\": {\n\t\t\t\t\t\tbackground: isLight ? \"rgba(0,0,0,0.25)\" : \"rgba(255,255,255,0.25)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Surfaces ----------\n\t\t\tMuiPaper: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\televation: 0,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tbackgroundImage: isLight\n\t\t\t\t\t\t\t? \"linear-gradient(135deg, rgba(255,255,255,0.9) 0%, rgba(255,255,255,0.7) 100%)\"\n\t\t\t\t\t\t\t: \"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)\",\n\t\t\t\t\t\tborder: `1px solid ${isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\"}`,\n\t\t\t\t\t\ttransition:\n\t\t\t\t\t\t\t\"box-shadow 0.25s cubic-bezier(0.4,0,0.2,1), border-color 0.25s cubic-bezier(0.4,0,0.2,1), transform 0.25s cubic-bezier(0.4,0,0.2,1)\",\n\t\t\t\t\t},\n\t\t\t\t\televation0: {\n\t\t\t\t\t\tborder: `1px solid ${isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\"}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiCard: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\televation: 0,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tborder: `1px solid ${isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\"}`,\n\t\t\t\t\t\ttransition:\n\t\t\t\t\t\t\t\"box-shadow 0.3s cubic-bezier(0.4,0,0.2,1), border-color 0.3s cubic-bezier(0.4,0,0.2,1), transform 0.25s cubic-bezier(0.4,0,0.2,1)\",\n\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\tborderColor: hexAlpha(primaryColor, 0.3),\n\t\t\t\t\t\t\tboxShadow: isLight\n\t\t\t\t\t\t\t\t? `0 4px 16px ${hexAlpha(primaryColor, 0.12)}`\n\t\t\t\t\t\t\t\t: `0 4px 16px ${hexAlpha(primaryColor, 0.2)}`,\n\t\t\t\t\t\t\ttransform: \"translateY(-1px)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- AppBar ----------\n\t\t\tMuiAppBar: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\televation: 0,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tbackgroundImage: \"none\", // override MuiPaper gradient — AppBar extends Paper\n\t\t\t\t\t\tborderBottom: `1px solid ${isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\"}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Buttons ----------\n\t\t\tMuiButton: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableElevation: true,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\ttextTransform: \"none\" as const,\n\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\tborderRadius: 6,\n\t\t\t\t\t\ttransition: \"all 0.15s ease\",\n\t\t\t\t\t},\n\t\t\t\t\tcontainedPrimary: {\n\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\tboxShadow: `0 2px 8px ${hexAlpha(primaryColor, 0.35)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tcontainedSecondary: {\n\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\tboxShadow: `0 2px 8px ${hexAlpha(secondaryColor, 0.35)}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\toutlined: {\n\t\t\t\t\t\tborderWidth: 1.5,\n\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\tborderWidth: 1.5,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiButtonGroup: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tdisableElevation: true,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiIconButton: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tborderRadius: 8,\n\t\t\t\t\t\ttransition: \"background-color 0.15s ease\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiFab: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tcolor: \"secondary\" as const,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tboxShadow: `0 3px 12px ${hexAlpha(secondaryColor, 0.3)}`,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Inputs ----------\n\t\t\tMuiTextField: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tvariant: \"outlined\" as const,\n\t\t\t\t\tsize: \"small\" as const,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiOutlinedInput: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tborderRadius: 6,\n\t\t\t\t\t\t\"&.Mui-focused .MuiOutlinedInput-notchedOutline\": {\n\t\t\t\t\t\t\tborderWidth: 2,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnotchedOutline: {\n\t\t\t\t\t\tborderColor: isLight ? \"rgba(0, 0, 0, 0.15)\" : \"rgba(255, 255, 255, 0.15)\",\n\t\t\t\t\t\ttransition: \"border-color 0.15s ease\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiInputLabel: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiSelect: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tsize: \"small\" as const,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiAutocomplete: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\tpaper: {\n\t\t\t\t\t\tborderRadius: 8,\n\t\t\t\t\t\tmarginTop: 4,\n\t\t\t\t\t\tboxShadow: isLight ? \"0 4px 20px rgba(0,0,0,0.1)\" : \"0 4px 20px rgba(0,0,0,0.4)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Checkbox / Radio / Switch ----------\n\t\t\tMuiCheckbox: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tcolor: \"primary\" as const,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiRadio: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tcolor: \"primary\" as const,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiSwitch: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tcolor: \"primary\" as const,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Lists & Navigation ----------\n\t\t\tMuiListItemButton: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tborderRadius: 6,\n\t\t\t\t\t\tmargin: \"1px 4px\",\n\t\t\t\t\t\ttransition: \"background-color 0.15s ease\",\n\t\t\t\t\t\t\"&.Mui-selected\": {\n\t\t\t\t\t\t\tbackgroundColor: hexAlpha(primaryColor, 0.1),\n\t\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\t\tbackgroundColor: hexAlpha(primaryColor, 0.16),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiListItemIcon: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tminWidth: 36,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Tabs ----------\n\t\t\tMuiTab: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\ttextTransform: \"none\" as const,\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t\tminHeight: 40,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiTabs: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\tindicator: {\n\t\t\t\t\t\theight: 2.5,\n\t\t\t\t\t\tborderRadius: \"2px 2px 0 0\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Tables ----------\n\t\t\tMuiTableHead: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\t\"& .MuiTableCell-head\": {\n\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t\tbackgroundColor: isLight ? \"rgba(0, 0, 0, 0.02)\" : \"rgba(255, 255, 255, 0.03)\",\n\t\t\t\t\t\t\tborderBottom: `2px solid ${isLight ? \"rgba(0, 0, 0, 0.1)\" : \"rgba(255, 255, 255, 0.1)\"}`,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiTableRow: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\t\"&:last-child td\": {\n\t\t\t\t\t\t\tborderBottom: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Data Grid ----------\n\t\t\tMuiDataGrid: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tborder: `1px solid ${isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\"}`,\n\t\t\t\t\t\tborderRadius: 8,\n\t\t\t\t\t\t\"& .MuiDataGrid-columnHeaders\": {\n\t\t\t\t\t\t\tbackgroundColor: isLight ? \"rgba(0, 0, 0, 0.02)\" : \"rgba(255, 255, 255, 0.03)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"& .MuiDataGrid-columnHeaderTitle\": {\n\t\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"& .MuiDataGrid-row:hover\": {\n\t\t\t\t\t\t\tbackgroundColor: isLight ? hexAlpha(primaryColor, 0.04) : hexAlpha(primaryColor, 0.08),\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"& .MuiDataGrid-row.Mui-selected\": {\n\t\t\t\t\t\t\tbackgroundColor: hexAlpha(primaryColor, 0.08),\n\t\t\t\t\t\t\t\"&:hover\": {\n\t\t\t\t\t\t\t\tbackgroundColor: hexAlpha(primaryColor, 0.12),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"& .MuiDataGrid-cell:focus\": {\n\t\t\t\t\t\t\toutline: `2px solid ${primaryColor}`,\n\t\t\t\t\t\t\toutlineOffset: -2,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Dialogs ----------\n\t\t\tMuiDialog: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tPaperProps: {\n\t\t\t\t\t\televation: 0,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\tpaper: {\n\t\t\t\t\t\tborderRadius: 16,\n\t\t\t\t\t\tboxShadow: isLight\n\t\t\t\t\t\t\t? `0 20px 60px rgba(0,0,0,0.15), 0 0 0 1px ${hexAlpha(primaryColor, 0.06)}`\n\t\t\t\t\t\t\t: `0 20px 60px rgba(0,0,0,0.6), 0 0 0 1px ${hexAlpha(primaryColor, 0.1)}`,\n\t\t\t\t\t},\n\t\t\t\t\troot: {\n\t\t\t\t\t\t\"& .MuiBackdrop-root\": {\n\t\t\t\t\t\t\tbackdropFilter: \"blur(4px)\",\n\t\t\t\t\t\t\tbackgroundColor: isLight ? \"rgba(0, 0, 0, 0.3)\" : \"rgba(0, 0, 0, 0.5)\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiDialogTitle: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t\tfontSize: \"1.1rem\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Chips & Badges ----------\n\t\t\tMuiChip: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t\tborderRadius: 6,\n\t\t\t\t\t\ttransition: \"background-color 0.2s ease, box-shadow 0.2s ease\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\tMuiBadge: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\tstandard: {\n\t\t\t\t\t\tfontWeight: 600,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Tooltips ----------\n\t\t\tMuiTooltip: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tarrow: true,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\ttooltip: {\n\t\t\t\t\t\tborderRadius: 6,\n\t\t\t\t\t\tfontSize: \"0.75rem\",\n\t\t\t\t\t\tfontWeight: 500,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Alerts / Snackbars ----------\n\t\t\tMuiAlert: {\n\t\t\t\tdefaultProps: {\n\t\t\t\t\tvariant: \"outlined\" as const,\n\t\t\t\t},\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tborderRadius: 8,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Drawer ----------\n\t\t\tMuiDrawer: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\tpaper: {\n\t\t\t\t\t\tborderRight: `1px solid ${isLight ? \"rgba(0, 0, 0, 0.08)\" : \"rgba(255, 255, 255, 0.08)\"}`,\n\t\t\t\t\t\tbackgroundImage: isLight\n\t\t\t\t\t\t\t? \"linear-gradient(180deg, rgba(255,255,255,0.95) 0%, rgba(245,246,250,0.95) 100%)\"\n\t\t\t\t\t\t\t: \"linear-gradient(180deg, rgba(19,47,76,0.95) 0%, rgba(10,25,41,0.95) 100%)\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Breadcrumbs ----------\n\t\t\tMuiBreadcrumbs: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tfontSize: \"0.8rem\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// ---------- Toolbar ----------\n\t\t\tMuiToolbar: {\n\t\t\t\tstyleOverrides: {\n\t\t\t\t\troot: {\n\t\t\t\t\t\tminHeight: \"52px !important\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n}\n\n/**\n * Generate a modern shadow set.\n * MUI expects exactly 25 entries (indices 0–24). We provide subtle shadows\n * that feel elevated without being heavy — suited to flat/modern enterprise UIs.\n */\nfunction createModernShadows(isLight: boolean): string[] {\n\tconst base = isLight ? \"0,0,0\" : \"0,0,0\";\n\t// Only the first few elevations really matter in practice\n\treturn [\n\t\t\"none\", // 0\n\t\t`0 1px 2px rgba(${base},0.06)`, // 1\n\t\t`0 1px 4px rgba(${base},0.08)`, // 2\n\t\t`0 2px 6px rgba(${base},0.1)`, // 3\n\t\t`0 2px 8px rgba(${base},0.1)`, // 4\n\t\t`0 3px 10px rgba(${base},0.1)`, // 5\n\t\t`0 3px 12px rgba(${base},0.12)`, // 6\n\t\t`0 4px 14px rgba(${base},0.12)`, // 7\n\t\t`0 4px 16px rgba(${base},0.14)`, // 8\n\t\t`0 5px 18px rgba(${base},0.14)`, // 9\n\t\t`0 5px 20px rgba(${base},0.14)`, // 10\n\t\t`0 6px 22px rgba(${base},0.14)`, // 11\n\t\t`0 6px 24px rgba(${base},0.16)`, // 12\n\t\t`0 7px 26px rgba(${base},0.16)`, // 13\n\t\t`0 7px 28px rgba(${base},0.16)`, // 14\n\t\t`0 8px 30px rgba(${base},0.16)`, // 15\n\t\t`0 8px 32px rgba(${base},0.18)`, // 16\n\t\t`0 9px 34px rgba(${base},0.18)`, // 17\n\t\t`0 9px 36px rgba(${base},0.18)`, // 18\n\t\t`0 10px 38px rgba(${base},0.18)`, // 19\n\t\t`0 10px 40px rgba(${base},0.2)`, // 20\n\t\t`0 11px 42px rgba(${base},0.2)`, // 21\n\t\t`0 11px 44px rgba(${base},0.2)`, // 22\n\t\t`0 12px 46px rgba(${base},0.2)`, // 23\n\t\t`0 12px 48px rgba(${base},0.22)`, // 24\n\t];\n}\n","/**\n * Theme presets for JUDO UI applications.\n *\n * Each preset defines a primary and secondary color pair that drives the\n * entire visual identity. Presets can be used as-is or as starting points\n * for further customization via `muiThemeOptions`.\n *\n * @example\n * ```ts\n * import { themePresets } from '@judo/app-shell';\n *\n * <JudoRuntime config={{\n * theme: {\n * preset: 'corporate',\n * // or override specific colors:\n * // primaryColor: '#custom',\n * }\n * }} />\n * ```\n */\n\nexport interface ThemePreset {\n\t/** Human-readable preset name */\n\tname: string;\n\t/** Primary brand color (hex) */\n\tprimaryColor: string;\n\t/** Secondary accent color (hex) */\n\tsecondaryColor: string;\n\t/** Optional background tint for light mode */\n\tlightBackground?: string;\n\t/** Optional background tint for dark mode */\n\tdarkBackground?: string;\n}\n\n/**\n * Built-in theme presets.\n *\n * All presets are designed for enterprise/ERP contexts:\n * - High contrast for readability\n * - Professional color combinations\n * - Suitable for both light and dark modes\n */\n/**\n * Built-in theme preset names.\n * The `(string & {})` allows custom preset names while preserving autocomplete for built-ins.\n */\nexport type ThemePresetName = \"corporate\" | \"ocean\" | \"slate\" | \"indigo\" | \"forest\" | \"royal\";\n\nexport const themePresets: Record<ThemePresetName, ThemePreset> = {\n\t/**\n\t * Default corporate blue — professional, trustworthy.\n\t * Good default for ERP/business applications.\n\t */\n\tcorporate: {\n\t\tname: \"Corporate\",\n\t\tprimaryColor: \"#1565C0\",\n\t\tsecondaryColor: \"#00897B\",\n\t\tlightBackground: \"#F5F6FA\",\n\t\tdarkBackground: \"#0A1929\",\n\t},\n\n\t/**\n\t * Deep ocean hues — calm, focused.\n\t * Works well for data-heavy dashboards.\n\t */\n\tocean: {\n\t\tname: \"Ocean\",\n\t\tprimaryColor: \"#0277BD\",\n\t\tsecondaryColor: \"#26A69A\",\n\t\tlightBackground: \"#F0F7FA\",\n\t\tdarkBackground: \"#0D1B2A\",\n\t},\n\n\t/**\n\t * Warm slate with amber accents — modern, distinctive.\n\t * Good for differentiated business suites.\n\t */\n\tslate: {\n\t\tname: \"Slate\",\n\t\tprimaryColor: \"#37474F\",\n\t\tsecondaryColor: \"#FF8F00\",\n\t\tlightBackground: \"#F7F8F9\",\n\t\tdarkBackground: \"#121212\",\n\t},\n\n\t/**\n\t * Indigo with coral accents — vibrant but professional.\n\t * Suitable for modern ERP with a creative edge.\n\t */\n\tindigo: {\n\t\tname: \"Indigo\",\n\t\tprimaryColor: \"#283593\",\n\t\tsecondaryColor: \"#F4511E\",\n\t\tlightBackground: \"#F5F5FB\",\n\t\tdarkBackground: \"#0D0D2B\",\n\t},\n\n\t/**\n\t * Emerald green with deep teal — nature, growth.\n\t * Great for sustainability-focused or finance apps.\n\t */\n\tforest: {\n\t\tname: \"Forest\",\n\t\tprimaryColor: \"#2E7D32\",\n\t\tsecondaryColor: \"#00695C\",\n\t\tlightBackground: \"#F4F8F4\",\n\t\tdarkBackground: \"#0A1F0A\",\n\t},\n\n\t/**\n\t * Rich purple with magenta accents — premium feel.\n\t * Suitable for HR, creative, or analytics platforms.\n\t */\n\troyal: {\n\t\tname: \"Royal\",\n\t\tprimaryColor: \"#4527A0\",\n\t\tsecondaryColor: \"#AD1457\",\n\t\tlightBackground: \"#F6F3FA\",\n\t\tdarkBackground: \"#1A0A2E\",\n\t},\n} as const;\n\n/**\n * Resolve a preset by name. Returns `undefined` if not found.\n */\nexport function resolvePreset(presetName: string): ThemePreset | undefined {\n\treturn themePresets[presetName as ThemePresetName];\n}\n","import { CssBaseline, ThemeProvider as MuiThemeProvider, createTheme } from \"@mui/material\";\nimport { deepmerge } from \"@mui/utils\";\nimport type { ReactNode } from \"react\";\nimport { useMemo } from \"react\";\nimport { useTheme } from \"../hooks/use-theme\";\nimport { createDensityThemeOptions } from \"./density\";\nimport { createJudoThemeOptions } from \"./judo-theme-factory\";\nimport { resolvePreset } from \"./presets\";\n\nexport interface ThemeProviderProps {\n\tchildren: ReactNode;\n}\n\n/**\n * Theme provider that creates MUI theme from service configuration.\n *\n * Theme merge order (each layer overrides the previous):\n * 1. JUDO theme factory — modern component overrides based on primary/secondary colors\n * 2. Density options — spacing/sizing adjustments for compact/comfortable/standard\n * 3. User-supplied muiThemeOptions — final overrides for full customization\n *\n * All layers are merged as raw ThemeOptions **before** calling `createTheme()`\n * once. This is critical because `createTheme` converts primitive values like\n * `spacing: 8` into functions (`theme.spacing()`). Passing multiple args to\n * `createTheme()` deep-merges subsequent args into the *processed* theme,\n * which can replace those functions with plain primitives and break MUI\n * components that call e.g. `theme.spacing(2)`.\n */\nexport function ThemeProvider({ children }: ThemeProviderProps) {\n\tconst { config } = useTheme();\n\tconst { mode, primaryColor, secondaryColor, muiThemeOptions, density, preset } = config;\n\n\t// Create MUI theme from config\n\tconst theme = useMemo(() => {\n\t\t// Resolve preset for fallback colors; default to \"corporate\" when not specified\n\t\tconst resolvedPreset = resolvePreset(preset || \"corporate\");\n\n\t\t// Determine effective colors: explicit > preset > MUI defaults\n\t\tconst effectivePrimary = primaryColor ?? resolvedPreset?.primaryColor;\n\t\tconst effectiveSecondary = secondaryColor ?? resolvedPreset?.secondaryColor;\n\n\t\t// When colors are available, use JUDO theme factory for full modern styling\n\t\tconst judoOptions =\n\t\t\teffectivePrimary && effectiveSecondary\n\t\t\t\t? createJudoThemeOptions({\n\t\t\t\t\t\tprimaryColor: effectivePrimary,\n\t\t\t\t\t\tsecondaryColor: effectiveSecondary,\n\t\t\t\t\t\tmode,\n\t\t\t\t\t\tlightBackground: resolvedPreset?.lightBackground,\n\t\t\t\t\t\tdarkBackground: resolvedPreset?.darkBackground,\n\t\t\t\t\t})\n\t\t\t\t: {\n\t\t\t\t\t\t// Minimal fallback when no colors are provided\n\t\t\t\t\t\tpalette: {\n\t\t\t\t\t\t\tmode,\n\t\t\t\t\t\t\tbackground: mode === \"light\" ? { default: \"#F5F6FA\" } : {},\n\t\t\t\t\t\t\t...(effectivePrimary && { primary: { main: effectivePrimary } }),\n\t\t\t\t\t\t\t...(effectiveSecondary && { secondary: { main: effectiveSecondary } }),\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\n\t\t// Density options are applied between JUDO theme and user overrides\n\t\tconst densityOptions = createDensityThemeOptions(density ?? \"compact\");\n\n\t\t// Merge all raw ThemeOptions into one object BEFORE createTheme processes\n\t\t// them. This ensures that e.g. `spacing: 6` is processed into a proper\n\t\t// spacing function instead of clobbering one during post-creation deepmerge.\n\t\t// Merge order: judoOptions <- densityOptions <- muiThemeOptions\n\t\tconst merged = deepmerge(deepmerge(judoOptions, densityOptions), muiThemeOptions ?? {});\n\t\treturn createTheme(merged);\n\t}, [mode, primaryColor, secondaryColor, muiThemeOptions, density, preset]);\n\n\treturn (\n\t\t<MuiThemeProvider theme={theme}>\n\t\t\t<CssBaseline />\n\t\t\t{children}\n\t\t</MuiThemeProvider>\n\t);\n}\n","import RefreshIcon from \"@mui/icons-material/Refresh\";\nimport { Alert, Box, Button, Typography } from \"@mui/material\";\n\nexport interface DefaultErrorScreenProps {\n\t/** The error that occurred */\n\terror: Error;\n\t/** Callback to retry initialization */\n\tonRetry?: () => void;\n}\n\n/**\n * Default error screen shown when model loading fails.\n */\nexport function DefaultErrorScreen({ error, onRetry }: DefaultErrorScreenProps) {\n\treturn (\n\t\t<Box\n\t\t\tdata-testid=\"error-screen\"\n\t\t\tsx={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\tminHeight: \"100vh\",\n\t\t\t\tgap: 3,\n\t\t\t\tp: 4,\n\t\t\t}}\n\t\t>\n\t\t\t<Typography variant=\"h5\" component=\"h1\" color=\"error\">\n\t\t\t\tApplication Error\n\t\t\t</Typography>\n\n\t\t\t<Alert severity=\"error\" sx={{ maxWidth: 600 }}>\n\t\t\t\t<Typography variant=\"body2\" component=\"pre\" sx={{ whiteSpace: \"pre-wrap\", wordBreak: \"break-word\" }}>\n\t\t\t\t\t{error.message}\n\t\t\t\t</Typography>\n\t\t\t</Alert>\n\n\t\t\t{onRetry && (\n\t\t\t\t<Button variant=\"contained\" startIcon={<RefreshIcon />} onClick={onRetry}>\n\t\t\t\t\tRetry\n\t\t\t\t</Button>\n\t\t\t)}\n\n\t\t\t{import.meta.env?.DEV && error.stack && (\n\t\t\t\t<Box\n\t\t\t\t\tcomponent=\"details\"\n\t\t\t\t\tsx={{\n\t\t\t\t\t\tmaxWidth: 800,\n\t\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\t\tmt: 2,\n\t\t\t\t\t}}\n\t\t\t\t>\n\t\t\t\t\t<Typography component=\"summary\" variant=\"body2\" color=\"text.secondary\" sx={{ cursor: \"pointer\" }}>\n\t\t\t\t\t\tStack trace\n\t\t\t\t\t</Typography>\n\t\t\t\t\t<Box\n\t\t\t\t\t\tcomponent=\"pre\"\n\t\t\t\t\t\tsx={{\n\t\t\t\t\t\t\tmt: 1,\n\t\t\t\t\t\t\tp: 2,\n\t\t\t\t\t\t\tbgcolor: \"grey.100\",\n\t\t\t\t\t\t\tborderRadius: 1,\n\t\t\t\t\t\t\tfontSize: \"0.75rem\",\n\t\t\t\t\t\t\toverflow: \"auto\",\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t{error.stack}\n\t\t\t\t\t</Box>\n\t\t\t\t</Box>\n\t\t\t)}\n\t\t</Box>\n\t);\n}\n","import { Box, CircularProgress, Typography } from \"@mui/material\";\n\n/**\n * Default loading screen shown during model initialization.\n */\nexport function DefaultLoadingScreen() {\n\treturn (\n\t\t<Box\n\t\t\tdata-testid=\"loading-screen\"\n\t\t\tsx={{\n\t\t\t\tdisplay: \"flex\",\n\t\t\t\tflexDirection: \"column\",\n\t\t\t\talignItems: \"center\",\n\t\t\t\tjustifyContent: \"center\",\n\t\t\t\tminHeight: \"100vh\",\n\t\t\t\tgap: 2,\n\t\t\t}}\n\t\t>\n\t\t\t<CircularProgress size={48} />\n\t\t\t<Typography variant=\"body1\" color=\"text.secondary\">\n\t\t\t\tLoading application...\n\t\t\t</Typography>\n\t\t</Box>\n\t);\n}\n","import { CssBaseline, ThemeProvider as MuiThemeProvider, createTheme } from \"@mui/material\";\nimport type { PaletteMode } from \"@mui/material\";\nimport { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { BrowserRouter, HashRouter, MemoryRouter, useNavigate } from \"react-router\";\n\nimport { ApiProvider, type JudoRestApi, createJudoRestApi, useApi } from \"@judo/actions\";\nimport { ActorAuthBoundary, JudoAuthProvider, createOidcOptions, getAuthConfig, useAuth } from \"@judo/auth\";\nimport type { OidcOptions } from \"@judo/auth\";\nimport {\n\tApplicationProvider,\n\tCustomizationsProvider,\n\tDataProvider,\n\tMuiProProvider,\n\tNavigationProvider,\n\tRuntimeConfigProvider,\n\tuseApplication,\n\tuseCustomizationsOptional,\n} from \"@judo/core\";\nimport { ExpressionProvider } from \"@judo/expressions\";\nimport { FeedbackProvider } from \"@judo/feedback\";\nimport { I18nProvider } from \"@judo/i18n\";\nimport type { Application, GuestPageProps, MenuLayout } from \"@judo/model-api\";\nimport { EmbeddedModelLoader, HttpModelLoader, ModelRegistry } from \"@judo/model-loader\";\nimport type { ComponentType } from \"react\";\n\nimport { initializeThemeStore } from \"../hooks/use-theme\";\nimport { AppShellLayout } from \"../layout/AppShellLayout\";\nimport { PrincipalBridge } from \"./PrincipalBridge\";\nimport { getRouteForPage } from \"../navigation/navigation-utils\";\nimport { DefaultGuestPage } from \"../routes/DefaultGuestPage\";\nimport { generateRoutes } from \"../routes/generate-routes\";\nimport { ThemeProvider } from \"../theme/ThemeProvider\";\nimport { DefaultErrorScreen } from \"./DefaultErrorScreen\";\nimport { DefaultLoadingScreen } from \"./DefaultLoadingScreen\";\nimport type { JudoRuntimeConfig, JudoRuntimeProps, JudoRuntimeState } from \"./types\";\n\n// Get initial mode from localStorage or system preference\nfunction getInitialMode(): \"light\" | \"dark\" {\n\tif (typeof window === \"undefined\") return \"light\";\n\tconst stored = localStorage.getItem(\"theme-mode\");\n\tif (stored === \"light\" || stored === \"dark\") return stored;\n\tif (typeof window.matchMedia === \"function\") {\n\t\treturn window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n\t}\n\treturn \"light\";\n}\n\n/**\n * JudoRuntime - Unified runtime layer for JUDO UI applications.\n *\n * Provides zero-boilerplate application setup:\n * - Model loading and parsing\n * - Provider tree (theme, notifications, dialogs, etc.)\n * - App shell layout with navigation\n * - Route generation from model\n *\n * @example\n * ```tsx\n * // Minimal usage\n * <JudoRuntime modelSource=\"/models/my-app.model\" />\n *\n * // With configuration\n * <JudoRuntime\n * config={{\n * model: { source: '/models/my-app.model' },\n * auth: { skip: true },\n * features: { devTools: true },\n * }}\n * />\n * ```\n */\nexport function JudoRuntime({\n\tconfig = {},\n\tmodelSource,\n\tlogo,\n\tappBarExtra,\n\tloadingComponent,\n\terrorComponent,\n\tchildren,\n\tcustomizations,\n}: JudoRuntimeProps) {\n\t// Merge shorthand modelSource with config\n\tconst effectiveConfig = useMemo<JudoRuntimeConfig>(\n\t\t() => ({\n\t\t\t...config,\n\t\t\tmodel: {\n\t\t\t\t...config.model,\n\t\t\t\tsource: modelSource ?? config.model?.source,\n\t\t\t},\n\t\t}),\n\t\t[config, modelSource]\n\t);\n\n\t// State\n\tconst [state, setState] = useState<JudoRuntimeState>({\n\t\tphase: \"initializing\",\n\t\terror: null,\n\t});\n\n\tconst [registry, setRegistry] = useState<ModelRegistry | null>(null);\n\tconst [api, setApi] = useState<JudoRestApi | null>(null);\n\tconst [muiProComponents, setMuiProComponents] = useState<Record<string, ComponentType<any>>>({});\n\tconst [initCount, setInitCount] = useState(0);\n\n\t// Initialize and load model\n\t// oxlint-disable-next-line react-hooks/exhaustive-deps -- initCount triggers re-init on retry\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\n\t\tasync function initialize() {\n\t\t\ttry {\n\t\t\t\tsetState({ phase: \"loading\", error: null });\n\n\t\t\t\t// Load model\n\t\t\t\tconst source = effectiveConfig.model?.source;\n\t\t\t\tif (!source) {\n\t\t\t\t\tthrow new Error(\"No model source provided. Pass modelSource prop or config.model.source.\");\n\t\t\t\t}\n\n\t\t\t\t// Handle both URL string and loader function\n\t\t\t\tlet applications: Application[];\n\t\t\t\tif (typeof source === \"function\") {\n\t\t\t\t\tconst content = await source();\n\t\t\t\t\tconst loader = new EmbeddedModelLoader(content);\n\t\t\t\t\tapplications = await loader.load();\n\t\t\t\t} else {\n\t\t\t\t\tconst loader = new HttpModelLoader();\n\t\t\t\t\tapplications = await loader.load(source);\n\t\t\t\t}\n\n\t\t\t\tif (applications.length === 0) {\n\t\t\t\t\tthrow new Error(\"No applications found in model\");\n\t\t\t\t}\n\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Create registry and activate application\n\t\t\t\tconst modelRegistry = new ModelRegistry();\n\t\t\t\tmodelRegistry.registerModel(applications);\n\n\t\t\t\tconst initialApp = effectiveConfig.model?.initialApplication ?? applications[0].name;\n\t\t\t\tmodelRegistry.setActiveApplication(initialApp);\n\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Get active application for API configuration\n\t\t\t\tconst activeApp = modelRegistry.getActiveApplication();\n\n\t\t\t\t// Create REST API client with Application context\n\t\t\t\tconst restApi = createJudoRestApi({\n\t\t\t\t\tbaseUrl: `${effectiveConfig.api?.baseUrl ?? window.location.origin}/api`,\n\t\t\t\t\tapplication: activeApp,\n\t\t\t\t\ttimeout: effectiveConfig.api?.timeout,\n\t\t\t\t\tdefaultHeaders: effectiveConfig.api?.headers,\n\t\t\t\t});\n\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\t// Activate MUI Pro if license key is configured\n\t\t\t\tlet resolvedMuiProComponents: Record<string, ComponentType<any>> = {};\n\t\t\t\tif (effectiveConfig.muiProLicenseKey) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst [licenseModule, proGridModule] = await Promise.all([\n\t\t\t\t\t\t\timport(\"@mui/x-license\"),\n\t\t\t\t\t\t\timport(\"@mui/x-data-grid-pro\"),\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tlicenseModule.LicenseInfo.setLicenseKey(effectiveConfig.muiProLicenseKey);\n\t\t\t\t\t\tresolvedMuiProComponents = {\n\t\t\t\t\t\t\tDataGrid: proGridModule.DataGridPro,\n\t\t\t\t\t\t};\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// MUI Pro packages not installed — fall back to community components\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (cancelled) return;\n\n\t\t\t\tsetRegistry(modelRegistry);\n\t\t\t\tsetApi(restApi);\n\t\t\t\tsetMuiProComponents(resolvedMuiProComponents);\n\t\t\t\tsetState({ phase: \"ready\", error: null });\n\t\t\t} catch (error) {\n\t\t\t\tif (cancelled) return;\n\t\t\t\tsetState({\n\t\t\t\t\tphase: \"error\",\n\t\t\t\t\terror: error instanceof Error ? error : new Error(String(error)),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tinitialize();\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [effectiveConfig, initCount]);\n\n\t// Retry handler\n\tconst handleRetry = useCallback(() => {\n\t\tsetInitCount((c) => c + 1);\n\t}, []);\n\n\t// Router component based on config\n\tconst RouterComponent = useMemo(() => {\n\t\tconst type = effectiveConfig.router?.type ?? \"browser\";\n\t\tswitch (type) {\n\t\t\tcase \"hash\":\n\t\t\t\treturn HashRouter;\n\t\t\tcase \"memory\":\n\t\t\t\treturn MemoryRouter;\n\t\t\tdefault:\n\t\t\t\treturn BrowserRouter;\n\t\t}\n\t}, [effectiveConfig.router?.type]);\n\n\t// Theme - initialize store with runtime config and OS preference tracking\n\tuseEffect(() => {\n\t\tconst themeConfig = effectiveConfig.theme ?? {};\n\t\tconst useSystemPreference = themeConfig.defaultMode === \"system\" || themeConfig.defaultMode === undefined;\n\t\tconst mode =\n\t\t\tthemeConfig.defaultMode === \"dark\" ? \"dark\" : themeConfig.defaultMode === \"light\" ? \"light\" : getInitialMode();\n\n\t\tinitializeThemeStore(\n\t\t\t{\n\t\t\t\tmode,\n\t\t\t\tprimaryColor: themeConfig.primaryColor,\n\t\t\t\tsecondaryColor: themeConfig.secondaryColor,\n\t\t\t\tmuiThemeOptions: themeConfig.muiThemeOptions,\n\t\t\t\tdensity: themeConfig.density,\n\t\t\t\tpreset: themeConfig.preset,\n\t\t\t},\n\t\t\tuseSystemPreference\n\t\t);\n\t}, [effectiveConfig.theme]);\n\n\t// Create theme for loading/error states\n\tconst theme = useMemo(() => {\n\t\tconst themeConfig = effectiveConfig.theme ?? {};\n\t\tconst mode: PaletteMode =\n\t\t\tthemeConfig.defaultMode === \"dark\" ? \"dark\" : themeConfig.defaultMode === \"light\" ? \"light\" : getInitialMode();\n\t\tconst baseConfig = {\n\t\t\tpalette: {\n\t\t\t\tmode,\n\t\t\t\t...(themeConfig.primaryColor && {\n\t\t\t\t\tprimary: { main: themeConfig.primaryColor },\n\t\t\t\t}),\n\t\t\t\t...(themeConfig.secondaryColor && {\n\t\t\t\t\tsecondary: { main: themeConfig.secondaryColor },\n\t\t\t\t}),\n\t\t\t},\n\t\t};\n\t\treturn themeConfig.muiThemeOptions ? createTheme(baseConfig, themeConfig.muiThemeOptions) : createTheme(baseConfig);\n\t}, [effectiveConfig.theme]);\n\n\t// Build OIDC options from config (memoized) — must be before early returns to maintain hook order\n\tconst oidcOptions = useMemo<OidcOptions | null>(() => {\n\t\tconst authConfig = effectiveConfig.auth;\n\t\tif (authConfig?.skip || !authConfig?.oidc) {\n\t\t\treturn null;\n\t\t}\n\t\treturn createOidcOptions(authConfig.oidc);\n\t}, [effectiveConfig.auth]);\n\n\t// Render loading state\n\tif (state.phase === \"initializing\" || state.phase === \"loading\") {\n\t\treturn (\n\t\t\t<MuiThemeProvider theme={theme}>\n\t\t\t\t<CssBaseline />\n\t\t\t\t{loadingComponent ?? <DefaultLoadingScreen />}\n\t\t\t</MuiThemeProvider>\n\t\t);\n\t}\n\n\t// Render error state\n\tif (state.phase === \"error\" && state.error) {\n\t\tconst errorContent =\n\t\t\ttypeof errorComponent === \"function\"\n\t\t\t\t? errorComponent(state.error, handleRetry)\n\t\t\t\t: (errorComponent ?? <DefaultErrorScreen error={state.error} onRetry={handleRetry} />);\n\n\t\treturn (\n\t\t\t<MuiThemeProvider theme={theme}>\n\t\t\t\t<CssBaseline />\n\t\t\t\t{errorContent}\n\t\t\t</MuiThemeProvider>\n\t\t);\n\t}\n\n\t// Render ready state\n\tif (!registry || !api) {\n\t\treturn null;\n\t}\n\n\t// Convert JudoRuntimeConfig to RuntimeConfig\n\tconst isProEnabled = Object.keys(muiProComponents).length > 0;\n\tconst runtimeConfig = {\n\t\tfeatures: effectiveConfig.features,\n\t\tdensity: effectiveConfig.theme?.density,\n\t\tmuiProLicenseKey: effectiveConfig.muiProLicenseKey,\n\t};\n\n\t// Get the model-defined default language for i18n\n\tconst activeApp = registry.getActiveApplication();\n\tconst modelDefaultLanguage = activeApp.defaultLanguage ?? \"en-US\";\n\tconst i18nConfig = effectiveConfig.i18n;\n\n\treturn (\n\t\t<CustomizationsProvider customizations={customizations}>\n\t\t\t<ThemeProvider>\n\t\t\t\t<FeedbackProvider>\n\t\t\t\t\t<ApiProvider api={api}>\n\t\t\t\t\t\t<RuntimeConfigProvider config={runtimeConfig}>\n\t\t\t\t\t\t\t<MuiProProvider isProEnabled={isProEnabled} components={muiProComponents}>\n\t\t\t\t\t\t\t\t<ApplicationProvider registry={registry}>\n\t\t\t\t\t\t\t\t\t<ExpressionProvider>\n\t\t\t\t\t\t\t\t\t\t<I18nProvider\n\t\t\t\t\t\t\t\t\t\t\tdefaultLocale={modelDefaultLanguage}\n\t\t\t\t\t\t\t\t\t\t\tlocales={i18nConfig?.locales}\n\t\t\t\t\t\t\t\t\t\t\tlocaleLoader={i18nConfig?.localeLoader}\n\t\t\t\t\t\t\t\t\t\t\ttranslationKeyMap={i18nConfig?.translationKeyMap}\n\t\t\t\t\t\t\t\t\t\t\tpersistLocale={i18nConfig?.persistLocale}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<AuthBridge\n\t\t\t\t\t\t\t\t\t\t\t\toidcOptions={oidcOptions}\n\t\t\t\t\t\t\t\t\t\t\t\tskipAuth={effectiveConfig.auth?.skip}\n\t\t\t\t\t\t\t\t\t\t\t\tloadingComponent={loadingComponent}\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<DataProvider>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<RouterComponent basename={effectiveConfig.router?.basePath}>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<NavigationProviderBridge\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tlogo={logo}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tappBarExtra={appBarExtra}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tmenuLayout={effectiveConfig.menuLayout}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t{children ?? <ApplicationRoutes />}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</NavigationProviderBridge>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</RouterComponent>\n\t\t\t\t\t\t\t\t\t\t\t\t</DataProvider>\n\t\t\t\t\t\t\t\t\t\t\t</AuthBridge>\n\t\t\t\t\t\t\t\t\t\t</I18nProvider>{\" \"}\n\t\t\t\t\t\t\t\t\t</ExpressionProvider>{\" \"}\n\t\t\t\t\t\t\t\t</ApplicationProvider>\n\t\t\t\t\t\t\t</MuiProProvider>\n\t\t\t\t\t\t</RuntimeConfigProvider>\n\t\t\t\t\t</ApiProvider>\n\t\t\t\t</FeedbackProvider>\n\t\t\t</ThemeProvider>\n\t\t</CustomizationsProvider>\n\t);\n}\n\n/**\n * Bridge component that connects auth providers with the active application.\n * Must be rendered inside ApplicationProvider to access useApplication().\n *\n * When auth is not skipped and OIDC options are provided, wraps children\n * in JudoAuthProvider + ActorAuthBoundary. Otherwise renders children directly.\n *\n * When the active application has `supportGuestAccess: true`, passes the\n * resolved guest component to `ActorAuthBoundary` so unauthenticated users\n * see a guest page instead of being auto-redirected to OIDC.\n */\nfunction AuthBridge({\n\toidcOptions,\n\tskipAuth,\n\tloadingComponent,\n\tchildren,\n}: {\n\toidcOptions: OidcOptions | null;\n\tskipAuth?: boolean;\n\tloadingComponent?: ReactNode;\n\tchildren: ReactNode;\n}) {\n\tconst { application } = useApplication();\n\tconst customizations = useCustomizationsOptional();\n\n\tconst authConfig = useMemo(() => getAuthConfig(application), [application]);\n\n\t// Skip auth entirely — render children directly\n\tif (skipAuth || !oidcOptions) {\n\t\treturn <>{children}</>;\n\t}\n\n\t// Resolve guest component from customizations or use DefaultGuestPage\n\tconst supportGuestAccess = String(application.supportGuestAccess) === \"true\";\n\tconst GuestComponent = customizations?.getGuestComponent() ?? DefaultGuestPage;\n\n\treturn (\n\t\t<JudoAuthProvider config={authConfig} oidcOptions={oidcOptions}>\n\t\t\t<AuthTokenSync />\n\t\t\t<ActorAuthBoundary\n\t\t\t\tloadingComponent={loadingComponent}\n\t\t\t\tsupportGuestAccess={supportGuestAccess}\n\t\t\t\tguestComponent={\n\t\t\t\t\tsupportGuestAccess ? <GuestPageBridge application={application} GuestComponent={GuestComponent} /> : undefined\n\t\t\t\t}\n\t\t\t>\n\t\t\t\t<PrincipalBridge>{children}</PrincipalBridge>\n\t\t\t</ActorAuthBoundary>\n\t\t</JudoAuthProvider>\n\t);\n}\n\n/**\n * Bridge that renders the guest page component with `signIn` wired to `useAuth().signinRedirect`.\n * Must be rendered inside JudoAuthProvider so `useAuth()` is available.\n */\nfunction GuestPageBridge({\n\tapplication,\n\tGuestComponent,\n}: {\n\tapplication: Application;\n\tGuestComponent: ComponentType<GuestPageProps>;\n}) {\n\tconst { signinRedirect } = useAuth();\n\tconst signIn = useCallback(() => {\n\t\tvoid signinRedirect();\n\t}, [signinRedirect]);\n\treturn <GuestComponent application={application} signIn={signIn} />;\n}\n\n/**\n * Syncs the OIDC access token into the JudoRestApi default headers.\n * Rendered inside JudoAuthProvider + ApiProvider so both useAuth() and useApi() are available.\n * Updates the Authorization header whenever the token changes — no interceptors needed.\n */\nfunction AuthTokenSync() {\n\tconst { user } = useAuth();\n\tconst api = useApi();\n\tconst prevTokenRef = useRef<string | undefined>(undefined);\n\n\tuseEffect(() => {\n\t\tconst token = user?.access_token;\n\t\tif (token !== prevTokenRef.current) {\n\t\t\tprevTokenRef.current = token;\n\t\t\tif (token) {\n\t\t\t\tapi.setDefaultHeaders({ Authorization: `Bearer ${token}` });\n\t\t\t} else {\n\t\t\t\tapi.setDefaultHeaders({});\n\t\t\t}\n\t\t}\n\t}, [api, user?.access_token]);\n\n\treturn null;\n}\n\n/**\n * Bridge component that connects NavigationProvider with React Router.\n * Must be rendered inside Router to access useNavigate.\n */\nfunction NavigationProviderBridge({\n\tlogo,\n\tappBarExtra,\n\tmenuLayout,\n\tchildren,\n}: {\n\tlogo?: ReactNode;\n\tappBarExtra?: ReactNode;\n\tmenuLayout?: MenuLayout;\n\tchildren?: ReactNode;\n}) {\n\tconst navigate = useNavigate();\n\n\treturn (\n\t\t<NavigationProvider navigate={navigate} getRouteForPage={getRouteForPage}>\n\t\t\t<AppShellLayout logo={logo} appBarExtra={appBarExtra} menuLayout={menuLayout}>\n\t\t\t\t{children}\n\t\t\t</AppShellLayout>\n\t\t</NavigationProvider>\n\t);\n}\n\n/**\n * Internal component that renders routes based on the current application.\n * Uses useApplication() to reactively update when the active application changes.\n */\nfunction ApplicationRoutes() {\n\tconst { application } = useApplication();\n\tconst customizations = useCustomizationsOptional();\n\tconst customRoutes = customizations?.getCustomRoutes();\n\tconst SettingsPage = customizations?.getSettingsPage();\n\treturn generateRoutes({ application, customRoutes, SettingsPage });\n}\n","import ErrorIcon from \"@mui/icons-material/Error\";\nimport { Box, Button, Paper, Typography } from \"@mui/material\";\nimport { Component, type ErrorInfo, type ReactNode } from \"react\";\n\nexport interface AppErrorBoundaryProps {\n\tchildren: ReactNode;\n}\n\ninterface AppErrorBoundaryState {\n\thasError: boolean;\n\terror: Error | null;\n}\n\n/**\n * Root error boundary for application-level errors.\n * No retry - user must refresh page.\n */\nexport class AppErrorBoundary extends Component<AppErrorBoundaryProps, AppErrorBoundaryState> {\n\tstate: AppErrorBoundaryState = {\n\t\thasError: false,\n\t\terror: null,\n\t};\n\n\tstatic getDerivedStateFromError(error: Error): AppErrorBoundaryState {\n\t\treturn { hasError: true, error };\n\t}\n\n\tcomponentDidCatch(error: Error, errorInfo: ErrorInfo): void {\n\t\tconsole.error(\"Application error:\", error, errorInfo);\n\t}\n\n\trender() {\n\t\tif (this.state.hasError) {\n\t\t\treturn (\n\t\t\t\t<Box\n\t\t\t\t\tdisplay=\"flex\"\n\t\t\t\t\tjustifyContent=\"center\"\n\t\t\t\t\talignItems=\"center\"\n\t\t\t\t\tminHeight=\"100vh\"\n\t\t\t\t\tp={4}\n\t\t\t\t\tdata-testid=\"app-error-boundary\"\n\t\t\t\t>\n\t\t\t\t\t<Paper sx={{ p: 4, maxWidth: 500, textAlign: \"center\" }}>\n\t\t\t\t\t\t<ErrorIcon color=\"error\" sx={{ fontSize: 64, mb: 2 }} />\n\t\t\t\t\t\t<Typography variant=\"h5\" gutterBottom>\n\t\t\t\t\t\t\tApplication Error\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Typography color=\"text.secondary\" paragraph>\n\t\t\t\t\t\t\tAn unexpected error occurred. Please refresh the page to continue.\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Typography\n\t\t\t\t\t\t\tvariant=\"body2\"\n\t\t\t\t\t\t\tcolor=\"error\"\n\t\t\t\t\t\t\tfontFamily=\"monospace\"\n\t\t\t\t\t\t\tsx={{ mb: 2 }}\n\t\t\t\t\t\t\tdata-testid=\"app-error-boundary::message\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{this.state.error?.message}\n\t\t\t\t\t\t</Typography>\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tvariant=\"contained\"\n\t\t\t\t\t\t\tonClick={() => window.location.reload()}\n\t\t\t\t\t\t\tdata-testid=\"app-error-boundary::refresh\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\tRefresh Page\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</Paper>\n\t\t\t\t</Box>\n\t\t\t);\n\t\t}\n\n\t\treturn this.props.children;\n\t}\n}\n","import type { ReactNode } from \"react\";\nimport { AppErrorBoundary } from \"./errors/AppErrorBoundary\";\nimport { AppShellLayout } from \"./layout/AppShellLayout\";\nimport { ThemeProvider } from \"./theme/ThemeProvider\";\n\nexport interface AppShellProps {\n\t/** Children rendered in main content area */\n\tchildren: ReactNode;\n\t/** Custom logo component */\n\tlogo?: ReactNode;\n\t/** Additional app bar items */\n\tappBarExtra?: ReactNode;\n}\n\n/**\n * Main application shell providing admin dashboard layout.\n * Requires ApplicationContext (model must be loaded).\n */\nexport function AppShell({ children, logo, appBarExtra }: AppShellProps) {\n\treturn (\n\t\t<ThemeProvider>\n\t\t\t<AppErrorBoundary>\n\t\t\t\t<AppShellLayout logo={logo} appBarExtra={appBarExtra}>\n\t\t\t\t\t{children}\n\t\t\t\t</AppShellLayout>\n\t\t\t</AppErrorBoundary>\n\t\t</ThemeProvider>\n\t);\n}\n","import { useAuth } from \"@judo/auth\";\nimport { getUserMenuTestId } from \"@judo/test-ids\";\nimport LogoutIcon from \"@mui/icons-material/Logout\";\nimport PersonIcon from \"@mui/icons-material/Person\";\nimport SettingsIcon from \"@mui/icons-material/Settings\";\nimport {\n\tAvatar,\n\tBox,\n\tDivider,\n\tIconButton,\n\tListItemIcon,\n\tListItemText,\n\tMenu,\n\tMenuItem,\n\tTypography,\n} from \"@mui/material\";\nimport { useState } from \"react\";\n\nexport interface UserMenuProps {\n\tclassName?: string;\n}\n\n/**\n * User menu with profile info and logout action.\n */\nexport function UserMenu({ className }: UserMenuProps) {\n\tconst [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);\n\tconst { principal, signoutRedirect, requiresAuth } = useAuth();\n\n\t// Don't render if no auth required\n\tif (!requiresAuth) {\n\t\treturn null;\n\t}\n\n\tconst handleLogout = () => {\n\t\tsetAnchorEl(null);\n\t\tsignoutRedirect();\n\t};\n\n\tconst triggerTestId = getUserMenuTestId(\"trigger\");\n\tconst displayName = principal?.preferredUsername ?? principal?.name ?? \"User\";\n\tconst initial = displayName[0] ?? \"?\";\n\n\treturn (\n\t\t<>\n\t\t\t<IconButton\n\t\t\t\tonClick={(e) => setAnchorEl(e.currentTarget)}\n\t\t\t\tcolor=\"inherit\"\n\t\t\t\tclassName={className}\n\t\t\t\tdata-testid={triggerTestId}\n\t\t\t>\n\t\t\t\t<Avatar sx={{ width: 32, height: 32 }}>{initial}</Avatar>\n\t\t\t</IconButton>\n\n\t\t\t<Menu\n\t\t\t\tanchorEl={anchorEl}\n\t\t\t\topen={!!anchorEl}\n\t\t\t\tonClose={() => setAnchorEl(null)}\n\t\t\t\tdata-testid={getUserMenuTestId(\"menu\")}\n\t\t\t>\n\t\t\t\t{/* User Info Header */}\n\t\t\t\t<Box sx={{ px: 2, py: 1 }}>\n\t\t\t\t\t<Typography variant=\"subtitle1\">{displayName}</Typography>\n\t\t\t\t\t<Typography variant=\"body2\" color=\"text.secondary\">\n\t\t\t\t\t\t{principal?.email}\n\t\t\t\t\t</Typography>\n\t\t\t\t</Box>\n\n\t\t\t\t<Divider />\n\n\t\t\t\t{/* Profile Link */}\n\t\t\t\t<MenuItem onClick={() => setAnchorEl(null)} data-testid={getUserMenuTestId(\"profile\")}>\n\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t<PersonIcon fontSize=\"small\" />\n\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t<ListItemText>Profile</ListItemText>\n\t\t\t\t</MenuItem>\n\n\t\t\t\t{/* Settings Link */}\n\t\t\t\t<MenuItem onClick={() => setAnchorEl(null)} data-testid={getUserMenuTestId(\"settings\")}>\n\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t<SettingsIcon fontSize=\"small\" />\n\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t<ListItemText>Settings</ListItemText>\n\t\t\t\t</MenuItem>\n\n\t\t\t\t<Divider />\n\n\t\t\t\t{/* Logout */}\n\t\t\t\t<MenuItem onClick={handleLogout} data-testid={getUserMenuTestId(\"logout\")}>\n\t\t\t\t\t<ListItemIcon>\n\t\t\t\t\t\t<LogoutIcon fontSize=\"small\" />\n\t\t\t\t\t</ListItemIcon>\n\t\t\t\t\t<ListItemText>Logout</ListItemText>\n\t\t\t\t</MenuItem>\n\t\t\t</Menu>\n\t\t</>\n\t);\n}\n"],"x_google_ignoreList":[25,26,27,28],"mappings":"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AgB,IAAK,IACtD,EACD;KACD,UAAU;MACT,aAAa;MACb,WAAW,EACV,aAAa,KACb;MACD;KACD;IACD;GAED,gBAAgB,EACf,cAAc,EACb,kBAAkB,IAClB,EACD;GAED,eAAe,EACd,gBAAgB,EACf,MAAM;IACL,cAAc;IACd,YAAY;IACZ,EACD,EACD;GAED,QAAQ;IACP,cAAc,EACb,OAAO,aACP;IACD,gBAAgB,EACf,MAAM,EACL,WAAW,cAAc,SAAS,GAAgB,GAAI,IACtD,EACD;IACD;GAGD,cAAc,EACb,cAAc;IACb,SAAS;IACT,MAAM;IACN,EACD;GAED,kBAAkB,EACjB,gBAAgB;IACf,MAAM;KACL,cAAc;KACd,kDAAkD,EACjD,aAAa,GACb;KACD;IACD,gBAAgB;KACf,aAAa,IAAU,wBAAwB;KAC/C,YAAY;KACZ;IACD,EACD;GAED,eAAe,EACd,gBAAgB,EACf,MAAM,EACL,YAAY,KACZ,EACD,EACD;GAED,WAAW,EACV,cAAc,EACb,MAAM,SACN,EACD;GAED,iBAAiB,EAChB,gBAAgB,EACf,OAAO;IACN,cAAc;IACd,WAAW;IACX,WAAW,IAAU,+BAA+B;IACpD,EACD,EACD;GAGD,aAAa,EACZ,cAAc,EACb,OAAO,WACP,EACD;GAED,UAAU,EACT,cAAc,EACb,OAAO,WACP,EACD;GAED,WAAW,EACV,cAAc,EACb,OAAO,WACP,EACD;GAGD,mBAAmB,EAClB,gBAAgB,EACf,MAAM;IACL,cAAc;IACd,QAAQ;IACR,YAAY;IACZ,kBAAkB;KACjB,iBAAiB,SAAS,GAAc,GAAI;KAC5C,WAAW,EACV,iBAAiB,SAAS,GAAc,IAAK,EAC7C;KACD;IACD,EACD,EACD;GAED,iBAAiB,EAChB,gBAAgB,EACf,MAAM,EACL,UAAU,IACV,EACD,EACD;GAGD,QAAQ,EACP,gBAAgB,EACf,MAAM;IACL,eAAe;IACf,YAAY;IACZ,WAAW;IACX,EACD,EACD;GAED,SAAS,EACR,gBAAgB,EACf,WAAW;IACV,QAAQ;IACR,cAAc;IACd,EACD,EACD;GAGD,cAAc,EACb,gBAAgB,EACf,MAAM,EACL,wBAAwB;IACvB,YAAY;IACZ,iBAAiB,IAAU,wBAAwB;IACnD,cAAc,aAAa,IAAU,uBAAuB;IAC5D,EACD,EACD,EACD;GAED,aAAa,EACZ,gBAAgB,EACf,MAAM,EACL,mBAAmB,EAClB,cAAc,GACd,EACD,EACD,EACD;GAGD,aAAa,EACZ,gBAAgB,EACf,MAAM;IACL,QAAQ,aAAa,IAAU,wBAAwB;IACvD,cAAc;IACd,gCAAgC,EAC/B,iBAAiB,IAAU,wBAAwB,6BACnD;IACD,oCAAoC,EACnC,YAAY,KACZ;IACD,4BAA4B,EAC3B,iBAAiB,IAAU,SAAS,GAAc,IAAK,GAAG,SAAS,GAAc,IAAK,EACtF;IACD,mCAAmC;KAClC,iBAAiB,SAAS,GAAc,IAAK;KAC7C,WAAW,EACV,iBAAiB,SAAS,GAAc,IAAK,EAC7C;KACD;IACD,6BAA6B;KAC5B,SAAS,aAAa;KACtB,eAAe;KACf;IACD,EACD,EACD;GAGD,WAAW;IACV,cAAc,EACb,YAAY,EACX,WAAW,GACX,EACD;IACD,gBAAgB;KACf,OAAO;MACN,cAAc;MACd,WAAW,IACR,2CAA2C,SAAS,GAAc,IAAK,KACvE,0CAA0C,SAAS,GAAc,GAAI;MACxE;KACD,MAAM,EACL,uBAAuB;MACtB,gBAAgB;MAChB,iBAAiB,IAAU,uBAAuB;MAClD,EACD;KACD;IACD;GAED,gBAAgB,EACf,gBAAgB,EACf,MAAM;IACL,YAAY;IACZ,UAAU;IACV,EACD,EACD;GAGD,SAAS,EACR,gBAAgB,EACf,MAAM;IACL,YAAY;IACZ,cAAc;IACd,YAAY;IACZ,EACD,EACD;GAED,UAAU,EACT,gBAAgB,EACf,UAAU,EACT,YAAY,KACZ,EACD,EACD;GAGD,YAAY;IACX,cAAc,EACb,OAAO,IACP;IACD,gBAAgB,EACf,SAAS;KACR,cAAc;KACd,UAAU;KACV,YAAY;KACZ,EACD;IACD;GAGD,UAAU;IACT,cAAc,EACb,SAAS,YACT;IACD,gBAAgB,EACf,MAAM,EACL,cAAc,GACd,EACD;IACD;GAGD,WAAW,EACV,gBAAgB,EACf,OAAO;IACN,aAAa,aAAa,IAAU,wBAAwB;IAC5D,iBAAiB,IACd,oFACA;IACH,EACD,EACD;GAGD,gBAAgB,EACf,gBAAgB,EACf,MAAM,EACL,UAAU,UACV,EACD,EACD;GAGD,YAAY,EACX,gBAAgB,EACf,MAAM,EACL,WAAW,mBACX,EACD,EACD;GACD;EACD;;AAQF,SAAS,oBAAoB,GAA4B;CACxD,IAAM,IAAiB;AAEvB,QAAO;EACN;EACA,kBAAkB,EAAK;EACvB,kBAAkB,EAAK;EACvB,kBAAkB,EAAK;EACvB,kBAAkB,EAAK;EACvB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,mBAAmB,EAAK;EACxB,oBAAoB,EAAK;EACzB,oBAAoB,EAAK;EACzB,oBAAoB,EAAK;EACzB,oBAAoB,EAAK;EACzB,oBAAoB,EAAK;EACzB,oBAAoB,EAAK;EACzB;;AC7eF,MAAaC,eAAqD;CAKjE,WAAW;EACV,MAAM;EACN,cAAc;EACd,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB;CAMD,OAAO;EACN,MAAM;EACN,cAAc;EACd,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB;CAMD,OAAO;EACN,MAAM;EACN,cAAc;EACd,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB;CAMD,QAAQ;EACP,MAAM;EACN,cAAc;EACd,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB;CAMD,QAAQ;EACP,MAAM;EACN,cAAc;EACd,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB;CAMD,OAAO;EACN,MAAM;EACN,cAAc;EACd,gBAAgB;EAChB,iBAAiB;EACjB,gBAAgB;EAChB;CACD;AAKD,SAAgB,cAAc,GAA6C;AAC1E,QAAO,aAAa;;AClGrB,SAAgB,cAAc,EAAE,eAAgC;CAC/D,IAAM,EAAE,cAAW,UAAU,EACvB,EAAE,SAAM,iBAAc,mBAAgB,oBAAiB,YAAS,cAAW;AA0CjF,QACC,qBAAC,iBAAA;EAAwB,OAxCZ,cAAc;GAE3B,IAAM,IAAiB,cAAc,KAAU,YAAY,EAGrD,IAAmB,KAAgB,GAAgB,cACnD,IAAqB,KAAkB,GAAgB;AA8B7D,UAAO,YADQ,UAAU,UAzBxB,KAAoB,IACjB,uBAAuB;IACvB,cAAc;IACd,gBAAgB;IAChB;IACA,iBAAiB,GAAgB;IACjC,gBAAgB,GAAgB;IAChC,CAAC,GACD,EAEA,SAAS;IACR;IACA,YAAY,MAAS,UAAU,EAAE,SAAS,WAAW,GAAG,EAAE;IAC1D,GAAI,KAAoB,EAAE,SAAS,EAAE,MAAM,GAAkB,EAAE;IAC/D,GAAI,KAAsB,EAAE,WAAW,EAAE,MAAM,GAAoB,EAAE;IACrE,EACD,EAGmB,0BAA0B,KAAW,UAAU,CAMP,EAAE,KAAmB,EAAE,CAAC,CAC7D;KACxB;GAAC;GAAM;GAAc;GAAgB;GAAiB;GAAS;GAAO,CAAC;aAIxE,oBAAC,aAAA,EAAA,CAAc,EACd,EAAA;GACiB;;AC/DrB,SAAgB,mBAAmB,EAAE,UAAO,cAAoC;AAC/E,QACC,qBAAC,KAAA;EACA,eAAY;EACZ,IAAI;GACH,SAAS;GACT,eAAe;GACf,YAAY;GACZ,gBAAgB;GAChB,WAAW;GACX,KAAK;GACL,GAAG;GACH;;GAED,oBAAC,YAAA;IAAW,SAAQ;IAAK,WAAU;IAAK,OAAM;cAAQ;KAEzC;GAEb,oBAAC,OAAA;IAAM,UAAS;IAAQ,IAAI,EAAE,UAAU,KAAK;cAC5C,oBAAC,YAAA;KAAW,SAAQ;KAAQ,WAAU;KAAM,IAAI;MAAE,YAAY;MAAY,WAAW;MAAc;eACjG,EAAM;MACK;KACN;GAEP,KACA,oBAAC,QAAA;IAAO,SAAQ;IAAY,WAAW,oBAAC,aAAA,EAAA,CAAc;IAAE,SAAS;cAAS;KAEjE;;;GA8BL;;ACjER,SAAgB,uBAAuB;AACtC,QACC,qBAAC,KAAA;EACA,eAAY;EACZ,IAAI;GACH,SAAS;GACT,eAAe;GACf,YAAY;GACZ,gBAAgB;GAChB,WAAW;GACX,KAAK;GACL;aAED,oBAAC,kBAAA,EAAiB,MAAM,IAAA,CAAM,EAC9B,oBAAC,YAAA;GAAW,SAAQ;GAAQ,OAAM;aAAiB;IAEtC,CAAA;GACR;;ACeR,SAAS,iBAAmC;AAC3C,KAAI,OAAO,SAAW,IAAa,QAAO;CAC1C,IAAM,IAAS,aAAa,QAAQ,aAAa;AAKjD,QAJI,MAAW,WAAW,MAAW,SAAe,IAChD,OAAO,OAAO,cAAe,cACzB,OAAO,WAAW,+BAA+B,CAAC,UAAU,SAAS;;AA6B9E,SAAgB,YAAY,EAC3B,YAAS,EAAE,EACX,gBACA,SACA,gBACA,qBACA,mBACA,aACA,qBACoB;CAEpB,IAAM,IAAkB,eAChB;EACN,GAAG;EACH,OAAO;GACN,GAAG,EAAO;GACV,QAAQ,KAAe,EAAO,OAAO;GACrC;EACD,GACD,CAAC,GAAQ,EAAY,CACrB,EAGK,CAAC,GAAO,KAAY,SAA2B;EACpD,OAAO;EACP,OAAO;EACP,CAAC,EAEI,CAAC,GAAU,KAAe,SAA+B,KAAK,EAC9D,CAAC,GAAK,KAAU,SAA6B,KAAK,EAClD,CAAC,GAAkB,KAAuB,SAA6C,EAAE,CAAC,EAC1F,CAAC,GAAW,KAAgB,SAAS,EAAE;AAI7C,iBAAgB;EACf,IAAI,IAAY;EAEhB,eAAe,IAAa;AAC3B,OAAI;AACH,MAAS;KAAE,OAAO;KAAW,OAAO;KAAM,CAAC;IAG3C,IAAM,IAAS,EAAgB,OAAO;AACtC,QAAI,CAAC,EACJ,OAAU,MAAM,0EAA0E;IAI3F,IAAIC;AAUJ,QATA,AAMC,IANG,OAAO,KAAW,aAGN,MADA,IAAI,oBADH,MAAM,GAAQ,CACiB,CACnB,MAAM,GAGnB,MADA,IAAI,iBAAiB,CACR,KAAK,EAAO,EAGrC,EAAa,WAAW,EAC3B,OAAU,MAAM,iCAAiC;AAGlD,QAAI,EAAW;IAGf,IAAM,IAAgB,IAAI,eAAe;AAMzC,QALA,EAAc,cAAc,EAAa,EAGzC,EAAc,qBADK,EAAgB,OAAO,sBAAsB,EAAa,GAAG,KAClC,EAE1C,EAAW;IAGf,IAAM,IAAY,EAAc,sBAAsB,EAGhD,IAAU,kBAAkB;KACjC,SAAS,GAAG,EAAgB,KAAK,WAAW,OAAO,SAAS,OAAO;KACnE,aAAa;KACb,SAAS,EAAgB,KAAK;KAC9B,gBAAgB,EAAgB,KAAK;KACrC,CAAC;AAEF,QAAI,EAAW;IAGf,IAAIC,IAA+D,EAAE;AACrE,QAAI,EAAgB,iBACnB,KAAI;KACH,IAAM,CAAC,GAAe,KAAiB,MAAM,QAAQ,IAAI,CACxD,OAAO,mBACP,OAAO,wBACP,CAAC;AAEF,KADA,EAAc,YAAY,cAAc,EAAgB,iBAAiB,EACzE,IAA2B,EAC1B,UAAU,EAAc,aACxB;YACM;AAKT,QAAI,EAAW;AAKf,IAHA,EAAY,EAAc,EAC1B,EAAO,EAAQ,EACf,EAAoB,EAAyB,EAC7C,EAAS;KAAE,OAAO;KAAS,OAAO;KAAM,CAAC;YACjC,GAAO;AACf,QAAI,EAAW;AACf,MAAS;KACR,OAAO;KACP,OAAO,aAAiB,QAAQ,IAAY,MAAM,OAAO,EAAM,CAAC;KAChE,CAAC;;;AAMJ,SAFA,GAAY,QAEC;AACZ,OAAY;;IAEX,CAAC,GAAiB,EAAU,CAAC;CAGhC,IAAM,IAAc,kBAAkB;AACrC,KAAc,MAAM,IAAI,EAAE;IACxB,EAAE,CAAC,EAGA,IAAkB,cAAc;AAErC,UADa,EAAgB,QAAQ,QAAQ,WAC7C;GACC,KAAK,OACJ,QAAO;GACR,KAAK,SACJ,QAAO;GACR,QACC,QAAO;;IAEP,CAAC,EAAgB,QAAQ,KAAK,CAAC;AAGlC,iBAAgB;EACf,IAAM,IAAc,EAAgB,SAAS,EAAE,EACzC,IAAsB,EAAY,gBAAgB,YAAY,EAAY,gBAAgB,KAAA;AAIhG,uBACC;GACC,MAJD,EAAY,gBAAgB,SAAS,SAAS,EAAY,gBAAgB,UAAU,UAAU,gBAAgB;GAK7G,cAAc,EAAY;GAC1B,gBAAgB,EAAY;GAC5B,iBAAiB,EAAY;GAC7B,SAAS,EAAY;GACrB,QAAQ,EAAY;GACpB,EACD,EACA;IACC,CAAC,EAAgB,MAAM,CAAC;CAG3B,IAAM,IAAQ,cAAc;EAC3B,IAAM,IAAc,EAAgB,SAAS,EAAE,EAGzC,IAAa,EAClB,SAAS;GACR,MAHD,EAAY,gBAAgB,SAAS,SAAS,EAAY,gBAAgB,UAAU,UAAU,gBAAgB;GAI7G,GAAI,EAAY,gBAAgB,EAC/B,SAAS,EAAE,MAAM,EAAY,cAAc,EAC3C;GACD,GAAI,EAAY,kBAAkB,EACjC,WAAW,EAAE,MAAM,EAAY,gBAAgB,EAC/C;GACD,EACD;AACD,SAAO,EAAY,kBAAkB,YAAY,GAAY,EAAY,gBAAgB,GAAG,YAAY,EAAW;IACjH,CAAC,EAAgB,MAAM,CAAC,EAGrB,IAAc,cAAkC;EACrD,IAAM,IAAa,EAAgB;AAInC,SAHI,GAAY,QAAQ,CAAC,GAAY,OAC7B,OAED,kBAAkB,EAAW,KAAK;IACvC,CAAC,EAAgB,KAAK,CAAC;AAG1B,KAAI,EAAM,UAAU,kBAAkB,EAAM,UAAU,UACrD,QACC,qBAAC,iBAAA;EAAwB;aACxB,oBAAC,aAAA,EAAA,CAAc,EACd,KAAoB,oBAAC,sBAAA,EAAA,CAAuB,CAAA;GAC3B;AAKrB,KAAI,EAAM,UAAU,WAAW,EAAM,OAAO;EAC3C,IAAM,IACL,OAAO,KAAmB,aACvB,EAAe,EAAM,OAAO,EAAY,GACvC,KAAkB,oBAAC,oBAAA;GAAmB,OAAO,EAAM;GAAO,SAAS;IAAe;AAEvF,SACC,qBAAC,iBAAA;GAAwB;cACxB,oBAAC,aAAA,EAAA,CAAc,EACd,EAAA;IACiB;;AAKrB,KAAI,CAAC,KAAY,CAAC,EACjB,QAAO;CAIR,IAAM,IAAe,OAAO,KAAK,EAAiB,CAAC,SAAS,GACtD,IAAgB;EACrB,UAAU,EAAgB;EAC1B,SAAS,EAAgB,OAAO;EAChC,kBAAkB,EAAgB;EAClC,EAIK,IADY,EAAS,sBAAsB,CACV,mBAAmB,SACpD,IAAa,EAAgB;AAEnC,QACC,oBAAC,wBAAA;EAAuC;YACvC,oBAAC,eAAA,EAAA,UACA,oBAAC,kBAAA,EAAA,UACA,oBAAC,aAAA;GAAiB;aACjB,oBAAC,uBAAA;IAAsB,QAAQ;cAC9B,oBAAC,gBAAA;KAA6B;KAAc,YAAY;eACvD,qBAAC,qBAAA;MAA8B;iBAC9B,qBAAC,oBAAA,EAAA,UAAA,CACA,oBAAC,cAAA;OACA,eAAe;OACf,SAAS,GAAY;OACrB,cAAc,GAAY;OAC1B,mBAAmB,GAAY;OAC/B,eAAe,GAAY;iBAE3B,oBAAC,YAAA;QACa;QACb,UAAU,EAAgB,MAAM;QACd;kBAElB,oBAAC,cAAA,EAAA,UACA,oBAAC,GAAA;SAAgB,UAAU,EAAgB,QAAQ;mBAClD,oBAAC,0BAAA;UACM;UACO;UACb,YAAY,EAAgB;oBAE3B,KAAY,oBAAC,mBAAA,EAAA,CAAoB;WACR;UACV,EAAA,CACJ;SACH;QACC,EAAC,IAAA,EAAA,CACI,EAAC,IAAA;OACD;MACN;KACM;IACX,EAAA,CACI,EAAA,CACJ;GACQ;;AAe3B,SAAS,WAAW,EACnB,gBACA,aACA,qBACA,eAME;CACF,IAAM,EAAE,mBAAgB,gBAAgB,EAClC,IAAiB,2BAA2B,EAE5C,IAAa,cAAc,cAAc,EAAY,EAAE,CAAC,EAAY,CAAC;AAG3E,KAAI,KAAY,CAAC,EAChB,QAAO,oBAAA,UAAA,EAAG,aAAA,CAAY;CAIvB,IAAM,IAAqB,OAAO,EAAY,mBAAmB,KAAK,QAChE,IAAiB,GAAgB,mBAAmB,IAAI;AAE9D,QACC,qBAAC,kBAAA;EAAiB,QAAQ;EAAyB;aAClD,oBAAC,eAAA,EAAA,CAAgB,EACjB,oBAAC,mBAAA;GACkB;GACE;GACpB,gBACC,IAAqB,oBAAC,iBAAA;IAA6B;IAA6B;KAAkB,GAAG,KAAA;aAGtG,oBAAC,iBAAA,EAAiB,aAAA,CAA2B;IAC1B,CAAA;GACF;;AAQrB,SAAS,gBAAgB,EACxB,gBACA,qBAIE;CACF,IAAM,EAAE,sBAAmB,SAAS;AAIpC,QAAO,oBAAC,GAAA;EAA4B;EAAqB,QAH1C,kBAAkB;AAC3B,MAAgB;KACnB,CAAC,EAAe,CAAC;GAC+C;;AAQpE,SAAS,gBAAgB;CACxB,IAAM,EAAE,YAAS,SAAS,EACpB,IAAM,QAAQ,EACd,IAAe,OAA2B,KAAA,EAAU;AAc1D,QAZA,gBAAgB;EACf,IAAM,IAAQ,GAAM;AACpB,EAAI,MAAU,EAAa,YAC1B,EAAa,UAAU,GACnB,IACH,EAAI,kBAAkB,EAAE,eAAe,UAAU,KAAS,CAAC,GAE3D,EAAI,kBAAkB,EAAE,CAAC;IAGzB,CAAC,GAAK,GAAM,aAAa,CAAC,EAEtB;;AAOR,SAAS,yBAAyB,EACjC,SACA,gBACA,eACA,eAME;AAGF,QACC,oBAAC,oBAAA;EAA6B,UAHd,aAAa;EAG4B;YACxD,oBAAC,gBAAA;GAAqB;GAAmB;GAAyB;GAChE;IACe;GACG;;AAQvB,SAAS,oBAAoB;CAC5B,IAAM,EAAE,mBAAgB,gBAAgB,EAClC,IAAiB,2BAA2B,EAC5C,IAAe,GAAgB,iBAAiB,EAChD,IAAe,GAAgB,iBAAiB;AACtD,QAAO,eAAe;EAAE;EAAa;EAAc;EAAc,CAAC;;AChdnE,IAAa,mBAAb,cAAsC,UAAwD;CAC7F,QAA+B;EAC9B,UAAU;EACV,OAAO;EACP;CAED,OAAO,yBAAyB,GAAqC;AACpE,SAAO;GAAE,UAAU;GAAM;GAAO;;CAGjC,kBAAkB,GAAc,GAA4B;AAC3D,UAAQ,MAAM,sBAAsB,GAAO,EAAU;;CAGtD,SAAS;AAwCR,SAvCI,KAAK,MAAM,WAEb,oBAAC,KAAA;GACA,SAAQ;GACR,gBAAe;GACf,YAAW;GACX,WAAU;GACV,GAAG;GACH,eAAY;aAEZ,qBAAC,OAAA;IAAM,IAAI;KAAE,GAAG;KAAG,UAAU;KAAK,WAAW;KAAU;;KACtD,oBAAC,WAAA;MAAU,OAAM;MAAQ,IAAI;OAAE,UAAU;OAAI,IAAI;OAAG;OAAI;KACxD,oBAAC,YAAA;MAAW,SAAQ;MAAK,cAAA;gBAAa;OAEzB;KACb,oBAAC,YAAA;MAAW,OAAM;MAAiB,WAAA;gBAAU;OAEhC;KACb,oBAAC,YAAA;MACA,SAAQ;MACR,OAAM;MACN,YAAW;MACX,IAAI,EAAE,IAAI,GAAG;MACb,eAAY;gBAEX,KAAK,MAAM,OAAO;OACP;KACb,oBAAC,QAAA;MACA,SAAQ;MACR,eAAe,OAAO,SAAS,QAAQ;MACvC,eAAY;gBACZ;OAEQ;;KACF;IACH,GAID,KAAK,MAAM;;;ACrDpB,SAAgB,SAAS,EAAE,aAAU,SAAM,kBAA8B;AACxE,QACC,oBAAC,eAAA,EAAA,UACA,oBAAC,kBAAA,EAAA,UACA,oBAAC,gBAAA;EAAqB;EAAmB;EACvC;GACe,EAAA,CACC,EAAA,CACJ;;ACDlB,SAAgB,SAAS,EAAE,gBAA4B;CACtD,IAAM,CAAC,GAAU,KAAe,SAA6B,KAAK,EAC5D,EAAE,cAAW,oBAAiB,oBAAiB,SAAS;AAG9D,KAAI,CAAC,EACJ,QAAO;CAGR,IAAM,UAAqB;AAE1B,EADA,EAAY,KAAK,EACjB,GAAiB;IAGZ,IAAgB,kBAAkB,UAAU,EAC5C,IAAc,GAAW,qBAAqB,GAAW,QAAQ,QACjE,IAAU,EAAY,MAAM;AAElC,QACC,qBAAA,UAAA,EAAA,UAAA,CACC,oBAAC,YAAA;EACA,UAAU,MAAM,EAAY,EAAE,cAAc;EAC5C,OAAM;EACK;EACX,eAAa;YAEb,oBAAC,QAAA;GAAO,IAAI;IAAE,OAAO;IAAI,QAAQ;IAAI;aAAG;IAAiB;GAC7C,EAEb,qBAAC,MAAA;EACU;EACV,MAAM,CAAC,CAAC;EACR,eAAe,EAAY,KAAK;EAChC,eAAa,kBAAkB,OAAO;;GAGtC,qBAAC,KAAA;IAAI,IAAI;KAAE,IAAI;KAAG,IAAI;KAAG;eACxB,oBAAC,YAAA;KAAW,SAAQ;eAAa;MAAyB,EAC1D,oBAAC,YAAA;KAAW,SAAQ;KAAQ,OAAM;eAChC,GAAW;MACA,CAAA;KACR;GAEN,oBAAC,SAAA,EAAA,CAAU;GAGX,qBAAC,UAAA;IAAS,eAAe,EAAY,KAAK;IAAE,eAAa,kBAAkB,UAAU;eACpF,oBAAC,cAAA,EAAA,UACA,oBAAC,YAAA,EAAW,UAAS,SAAA,CAAU,EAAA,CACjB,EACf,oBAAC,cAAA,EAAA,UAAa,WAAA,CAAsB,CAAA;KAC1B;GAGX,qBAAC,UAAA;IAAS,eAAe,EAAY,KAAK;IAAE,eAAa,kBAAkB,WAAW;eACrF,oBAAC,cAAA,EAAA,UACA,oBAAC,cAAA,EAAa,UAAS,SAAA,CAAU,EAAA,CACnB,EACf,oBAAC,cAAA,EAAA,UAAa,YAAA,CAAuB,CAAA;KAC3B;GAEX,oBAAC,SAAA,EAAA,CAAU;GAGX,qBAAC,UAAA;IAAS,SAAS;IAAc,eAAa,kBAAkB,SAAS;eACxE,oBAAC,cAAA,EAAA,UACA,oBAAC,YAAA,EAAW,UAAS,SAAA,CAAU,EAAA,CACjB,EACf,oBAAC,cAAA,EAAA,UAAa,UAAA,CAAqB,CAAA;KACzB;;GACL,CAAA,EAAA,CACL"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { MenuLayout, NavigationController } from '@judo/model-api';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
export interface AppBarProps {
|
|
4
|
+
drawerWidth: number;
|
|
5
|
+
/** Click handler for the hamburger menu button. When undefined, the button is hidden (horizontal mode). */
|
|
6
|
+
onMenuClick?: () => void;
|
|
7
|
+
logo?: ReactNode;
|
|
8
|
+
extra?: ReactNode;
|
|
9
|
+
/** Current menu layout mode */
|
|
10
|
+
menuLayout?: MenuLayout;
|
|
11
|
+
/** Navigation controller for horizontal menu rendering */
|
|
12
|
+
navigationController?: NavigationController;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Application header bar with navigation toggle, actor selector, and user menu.
|
|
16
|
+
* In horizontal mode, embeds the navigation items directly in the toolbar.
|
|
17
|
+
*/
|
|
18
|
+
export declare function AppBar({ drawerWidth, onMenuClick, logo, extra, menuLayout, navigationController }: AppBarProps): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=AppBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppBar.d.ts","sourceRoot":"","sources":["../../src/layout/AppBar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,UAAU,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAIvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,MAAM,WAAW,WAAW;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,2GAA2G;IAC3G,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+BAA+B;IAC/B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,0DAA0D;IAC1D,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC5C;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAE,EAAE,WAAW,2CA+G9G"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MenuLayout } from '@judo/model-api';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
export interface AppShellLayoutProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
logo?: ReactNode;
|
|
6
|
+
appBarExtra?: ReactNode;
|
|
7
|
+
/** Override the menu layout from the model. When not set, uses Application.defaultMenuLayout (falls back to VERTICAL). */
|
|
8
|
+
menuLayout?: MenuLayout;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Main application shell layout with drawer (vertical) or horizontal app bar navigation.
|
|
12
|
+
*/
|
|
13
|
+
export declare function AppShellLayout({ children, logo, appBarExtra, menuLayout }: AppShellLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
//# sourceMappingURL=AppShellLayout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppShellLayout.d.ts","sourceRoot":"","sources":["../../src/layout/AppShellLayout.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EAAE,KAAK,SAAS,EAAY,MAAM,OAAO,CAAC;AAQjD,MAAM,WAAW,mBAAmB;IACnC,QAAQ,EAAE,SAAS,CAAC;IACpB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,0HAA0H;IAC1H,UAAU,CAAC,EAAE,UAAU,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,mBAAmB,2CAsE9F"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface BreadcrumbsProps {
|
|
2
|
+
className?: string;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Breadcrumb navigation showing page stack.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Breadcrumbs({ className }: BreadcrumbsProps): import("react/jsx-runtime").JSX.Element | null;
|
|
8
|
+
//# sourceMappingURL=Breadcrumbs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Breadcrumbs.d.ts","sourceRoot":"","sources":["../../src/layout/Breadcrumbs.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,gBAAgB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,gBAAgB,kDA4C1D"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application footer rendered at the bottom of the shell layout.
|
|
3
|
+
*
|
|
4
|
+
* By default shows "© {year} {modelName}".
|
|
5
|
+
* When `footerText` is configured in `CustomizationsConfig`, uses that instead.
|
|
6
|
+
* Supports static strings and dynamic functions.
|
|
7
|
+
*/
|
|
8
|
+
export declare function Footer(): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=Footer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Footer.d.ts","sourceRoot":"","sources":["../../src/layout/Footer.tsx"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,wBAAgB,MAAM,4CA6BrB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PageDialogHost renders the dialog stack from NavigationContext.
|
|
3
|
+
* Place this component near the root of your application layout.
|
|
4
|
+
*
|
|
5
|
+
* Renders ALL dialogs in the stack so that lower dialogs stay mounted
|
|
6
|
+
* (preserving React state and data), while only the topmost is interactive.
|
|
7
|
+
*/
|
|
8
|
+
export declare function PageDialogHost(): import("react/jsx-runtime").JSX.Element | null;
|
|
9
|
+
//# sourceMappingURL=PageDialogHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PageDialogHost.d.ts","sourceRoot":"","sources":["../../src/layout/PageDialogHost.tsx"],"names":[],"mappings":"AA8NA;;;;;;GAMG;AACH,wBAAgB,cAAc,mDAqB7B"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout dimension constants for the application shell.
|
|
3
|
+
* Separated from component files to preserve HMR boundaries.
|
|
4
|
+
* See: specs/HMR.md — Standard I: Single-Authority Export Mandate
|
|
5
|
+
*/
|
|
6
|
+
export declare const DRAWER_WIDTH_EXPANDED = 280;
|
|
7
|
+
export declare const DRAWER_WIDTH_COLLAPSED = 64;
|
|
8
|
+
//# sourceMappingURL=layout-constants.d.ts.map
|