@meshmakers/shared-ui 3.4.1480 → 3.5.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.
Files changed (56) hide show
  1. package/README.md +48 -0
  2. package/assets/octobot/lg/octo_blink.webp +0 -0
  3. package/assets/octobot/lg/octo_blink_still.png +0 -0
  4. package/assets/octobot/lg/octo_idle.webp +0 -0
  5. package/assets/octobot/lg/octo_idle_still.png +0 -0
  6. package/assets/octobot/lg/octo_look.webp +0 -0
  7. package/assets/octobot/lg/octo_look_still.png +0 -0
  8. package/assets/octobot/lg/octo_swim.webp +0 -0
  9. package/assets/octobot/lg/octo_swim_still.png +0 -0
  10. package/assets/octobot/lg/octo_thinking.webp +0 -0
  11. package/assets/octobot/lg/octo_thinking_still.png +0 -0
  12. package/assets/octobot/lg/octo_wave.webp +0 -0
  13. package/assets/octobot/lg/octo_wave_still.png +0 -0
  14. package/assets/octobot/md/octo_blink.webp +0 -0
  15. package/assets/octobot/md/octo_blink_still.png +0 -0
  16. package/assets/octobot/md/octo_idle.webp +0 -0
  17. package/assets/octobot/md/octo_idle_still.png +0 -0
  18. package/assets/octobot/md/octo_look.webp +0 -0
  19. package/assets/octobot/md/octo_look_still.png +0 -0
  20. package/assets/octobot/md/octo_swim.webp +0 -0
  21. package/assets/octobot/md/octo_swim_still.png +0 -0
  22. package/assets/octobot/md/octo_thinking.webp +0 -0
  23. package/assets/octobot/md/octo_thinking_still.png +0 -0
  24. package/assets/octobot/md/octo_wave.webp +0 -0
  25. package/assets/octobot/md/octo_wave_still.png +0 -0
  26. package/assets/octobot/sm/octo_blink.webp +0 -0
  27. package/assets/octobot/sm/octo_blink_still.png +0 -0
  28. package/assets/octobot/sm/octo_idle.webp +0 -0
  29. package/assets/octobot/sm/octo_idle_still.png +0 -0
  30. package/assets/octobot/sm/octo_look.webp +0 -0
  31. package/assets/octobot/sm/octo_look_still.png +0 -0
  32. package/assets/octobot/sm/octo_swim.webp +0 -0
  33. package/assets/octobot/sm/octo_swim_still.png +0 -0
  34. package/assets/octobot/sm/octo_thinking.webp +0 -0
  35. package/assets/octobot/sm/octo_thinking_still.png +0 -0
  36. package/assets/octobot/sm/octo_wave.webp +0 -0
  37. package/assets/octobot/sm/octo_wave_still.png +0 -0
  38. package/fesm2022/meshmakers-shared-ui-assistant-core.mjs +940 -0
  39. package/fesm2022/meshmakers-shared-ui-assistant-core.mjs.map +1 -0
  40. package/fesm2022/meshmakers-shared-ui-assistant.mjs +819 -0
  41. package/fesm2022/meshmakers-shared-ui-assistant.mjs.map +1 -0
  42. package/fesm2022/meshmakers-shared-ui-command-palette.mjs +817 -0
  43. package/fesm2022/meshmakers-shared-ui-command-palette.mjs.map +1 -0
  44. package/fesm2022/meshmakers-shared-ui-shell.mjs +1738 -0
  45. package/fesm2022/meshmakers-shared-ui-shell.mjs.map +1 -0
  46. package/fesm2022/meshmakers-shared-ui-testing.mjs +92 -0
  47. package/fesm2022/meshmakers-shared-ui-testing.mjs.map +1 -0
  48. package/fesm2022/meshmakers-shared-ui.mjs +1550 -203
  49. package/fesm2022/meshmakers-shared-ui.mjs.map +1 -1
  50. package/package.json +28 -2
  51. package/types/meshmakers-shared-ui-assistant-core.d.ts +732 -0
  52. package/types/meshmakers-shared-ui-assistant.d.ts +258 -0
  53. package/types/meshmakers-shared-ui-command-palette.d.ts +398 -0
  54. package/types/meshmakers-shared-ui-shell.d.ts +939 -0
  55. package/types/meshmakers-shared-ui-testing.d.ts +41 -0
  56. package/types/meshmakers-shared-ui.d.ts +1004 -154
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshmakers-shared-ui-shell.mjs","sources":["../../../../projects/meshmakers/shared-ui/shell/src/shell.messages.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-areas.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-navigation.service.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-badges.ts","../../../../projects/meshmakers/shared-ui/shell/src/space-header.service.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-search-trigger.service.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-breadcrumbs.ts","../../../../projects/meshmakers/shared-ui/shell/src/home-greeting.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-environment.ts","../../../../projects/meshmakers/shared-ui/shell/src/shell-notifications.ts","../../../../projects/meshmakers/shared-ui/shell/src/rail/rail.component.ts","../../../../projects/meshmakers/shared-ui/shell/src/rail/rail.component.html","../../../../projects/meshmakers/shared-ui/shell/src/space-shell/space-shell.component.ts","../../../../projects/meshmakers/shared-ui/shell/src/space-shell/space-shell.component.html","../../../../projects/meshmakers/shared-ui/shell/src/settings-side-nav/settings-side-nav.component.ts","../../../../projects/meshmakers/shared-ui/shell/src/settings-side-nav/settings-side-nav.component.html","../../../../projects/meshmakers/shared-ui/shell/src/settings-side-nav/settings-side-nav-badges.service.ts","../../../../projects/meshmakers/shared-ui/shell/src/user-menu/user-menu.component.ts","../../../../projects/meshmakers/shared-ui/shell/src/user-menu/user-menu.component.html","../../../../projects/meshmakers/shared-ui/shell/src/top-bar/top-bar.component.ts","../../../../projects/meshmakers/shared-ui/shell/src/top-bar/top-bar.component.html","../../../../projects/meshmakers/shared-ui/shell/src/public-api.ts","../../../../projects/meshmakers/shared-ui/shell/src/meshmakers-shared-ui-shell.ts"],"sourcesContent":["import { computed, inject, InjectionToken, Signal } from '@angular/core';\n\n/**\n * UI strings of the shell building blocks (`mm-shell-rail`, `mm-space-shell`,\n * `mm-settings-side-nav`, `mm-shell-top-bar`, `mm-shell-user-menu`) and of the\n * pure helpers (greeting, environment chip).\n *\n * Hosts translate them in two ways, which can be combined:\n * - app wide: `{ provide: SHELL_MESSAGES, useValue: { signIn: 'Anmelden', … } }`;\n * - per component: the `messages` input (wins over the token).\n *\n * Missing, `undefined` or `null` members keep the English default of\n * {@link DEFAULT_SHELL_MESSAGES}. Strings with `{name}` placeholders are filled with\n * {@link formatShellMessage}.\n */\nexport interface ShellMessages {\n // --- Shared ---\n /** Screen-reader text after an external link marker (↗). */\n opensInNewTab: string;\n\n // --- Rail ---\n /** `aria-label` of the rail navigation. */\n railLabel: string;\n /** Accessible text of a navigation badge without its own label; `{count}` = the count. */\n navBadge: string;\n /** `aria-label` of a rail icon with a badge; `{label}` = area name, `{badge}` = badge text. */\n navItemWithBadge: string;\n\n // --- Space shell ---\n /** `aria-label` of the back link on object detail pages; `{target}` = list name. */\n backTo: string;\n /** `aria-label` of the status chip list. */\n statusChips: string;\n /** `aria-label` of the tab strip; `{area}` = area name. */\n areaPages: string;\n\n // --- Settings side navigation ---\n /** `aria-label` of the side navigation; `{area}` = area name. */\n areaCategories: string;\n /** The \"home\" entry of the side navigation; `{area}` = area name as given (not re-cased, AB#5621). */\n allOfArea: string;\n\n // --- Top bar ---\n /** `aria-label` of the mode switch group. */\n modeSwitch: string;\n /** `aria-label` of the search trigger. */\n searchAriaLabel: string;\n /** Visible text of the search trigger. */\n search: string;\n /** Visible text of the assistant toggle. */\n assistant: string;\n\n // --- User menu ---\n signIn: string;\n signOut: string;\n /** Title (`aria-label`) of the account panel. */\n accountAndPreferences: string;\n /** `aria-label` of the avatar button for a known user; `{name}` = display name. */\n accountAndPreferencesOf: string;\n theme: string;\n themeSystem: string;\n themeLight: string;\n themeDark: string;\n density: string;\n language: string;\n manageProfile: string;\n /** Version line; `{version}` = version string. */\n version: string;\n\n // --- Environment chip ---\n environmentProduction: string;\n environmentProductionShort: string;\n environmentStaging: string;\n environmentStagingShort: string;\n environmentDevelopment: string;\n environmentDevelopmentShort: string;\n environmentTesting: string;\n environmentTestingShort: string;\n environmentUnknown: string;\n environmentUnknownShort: string;\n\n // --- Home greeting ---\n greetingMorning: string;\n greetingAfternoon: string;\n greetingEvening: string;\n /** Greeting with a name; `{greeting}` = phrase, `{name}` = first name. */\n greetingWithName: string;\n /** Meta line label of the tenant. */\n tenant: string;\n}\n\n/** English defaults of {@link ShellMessages}. */\nexport const DEFAULT_SHELL_MESSAGES: ShellMessages = {\n opensInNewTab: '(opens in a new tab)',\n railLabel: 'Areas',\n navBadge: '{count} open',\n navItemWithBadge: '{label}, {badge}',\n backTo: 'Back to {target}',\n statusChips: 'Status',\n areaPages: '{area} pages',\n areaCategories: '{area} categories',\n allOfArea: 'All {area}',\n modeSwitch: 'Mode',\n searchAriaLabel: 'Search or run a command',\n search: 'Search',\n assistant: 'Assistant',\n signIn: 'Sign in',\n signOut: 'Sign out',\n accountAndPreferences: 'Account and preferences',\n accountAndPreferencesOf: 'Account and preferences of {name}',\n theme: 'Theme',\n themeSystem: 'System',\n themeLight: 'Light',\n themeDark: 'Dark',\n density: 'Density',\n language: 'Language',\n manageProfile: 'Manage profile',\n version: 'Version {version}',\n environmentProduction: 'Production',\n environmentProductionShort: 'Prod',\n environmentStaging: 'Staging',\n environmentStagingShort: 'Stage',\n environmentDevelopment: 'Development',\n environmentDevelopmentShort: 'Dev',\n environmentTesting: 'Testing',\n environmentTestingShort: 'Test',\n environmentUnknown: 'Environment unknown',\n environmentUnknownShort: 'Env?',\n greetingMorning: 'Good morning',\n greetingAfternoon: 'Good afternoon',\n greetingEvening: 'Good evening',\n greetingWithName: '{greeting}, {name}',\n tenant: 'Tenant',\n};\n\n/**\n * App-wide translations of the shell. Partial: members left out keep their English default.\n */\nexport const SHELL_MESSAGES = new InjectionToken<Partial<ShellMessages>>('SHELL_MESSAGES');\n\n/**\n * Merges message overrides over {@link DEFAULT_SHELL_MESSAGES}, later sources winning.\n * Members that are missing, `undefined` or `null` keep the earlier value, so a host compiled\n * against an older `ShellMessages` shape never renders an empty label.\n */\nexport function resolveShellMessages(...overrides: (Partial<ShellMessages> | null | undefined)[]): ShellMessages {\n const resolved: ShellMessages = { ...DEFAULT_SHELL_MESSAGES };\n for (const messages of overrides) {\n if (!messages) {\n continue;\n }\n for (const key of Object.keys(messages) as (keyof ShellMessages)[]) {\n const value = messages[key];\n if (value !== undefined && value !== null) {\n resolved[key] = value;\n }\n }\n }\n return resolved;\n}\n\n/** Replaces `{name}` placeholders; unknown placeholders stay as they are. */\nexport function formatShellMessage(message: string, values: Record<string, string | number>): string {\n return message.replace(/\\{(\\w+)\\}/g, (match, key: string) =>\n Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : match);\n}\n\n/**\n * The resolved messages of a shell component: {@link SHELL_MESSAGES} merged with the\n * component's `messages` input (the input wins). Call it in an injection context.\n * @internal\n */\nexport function shellMessages(input: Signal<Partial<ShellMessages> | null | undefined>): Signal<ShellMessages> {\n const injected = inject(SHELL_MESSAGES, { optional: true });\n return computed(() => resolveShellMessages(injected, input()));\n}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Ids and keys shared by the host's command tree (`CommandSettingsService`), the rail,\n * the space shell and route data. One definition feeds all of them:\n *\n * - A rail area is a top-level command item with the id `area-<space>`.\n * - A tab is a direct child of an area with the id `<space>-<tab>`.\n * - Routes may carry `data: { space: '<space>', tab: '<tab>' }`; the shell uses\n * it where the URL alone does not match a navigation entry.\n * - A top-level separator with the id {@link RAIL_BOTTOM_SEPARATOR_ID} moves the\n * areas after it to the bottom of the rail (e.g. Settings).\n *\n * The space names themselves belong to the host (e.g. `'data' | 'integration' | …`).\n */\nconst AREA_ID_PREFIX = 'area-';\n\n/** Id of the separator in front of the rail's bottom block (Settings). */\nexport const RAIL_BOTTOM_SEPARATOR_ID = 'rail-bottom';\n\nexport function areaId(space: string): string {\n return `${AREA_ID_PREFIX}${space}`;\n}\n\n/** The space of an area id (`area-data` → `data`), or null for any other id. */\nexport function spaceOfAreaId(id: string): string | null {\n return id.startsWith(AREA_ID_PREFIX) ? id.substring(AREA_ID_PREFIX.length) : null;\n}\n\nexport function tabId(space: string, tab: string): string {\n return `${space}-${tab}`;\n}\n\n/**\n * The space whose pages use the settings side navigation (`mm-settings-side-nav`) instead\n * of the tab strip. Default `'settings'` (area id `area-settings`); provide `null` for a\n * host without a settings space.\n */\nexport const SHELL_SETTINGS_SPACE = new InjectionToken<string | null>('SHELL_SETTINGS_SPACE', {\n providedIn: 'root',\n factory: () => 'settings',\n});\n","import { computed, inject, Injectable, signal } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { ActivatedRouteSnapshot, NavigationEnd, Router } from '@angular/router';\nimport { DrawerItem } from '@progress/kendo-angular-layout';\nimport { SVGIcon } from '@progress/kendo-svg-icons';\nimport { CommandItem, CommandService, CommandSettingsService } from '@meshmakers/shared-services';\nimport { filter } from 'rxjs/operators';\nimport { areaId, RAIL_BOTTOM_SEPARATOR_ID, SHELL_SETTINGS_SPACE, spaceOfAreaId, tabId } from './shell-areas';\n\n/**\n * One entry of the shell navigation: a rail area, a tab, or an entry nested\n * below a tab (flyout only). Built from the CommandService's visible items.\n */\nexport interface ShellNavNode {\n id: string;\n text: string;\n svgIcon?: SVGIcon;\n tooltip?: string;\n separator: boolean;\n /** The CommandService highlights exactly this entry (longest link match on the URL). */\n selected: boolean;\n /** This entry or one below it is selected. */\n active: boolean;\n /** Opening it navigates (router link or external href); otherwise it only groups entries. */\n navigable: boolean;\n /** Opens in a new browser tab. */\n external: boolean;\n children: ShellNavNode[];\n /**\n * Optional count shown as a badge on the rail icon / flyout entry (AB#5621); 0 or none shows\n * nothing. The rail's `badges` input wins over it. Not set by {@link ShellNavigationService}.\n */\n badgeCount?: number;\n}\n\n/** `space` / `tab` / `objectDetail` route data, merged from the root to the deepest active route. */\nexport interface ShellRouteData {\n space?: string;\n tab?: string;\n /**\n * The page is the detail page of one object (AB#5547): its own object header (name, chips,\n * actions, object tabs) replaces the area title and tab strip of the space header. Set by\n * `data: { objectDetail: true }` on any route of the chain.\n */\n objectDetail?: boolean;\n /**\n * `data: { spaceTabs: false }`: the page brings its own navigation for the area's entries, so\n * the space header leaves its tab strip out instead of showing the same entries twice.\n * (Settings needs no flag: its side navigation replaces the tab strip on every page.)\n */\n spaceTabs?: boolean;\n}\n\n/** Navigation traits of one command item, keyed by id (see {@link ShellNavigationService.buildTree}). */\nexport interface ShellNavItemKind {\n navigable: boolean;\n external: boolean;\n tooltip?: string;\n}\n\n/**\n * The shell's view of the navigation: turns the flat, visibility-filtered\n * item list of the CommandService into a tree (rail areas → tabs → nested\n * entries) and works out which area and tab are active.\n *\n * The active area comes from the route's `data.space` when it names an area\n * of the current mode, otherwise from the area that holds the selected\n * entry. The active tab likewise comes from `data.tab` (matched as\n * `<space>-<tab>`) or from the selection. URLs never change for the shell.\n */\n@Injectable({ providedIn: 'root' })\nexport class ShellNavigationService {\n private readonly commandService = inject(CommandService);\n private readonly commandSettings = inject(CommandSettingsService);\n private readonly router = inject(Router);\n private readonly settingsSpace = inject(SHELL_SETTINGS_SPACE);\n\n private readonly items = toSignal(this.commandService.drawerItems, { initialValue: [] as DrawerItem[] });\n private readonly _routeData = signal<ShellRouteData>({});\n\n readonly routeData = this._routeData.asReadonly();\n\n private readonly tree = computed(() => ShellNavigationService.buildTree(this.items(), this.collectKinds()));\n\n /** Rail areas above the bottom separator. */\n readonly topAreas = computed(() => this.tree().top);\n\n /** Rail areas pinned to the bottom (Settings). */\n readonly bottomAreas = computed(() => this.tree().bottom);\n\n readonly activeArea = computed<ShellNavNode | null>(() => {\n const areas = [...this.topAreas(), ...this.bottomAreas()];\n const space = this._routeData().space;\n if (space) {\n const fromRoute = areas.find(area => area.id === areaId(space));\n if (fromRoute) {\n return fromRoute;\n }\n }\n return areas.find(area => area.active) ?? null;\n });\n\n readonly activeTab = computed<ShellNavNode | null>(() => {\n const area = this.activeArea();\n if (!area) {\n return null;\n }\n const tab = this._routeData().tab;\n const space = spaceOfAreaId(area.id);\n if (tab && space) {\n const fromRoute = area.children.find(child => child.id === tabId(space, tab));\n if (fromRoute) {\n return fromRoute;\n }\n }\n return area.children.find(child => child.active) ?? null;\n });\n\n /**\n * Settings has one navigation (concept §5.6, AB#5523; the space comes from {@link SHELL_SETTINGS_SPACE}): the category list on the left of every\n * Settings page, never the tab strip — so opening a category cannot switch between two layouts.\n * Off on object detail pages, whose object header owns the navigation.\n */\n readonly settingsSideNav = computed(() =>\n this.settingsSpace !== null && this.activeArea()?.id === areaId(this.settingsSpace) && !this.objectDetail());\n\n /** The Settings home is open: Settings side navigation without an active category. */\n readonly settingsHomeActive = computed(() => this.settingsSideNav() && this.activeTab() === null);\n\n /**\n * Whether the space header shows the area's tab strip: not in Settings (side navigation), not\n * when the route says `spaceTabs: false`; default true.\n */\n readonly showTabs = computed(() => this._routeData().spaceTabs !== false && !this.settingsSideNav());\n\n /** The current page is an object detail page (route data `objectDetail`). */\n readonly objectDetail = computed(() => this._routeData().objectDetail === true);\n\n /**\n * Where \"back\" leads from an object detail page: the selected entry of the active area\n * (the list the object belongs to, e.g. Integration › Adapters), else the active tab.\n */\n readonly backTarget = computed<ShellNavNode | null>(() => {\n const area = this.activeArea();\n return (area ? ShellNavigationService.deepestSelected(area) : null) ?? this.activeTab();\n });\n\n constructor() {\n this.router.events\n .pipe(filter(event => event instanceof NavigationEnd))\n .subscribe(() => this._routeData.set(ShellNavigationService.readRouteData(this.router.routerState?.snapshot?.root)));\n }\n\n /**\n * Opens an entry: navigable entries navigate (or open their href), grouping\n * entries open their first navigable descendant.\n */\n async open(node: ShellNavNode): Promise<void> {\n const target = node.navigable ? node : ShellNavigationService.firstPage(node, true);\n if (target) {\n await this.commandService.setSelectedDrawerItem({ id: target.id } as DrawerItem);\n }\n }\n\n /**\n * Opens an area from the rail. An area with its own in-app link (e.g. Home without tabs, or a\n * Settings overview) opens that page (AB#5621); any other area opens its first page. Nothing\n * happens when the current page already lives in the area (re-clicking the active area must\n * not throw the person out of the page they are on). External entries are skipped; an area\n * click never pops up a browser tab.\n */\n async openArea(area: ShellNavNode): Promise<void> {\n if (area.id === this.activeArea()?.id) {\n return;\n }\n const target = ShellNavigationService.areaTarget(area);\n if (target) {\n await this.commandService.setSelectedDrawerItem({ id: target.id } as DrawerItem);\n }\n }\n\n /** Opens the first page of the first area (used after a mode switch). */\n async openFirstPage(): Promise<void> {\n const first = this.topAreas()[0];\n const target = first ? ShellNavigationService.areaTarget(first) : null;\n if (target) {\n await this.commandService.setSelectedDrawerItem({ id: target.id } as DrawerItem);\n }\n }\n\n /**\n * Where a rail click on an area leads: the area itself when it has its own in-app link,\n * else its first navigable, in-app entry; `null` when there is none.\n */\n static areaTarget(area: ShellNavNode): ShellNavNode | null {\n if (area.navigable && !area.external) {\n return area;\n }\n return ShellNavigationService.firstPage(area, false);\n }\n\n /** The selected entry at or below a node, deepest first; `null` when none is selected. */\n static deepestSelected(node: ShellNavNode): ShellNavNode | null {\n for (const child of node.children) {\n const nested = ShellNavigationService.deepestSelected(child);\n if (nested) {\n return nested;\n }\n }\n return node.selected && node.navigable ? node : null;\n }\n\n /** The first navigable, in-app entry below a node (depth first). */\n static firstPage(node: ShellNavNode, allowExternal: boolean): ShellNavNode | null {\n for (const child of node.children) {\n if (child.separator) {\n continue;\n }\n if (child.navigable && (allowExternal || !child.external)) {\n return child;\n }\n const nested = ShellNavigationService.firstPage(child, allowExternal);\n if (nested) {\n return nested;\n }\n }\n return null;\n }\n\n /**\n * Link / href / target per item id, read from the command item tree. The\n * CommandService's items carry neither, but the rail must know whether an\n * entry navigates and whether it leaves the app.\n */\n private collectKinds(): Map<string, ShellNavItemKind> {\n // Re-read whenever the items change: the tree depends on mode and tenant data.\n this.items();\n const kinds = new Map<string, ShellNavItemKind>();\n const walk = (items: CommandItem[]): void => {\n for (const item of items) {\n const navigable = item.link !== undefined || item.href !== undefined || item.onClick !== undefined;\n kinds.set(item.id, {\n navigable,\n external: item.href !== undefined,\n tooltip: item.tooltip\n });\n if (item.children) {\n walk(item.children);\n }\n }\n };\n walk(this.commandSettings.commandItems);\n return kinds;\n }\n\n static buildTree(items: DrawerItem[], kinds: Map<string, ShellNavItemKind>): { top: ShellNavNode[]; bottom: ShellNavNode[] } {\n const byParent = new Map<string, DrawerItem[]>();\n const roots: DrawerItem[] = [];\n for (const item of items) {\n const parentId = (item as { parentId?: string }).parentId;\n if (parentId) {\n const siblings = byParent.get(String(parentId)) ?? [];\n siblings.push(item);\n byParent.set(String(parentId), siblings);\n } else {\n roots.push(item);\n }\n }\n\n const toNode = (item: DrawerItem): ShellNavNode => {\n const id = String(item.id ?? '');\n const children = ShellNavigationService.tidySeparators((byParent.get(id) ?? []).map(toNode));\n const kind = kinds.get(id);\n const selected = item.selected === true;\n return {\n id,\n text: item.text ?? '',\n svgIcon: item.svgIcon,\n tooltip: kind?.tooltip,\n separator: item.separator === true,\n selected,\n active: selected || children.some(child => child.active),\n navigable: kind?.navigable ?? false,\n external: kind?.external ?? false,\n children\n };\n };\n\n const top: ShellNavNode[] = [];\n const bottom: ShellNavNode[] = [];\n let target = top;\n for (const root of roots) {\n if (root.separator === true) {\n if (root.id === RAIL_BOTTOM_SEPARATOR_ID) {\n target = bottom;\n }\n continue;\n }\n target.push(toNode(root));\n }\n return { top, bottom };\n }\n\n /** Drops leading, trailing and repeated separators (left over when entries around them are hidden). */\n static tidySeparators(nodes: ShellNavNode[]): ShellNavNode[] {\n const result: ShellNavNode[] = [];\n for (const node of nodes) {\n if (node.separator && (result.length === 0 || result[result.length - 1].separator)) {\n continue;\n }\n result.push(node);\n }\n while (result.length > 0 && result[result.length - 1].separator) {\n result.pop();\n }\n return result;\n }\n\n static readRouteData(root: ActivatedRouteSnapshot | null | undefined): ShellRouteData {\n const data: ShellRouteData = {};\n let route = root ?? null;\n while (route) {\n const space = route.data?.['space'];\n const tab = route.data?.['tab'];\n if (route.data?.['objectDetail'] === true) {\n data.objectDetail = true;\n }\n if (typeof route.data?.['spaceTabs'] === 'boolean') {\n data.spaceTabs = route.data['spaceTabs'];\n }\n if (typeof space === 'string') {\n data.space = space;\n // A new space resets the tab unless this route names one as well.\n data.tab = typeof tab === 'string' ? tab : undefined;\n } else if (typeof tab === 'string') {\n data.tab = tab;\n }\n route = route.firstChild;\n }\n return data;\n }\n}\n","/**\n * A count next to a navigation entry (AB#5621): pending work such as open inbox items or ToDos.\n * Hosts pass either the plain count or this object. A count of 0 (or none) shows no badge.\n */\nexport interface ShellNavBadge {\n count: number;\n /** Needs attention: rendered in the warning colour. */\n attention?: boolean;\n /**\n * Accessible text of the badge (e.g. \"3 open ToDos\"); without one the shell reads\n * {@link ShellMessages.navBadge} (`'{count} open'`).\n */\n label?: string;\n}\n\n/** Badge input of the rail: keyed by node id (area id `area-<space>` or a tab id). */\nexport type ShellNavBadges = Readonly<Record<string, number | ShellNavBadge | null | undefined>>;\n\n/** Highest count shown as a number; larger counts read `99+`. */\nexport const SHELL_BADGE_MAX = 99;\n\n/**\n * The badge of one entry: the `badges` input wins over the node's own `badgeCount`;\n * `null` when there is nothing to show (missing, 0, negative or not a number).\n */\nexport function resolveShellBadge(\n badges: ShellNavBadges | null | undefined,\n id: string,\n ownCount?: number | null\n): ShellNavBadge | null {\n const fromInput = badges?.[id];\n const badge: ShellNavBadge | null =\n typeof fromInput === 'number' ? { count: fromInput }\n : fromInput ? fromInput\n : typeof ownCount === 'number' ? { count: ownCount }\n : null;\n return badge && Number.isFinite(badge.count) && badge.count > 0 ? badge : null;\n}\n\n/** Visible text of a badge count: the number, or `99+` above {@link SHELL_BADGE_MAX}. */\nexport function shellBadgeText(count: number): string {\n return count > SHELL_BADGE_MAX ? `${SHELL_BADGE_MAX}+` : String(Math.floor(count));\n}\n","import { Injectable, signal, TemplateRef } from '@angular/core';\n\n/** A status chip in the space header: dot + label, never colour alone. */\nexport interface SpaceStatusChip {\n label: string;\n status: 'success' | 'warning' | 'error' | 'info' | 'neutral';\n}\n\n/**\n * Lets the page shown inside a space contribute to the space header: status\n * chips next to the title and a template for the primary actions.\n *\n * A page sets them in its constructor or `ngOnInit` and never cleans up: the\n * shell calls {@link mark} when a navigation starts and\n * {@link clearOlderThan} when it ends with a different page component, which\n * drops only what the previous page contributed. A cancelled navigation or a\n * param-only change (same component) keeps the chips.\n */\n@Injectable({ providedIn: 'root' })\nexport class SpaceHeaderService {\n private readonly _chips = signal<SpaceStatusChip[]>([]);\n private readonly _actions = signal<TemplateRef<unknown> | null>(null);\n private stamp = 0;\n private chipsStamp = 0;\n private actionsStamp = 0;\n\n readonly chips = this._chips.asReadonly();\n readonly actions = this._actions.asReadonly();\n\n setChips(chips: SpaceStatusChip[]): void {\n this._chips.set(chips);\n this.chipsStamp = ++this.stamp;\n }\n\n setActions(actions: TemplateRef<unknown> | null): void {\n this._actions.set(actions);\n this.actionsStamp = ++this.stamp;\n }\n\n /** A marker for \"now\"; contributions made after it count as newer. */\n mark(): number {\n return this.stamp;\n }\n\n /** Drops every contribution made at or before the marker. */\n clearOlderThan(marker: number): void {\n if (this.chipsStamp <= marker) {\n this._chips.set([]);\n }\n if (this.actionsStamp <= marker) {\n this._actions.set(null);\n }\n }\n}\n","import { Injectable } from '@angular/core';\nimport { Observable, Subject } from 'rxjs';\n\n/**\n * Hook between the top bar's search button and the command palette (AB#5520).\n *\n * The shell only announces that the person asked for search; it does not\n * know the palette. The host (or the palette) subscribes once and opens it:\n *\n * ```ts\n * inject(ShellSearchTriggerService).requested$\n * .pipe(takeUntilDestroyed())\n * .subscribe(() => commandPalette.open());\n * ```\n *\n * Until something subscribes, a click is a no-op. The keyboard shortcut\n * (Cmd/Ctrl+K) is not bound here — it belongs to the palette, which can call\n * {@link request} or open itself directly.\n */\n@Injectable({ providedIn: 'root' })\nexport class ShellSearchTriggerService {\n private readonly requests = new Subject<void>();\n\n /** Emits every time search was requested from the shell. */\n readonly requested$: Observable<void> = this.requests.asObservable();\n\n request(): void {\n this.requests.next();\n }\n}\n","import { BreadCrumbData } from '@meshmakers/shared-services';\nimport { ShellNavNode } from './shell-navigation.service';\n\n/**\n * Host-specific crumb rewriting of {@link shellBreadcrumbs}. Hosts that migrated from a\n * section-based navigation use it to replace the old section crumb with the rail area.\n */\nexport interface ShellBreadcrumbOptions {\n /**\n * Lower-case labels of old section crumbs that routes still start with (e.g. `'identity'`).\n * Such a first crumb is replaced by the rail area the page lives in.\n */\n legacySectionCrumbs?: ReadonlySet<string>;\n /**\n * Area names of old section crumbs (lower-case key → area name), used when the page has no\n * active area: `{ communication: 'Integration' }` turns \"Communication › Data Flows\" into\n * \"Integration › Data Flows\".\n */\n legacySectionAreaNames?: Readonly<Record<string, string>>;\n}\n\nconst NO_LEGACY_CRUMBS: ReadonlySet<string> = new Set();\n\n/** A breadcrumb the shell added for the rail area; clicking it opens the area. */\nexport interface ShellAreaCrumb extends BreadCrumbData {\n areaId: string;\n}\n\nexport function isAreaCrumb(item: unknown): item is ShellAreaCrumb {\n return !!item && typeof (item as ShellAreaCrumb).areaId === 'string';\n}\n\n/**\n * Breadcrumbs as the shell shows them (AB#5516): the first crumb names the rail area of the\n * page (route `data.space`), never a section of an old drawer navigation.\n *\n * - a legacy section crumb ({@link ShellBreadcrumbOptions.legacySectionCrumbs}) is replaced by the area crumb;\n * - a first crumb that already is the area (\"Settings\") stays as it is;\n * - otherwise the area crumb is put in front (\"Data Explorer\" → \"Data › Data Explorer\");\n * - the area crumb is dropped again when the next crumb carries the same label\n * (\"General › Settings\" → \"Settings\", not \"Settings › Settings\").\n *\n * - crumbs without text are dropped (no empty segments).\n *\n * Pure: returns a new array and never mutates the items (the BreadCrumbService re-emits the\n * same objects after resolving `{{placeholders}}`).\n */\nexport function shellBreadcrumbs(\n allItems: readonly BreadCrumbData[],\n area: ShellNavNode | null,\n options: ShellBreadcrumbOptions = {}\n): BreadCrumbData[] {\n const legacyCrumbs = options.legacySectionCrumbs ?? NO_LEGACY_CRUMBS;\n const legacyAreaNames = options.legacySectionAreaNames ?? {};\n // A crumb without text (e.g. an unresolved or empty `{{placeholder}}`) would render as an empty\n // segment (\"Integration › › Mesh Adapter\", visual check 2026-10-06) — drop it.\n const items = allItems.filter((item) => (item.text ?? '').trim().length > 0);\n if (items.length === 0) {\n return [];\n }\n if (!area) {\n const known = legacyAreaNames[(items[0].text ?? '').trim().toLowerCase()];\n return known ? [{ ...items[0], text: known, title: known, labelTemplate: known }, ...items.slice(1)] : [...items];\n }\n const areaLabel = area.text.trim().toLowerCase();\n const [first, ...rest] = items;\n const firstLabel = (first.text ?? '').trim().toLowerCase();\n if (firstLabel === areaLabel) {\n return [...items];\n }\n const tail = legacyCrumbs.has(firstLabel) ? rest : [...items];\n if ((tail[0]?.text ?? '').trim().toLowerCase() === areaLabel) {\n return tail;\n }\n const areaCrumb: ShellAreaCrumb = {\n text: area.text,\n title: area.text,\n svgIcon: area.svgIcon,\n labelTemplate: area.text,\n url: '',\n areaId: area.id\n };\n return [areaCrumb, ...tail];\n}\n\n/** \"Integration › Adapters\" — the description stored with a recent page. */\nexport function crumbPath(items: readonly BreadCrumbData[]): string | undefined {\n const texts = items.map(item => item.text?.trim()).filter((text): text is string => !!text);\n return texts.length > 0 ? texts.join(' › ') : undefined;\n}\n","import { ShellMessages, formatShellMessage, resolveShellMessages } from './shell.messages';\n\n/**\n * The Home space header (wireframe screen 1, AB#5558): instead of the area name \"Home\" it greets\n * the user — \"Good morning, Gerald\" — with a short meta line naming the tenant. Pass the results\n * to `mm-space-shell` as `heading` and `meta`.\n *\n * Every helper takes optional {@link ShellMessages} overrides (translations).\n */\n\n/** A label/value pair of the space header meta line (the value is set in mono). */\nexport interface SpaceMetaItem {\n label: string;\n value: string;\n}\n\n/** The parts of the signed-in user the greeting reads. */\nexport interface GreetingUser {\n given_name?: string | null;\n}\n\n/** Morning 05–11, afternoon 12–17, evening otherwise (local time of the browser). */\nexport function greetingPhrase(now: Date, messages?: Partial<ShellMessages> | null): string {\n const m = resolveShellMessages(messages);\n const hour = now.getHours();\n if (hour >= 5 && hour < 12) {\n return m.greetingMorning;\n }\n if (hour >= 12 && hour < 18) {\n return m.greetingAfternoon;\n }\n return m.greetingEvening;\n}\n\n/** The first name: the `given_name` claim, else the first word of the display name, else null. */\nexport function firstNameOf(user: GreetingUser | null | undefined, displayName: string | null | undefined): string | null {\n const given = user?.given_name?.trim();\n if (given) {\n return given;\n }\n const first = displayName?.trim().split(/\\s+/)[0];\n return first ? first : null;\n}\n\n/** \"Good morning, Gerald\", or just \"Good morning\" when the name is unknown. */\nexport function homeGreeting(\n user: GreetingUser | null | undefined,\n displayName: string | null | undefined,\n now: Date,\n messages?: Partial<ShellMessages> | null\n): string {\n const phrase = greetingPhrase(now, messages);\n const name = firstNameOf(user, displayName);\n return name ? formatShellMessage(resolveShellMessages(messages).greetingWithName, { greeting: phrase, name }) : phrase;\n}\n\n/** The meta line of the Home header: the tenant (nothing without one). */\nexport function homeMeta(tenantId: string | null | undefined, messages?: Partial<ShellMessages> | null): SpaceMetaItem[] {\n return tenantId ? [{ label: resolveShellMessages(messages).tenant, value: tenantId }] : [];\n}\n","import { ShellMessages, resolveShellMessages } from './shell.messages';\n\n/** Status colour of a chip; the label always carries the meaning as well (never colour alone). */\nexport type ShellStatus = 'success' | 'warning' | 'error' | 'info' | 'neutral';\n\n/** The environment chip next to the tenant switcher in `mm-shell-top-bar`. */\nexport interface ShellEnvironmentChip {\n label: string;\n /** Shown on narrow screens, so the environment never becomes colour-only. */\n short: string;\n status: ShellStatus;\n /** Marks the whole top bar as production (accent line). */\n production?: boolean;\n}\n\n/** Tenant environment modes of the OctoMesh tenant mode configuration. */\nexport type ShellEnvironmentMode = 'PRODUCTION' | 'STAGING' | 'DEVELOPMENT' | 'TESTING' | 'unknown';\n\n/**\n * The environment chip of a tenant mode, in sentence case with its status colour:\n * Production (error, marks the bar), Staging (warning), Development (success),\n * Testing (info), anything else \"Environment unknown\" (neutral).\n */\nexport function shellEnvironmentChip(\n mode: ShellEnvironmentMode | string | null | undefined,\n messages?: Partial<ShellMessages> | null\n): ShellEnvironmentChip {\n const m = resolveShellMessages(messages);\n switch (mode) {\n case 'PRODUCTION':\n return { label: m.environmentProduction, short: m.environmentProductionShort, status: 'error', production: true };\n case 'STAGING':\n return { label: m.environmentStaging, short: m.environmentStagingShort, status: 'warning' };\n case 'DEVELOPMENT':\n return { label: m.environmentDevelopment, short: m.environmentDevelopmentShort, status: 'success' };\n case 'TESTING':\n return { label: m.environmentTesting, short: m.environmentTestingShort, status: 'info' };\n default:\n return { label: m.environmentUnknown, short: m.environmentUnknownShort, status: 'neutral' };\n }\n}\n","import { NotificationDisplayOptions } from '@meshmakers/shared-ui';\n\n/**\n * Toast stacking for a shell host (AB#5516 visual check: six identical \"not found\" errors\n * covered the top bar): identical messages once; errors leave after 10 s and warnings after\n * 8 s (paused while hovered or focused), except those with details, which wait for the user;\n * at most three toasts, a success/info is dropped before any error. Errors that must stay\n * pass `hideAfter: 0`.\n *\n * Use: `{ provide: NOTIFICATION_DISPLAY_OPTIONS, useValue: SHELL_NOTIFICATION_OPTIONS }`.\n * Placing `.k-notification-group` below the top bar is the host's global style.\n */\nexport const SHELL_NOTIFICATION_OPTIONS: NotificationDisplayOptions = {\n dedupe: true,\n errorHideAfter: 10_000,\n warningHideAfter: 8_000,\n stickyWithDetails: true,\n maxVisible: 3\n};\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, DestroyRef, effect, ElementRef, inject, input, output, signal, untracked } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { NavigationEnd, Router } from '@angular/router';\nimport { SVGIconComponent } from '@progress/kendo-angular-icons';\nimport { ShellNavNode } from '../shell-navigation.service';\nimport { formatShellMessage, ShellMessages, shellMessages } from '../shell.messages';\nimport { resolveShellBadge, ShellNavBadge, ShellNavBadges, shellBadgeText } from '../shell-badges';\n\n/**\n * The rail: one icon per area of the navigation tree, Settings pinned to the\n * bottom. Enter/Space or a click on an icon navigates to the area. The\n * flyout with the area's entries is a disclosure: it opens on hover or with\n * Arrow Right (`aria-expanded` / `aria-controls` on the icon); it never opens\n * on focus alone. On phones (≤ 640 px) the rail is a bottom bar without\n * flyouts — the space shell's tab strip takes over.\n *\n * Pointer: hovering opens the flyout after a short intent delay (at once when\n * another flyout is already showing). It stays open while the pointer is over\n * the icon or the flyout — the flyout host spans the gap between them, so\n * crossing it never counts as leaving — and closes only after a grace delay\n * once the pointer has left both. A mouse click on an icon with a flyout\n * still navigates, and additionally pins the flyout open (as does Arrow\n * Right): a pinned flyout ignores the pointer leaving and closes on an\n * outside click, Escape, choosing an entry, focus leaving the entry, a\n * second click on the same icon, or a navigation (AB#5621).\n *\n * Navigation (AB#5621): every open flyout — pinned or hovered — closes when a\n * router navigation ends or the active area changes, so a click on an icon\n * that navigates does not leave the flyout over the new page. A click that\n * does not navigate (the area's page is already open) keeps the pin. Closing\n * on navigation moves focus only when it was inside the flyout (back to its\n * area icon); focus the new page took is left alone.\n *\n * Keyboard: the rail is one tab stop (roving tabindex). Arrow Up/Down (Left/\n * Right on the bottom bar) move between areas, Home/End jump, Arrow Right\n * opens the flyout and focuses its first entry; inside the flyout Arrow\n * Up/Down move, Escape or Arrow Left return to the icon. After choosing a\n * flyout entry focus returns to the area icon instead of falling to <body>.\n *\n * Badges (AB#5621): `badges` maps node ids (areas and flyout entries) to a count or a\n * {@link ShellNavBadge}; a node's own `badgeCount` is the fallback. 0 or no count shows nothing.\n * The count joins the icon's accessible name (\"Inbox, 3 open\") and is read after a flyout entry.\n *\n * Every activation of an area icon emits `areaSelected` — also for areas without entries\n * (Home, a Settings overview), which have no flyout; `ShellNavigationService.openArea` opens\n * the area's own link then.\n *\n * Pure presentation: the host feeds the areas (`ShellNavigationService.topAreas()` /\n * `bottomAreas()`) and handles the outputs (`openArea` / `open`).\n */\n/** Hover intent before a flyout opens when none is showing (ms). */\nexport const RAIL_FLYOUT_OPEN_DELAY = 120;\n/** Grace period after the pointer left both icon and flyout (ms). */\nexport const RAIL_FLYOUT_CLOSE_DELAY = 300;\n\n@Component({\n selector: 'mm-shell-rail',\n imports: [SVGIconComponent, NgTemplateOutlet],\n templateUrl: './rail.component.html',\n styleUrl: './rail.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '(document:pointerdown)': 'onDocumentPointerDown($event)',\n '(document:keydown.escape)': 'onDocumentEscape()'\n }\n})\nexport class ShellRailComponent {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly changeDetector = inject(ChangeDetectorRef);\n\n readonly areas = input<ShellNavNode[]>([]);\n readonly bottomAreas = input<ShellNavNode[]>([]);\n readonly activeAreaId = input<string | null>(null);\n /** Counts per node id (area or flyout entry); wins over `ShellNavNode.badgeCount`. */\n readonly badges = input<ShellNavBadges>({});\n /** Translations; members left out fall back to {@link SHELL_MESSAGES}, then English. */\n readonly messages = input<Partial<ShellMessages> | null>(null);\n protected readonly m = shellMessages(this.messages);\n\n /** An area icon was activated. */\n readonly areaSelected = output<ShellNavNode>();\n /** An entry in a flyout was activated. */\n readonly itemSelected = output<ShellNavNode>();\n\n /** The area whose flyout is shown. */\n protected readonly openId = signal<string | null>(null);\n /** Opened by click or keyboard: the pointer leaving does not close it. */\n protected readonly pinned = signal(false);\n private readonly focusedId = signal<string | null>(null);\n private openTimer: ReturnType<typeof setTimeout> | null = null;\n private closeTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor() {\n const destroyRef = inject(DestroyRef);\n destroyRef.onDestroy(() => this.clearTimers());\n\n // Optional: the rail also works without a router (the active area change covers that case).\n const router = inject(Router, { optional: true });\n const subscription = router?.events.subscribe(event => {\n if (event instanceof NavigationEnd) {\n this.closeOnNavigation();\n }\n });\n destroyRef.onDestroy(() => subscription?.unsubscribe());\n\n let previousActive: string | null | undefined;\n effect(() => {\n const active = this.activeAreaId();\n if (previousActive !== undefined && previousActive !== active) {\n untracked(() => this.closeOnNavigation());\n }\n previousActive = active;\n });\n }\n\n private readonly allAreas = computed(() => [...this.areas(), ...this.bottomAreas()]);\n\n /** The one area button in the tab order: the focused one, else the active one, else the first. */\n protected readonly tabStopId = computed(() => {\n const ids = this.allAreas().map(area => area.id);\n const focused = this.focusedId();\n if (focused && ids.includes(focused)) {\n return focused;\n }\n const active = this.activeAreaId();\n return active && ids.includes(active) ? active : ids[0] ?? null;\n });\n\n protected hasFlyout(area: ShellNavNode): boolean {\n return area.children.some(child => !child.separator);\n }\n\n /** The badge of a node, or null when it shows none. */\n protected badgeOf(node: ShellNavNode): ShellNavBadge | null {\n return resolveShellBadge(this.badges(), node.id, node.badgeCount);\n }\n\n protected badgeText(badge: ShellNavBadge): string {\n return shellBadgeText(badge.count);\n }\n\n /** Accessible text of a badge: its own label, else \"{count} open\". */\n protected badgeLabel(badge: ShellNavBadge): string {\n return badge.label ?? formatShellMessage(this.m().navBadge, { count: badge.count });\n }\n\n /** Accessible name of an area icon, with its badge when it has one. */\n protected areaLabel(area: ShellNavNode): string {\n const badge = this.badgeOf(area);\n return badge\n ? formatShellMessage(this.m().navItemWithBadge, { label: area.text, badge: this.badgeLabel(badge) })\n : area.text;\n }\n\n protected flyoutId(area: ShellNavNode): string {\n return `rail-flyout-${area.id}`;\n }\n\n protected onAreaClick(area: ShellNavNode, event?: MouseEvent): void {\n // A click with the pointer (detail ≥ 1) pins the flyout; Enter/Space keep the plain behaviour.\n const byPointer = !!event && event.detail > 0;\n if (byPointer && this.hasFlyout(area) && !this.isBottomBar()) {\n if (this.pinned() && this.openId() === area.id) {\n this.close();\n return;\n }\n this.openNow(area.id, true);\n } else {\n this.close();\n }\n this.areaSelected.emit(area);\n }\n\n protected onItemClick(area: ShellNavNode, item: ShellNavNode): void {\n // The flyout hides once closed; move focus first so it does not drop to <body>.\n this.focusArea(area.id);\n this.close();\n this.itemSelected.emit(item);\n }\n\n protected onAreaFocus(area: ShellNavNode): void {\n this.focusedId.set(area.id);\n }\n\n protected onPointerEnter(area: ShellNavNode): void {\n this.cancelClose();\n if (this.pinned() || !this.hasFlyout(area)) {\n return;\n }\n if (this.openId() !== null) {\n // Moving between areas while a flyout shows: switch without delay.\n this.openNow(area.id, false);\n return;\n }\n this.cancelOpen();\n this.openTimer = setTimeout(() => {\n this.openTimer = null;\n this.openNow(area.id, false);\n }, RAIL_FLYOUT_OPEN_DELAY);\n }\n\n protected onPointerLeave(area: ShellNavNode): void {\n this.cancelOpen();\n if (this.pinned() || this.openId() !== area.id) {\n return;\n }\n this.cancelClose();\n this.closeTimer = setTimeout(() => {\n this.closeTimer = null;\n if (this.openId() === area.id && !this.pinned() && !this.entryOf(area)?.contains(document.activeElement)) {\n this.openId.set(null);\n }\n }, RAIL_FLYOUT_CLOSE_DELAY);\n }\n\n protected onEntryFocusOut(area: ShellNavNode, event: FocusEvent): void {\n const next = event.relatedTarget;\n if (next instanceof Node && this.entryOf(area)?.contains(next)) {\n return;\n }\n // Focus dropping to nothing (e.g. a click on the flyout title) is not \"leaving\":\n // a pinned flyout waits for the outside click instead.\n if (next === null && this.pinned()) {\n return;\n }\n if (this.openId() === area.id) {\n this.close();\n }\n }\n\n protected onDocumentPointerDown(event: Event): void {\n const id = this.openId();\n if (!this.pinned() || id === null) {\n return;\n }\n const target = event.target;\n if (target instanceof Node && this.findByAttribute('data-entry-id', id)?.contains(target)) {\n return;\n }\n this.close();\n }\n\n protected onDocumentEscape(): void {\n if (this.openId() !== null) {\n this.close();\n }\n }\n\n protected onAreaKeydown(area: ShellNavNode, event: KeyboardEvent): void {\n const ids = this.allAreas().map(a => a.id);\n const index = ids.indexOf(area.id);\n let target: string | undefined;\n switch (event.key) {\n case 'ArrowDown':\n target = ids[(index + 1) % ids.length];\n break;\n case 'ArrowUp':\n target = ids[(index - 1 + ids.length) % ids.length];\n break;\n case 'Home':\n target = ids[0];\n break;\n case 'End':\n target = ids[ids.length - 1];\n break;\n case 'ArrowRight':\n if (this.isBottomBar()) {\n target = ids[(index + 1) % ids.length];\n break;\n }\n if (this.hasFlyout(area)) {\n event.preventDefault();\n this.openNow(area.id, true);\n // The flyout is hidden by CSS (`display: none`) until the entry carries `.open`; render that\n // class first, otherwise browsers (and jsdom with styles) refuse to focus the hidden entry.\n this.changeDetector.detectChanges();\n this.flyoutItems(area)[0]?.focus();\n }\n return;\n case 'ArrowLeft':\n if (this.isBottomBar()) {\n target = ids[(index - 1 + ids.length) % ids.length];\n break;\n }\n return;\n case 'Escape':\n this.close();\n return;\n default:\n return;\n }\n if (target) {\n event.preventDefault();\n this.focusArea(target);\n }\n }\n\n protected onFlyoutKeydown(area: ShellNavNode, event: KeyboardEvent): void {\n const items = this.flyoutItems(area);\n const index = items.indexOf(event.target as HTMLElement);\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n items[(index + 1) % items.length]?.focus();\n break;\n case 'ArrowUp':\n event.preventDefault();\n items[(index - 1 + items.length) % items.length]?.focus();\n break;\n case 'Home':\n event.preventDefault();\n items[0]?.focus();\n break;\n case 'End':\n event.preventDefault();\n items[items.length - 1]?.focus();\n break;\n case 'Escape':\n case 'ArrowLeft':\n event.preventDefault();\n this.focusArea(area.id);\n this.close();\n break;\n }\n }\n\n /** A navigation happened: close the flyout without taking focus from the new page. */\n private closeOnNavigation(): void {\n const id = this.openId();\n if (id === null) {\n return;\n }\n const flyout = this.findByAttribute('id', `rail-flyout-${id}`);\n if (flyout && document.activeElement instanceof Node && flyout.contains(document.activeElement)) {\n // Focus would drop to <body> once the flyout hides.\n this.focusArea(id);\n }\n this.close();\n this.changeDetector.markForCheck();\n }\n\n private openNow(id: string, pinned: boolean): void {\n this.clearTimers();\n this.openId.set(id);\n this.pinned.set(pinned);\n }\n\n private close(): void {\n this.clearTimers();\n this.openId.set(null);\n this.pinned.set(false);\n }\n\n private cancelOpen(): void {\n if (this.openTimer !== null) {\n clearTimeout(this.openTimer);\n this.openTimer = null;\n }\n }\n\n private cancelClose(): void {\n if (this.closeTimer !== null) {\n clearTimeout(this.closeTimer);\n this.closeTimer = null;\n }\n }\n\n private clearTimers(): void {\n this.cancelOpen();\n this.cancelClose();\n }\n\n private focusArea(id: string): void {\n this.focusedId.set(id);\n this.findByAttribute('data-area-id', id)?.focus();\n }\n\n private entryOf(area: ShellNavNode): HTMLElement | null {\n return this.findByAttribute('data-entry-id', area.id);\n }\n\n private flyoutItems(area: ShellNavNode): HTMLElement[] {\n const flyout = this.findByAttribute('id', this.flyoutId(area));\n return flyout ? Array.from(flyout.querySelectorAll<HTMLElement>('.flyout-item')) : [];\n }\n\n /** Attribute lookup without building a selector from ids (no escaping needed). */\n private findByAttribute(name: string, value: string): HTMLElement | null {\n const candidates = this.host.nativeElement.querySelectorAll<HTMLElement>(`[${name}]`);\n return Array.from(candidates).find(element => element.getAttribute(name) === value) ?? null;\n }\n\n /** Below 640 px the rail is laid out horizontally at the bottom. */\n private isBottomBar(): boolean {\n return typeof window.matchMedia === 'function' && window.matchMedia('(max-width: 640px)').matches;\n }\n}\n","<nav class=\"rail\" [attr.aria-label]=\"m().railLabel\">\n <ul class=\"rail-list\" role=\"list\">\n @for (area of areas(); track area.id) {\n <ng-container *ngTemplateOutlet=\"entry; context: { $implicit: area }\"></ng-container>\n }\n </ul>\n @if (bottomAreas().length > 0) {\n <ul class=\"rail-list rail-bottom\" role=\"list\">\n @for (area of bottomAreas(); track area.id) {\n <ng-container *ngTemplateOutlet=\"entry; context: { $implicit: area }\"></ng-container>\n }\n </ul>\n }\n</nav>\n\n<ng-template #entry let-area>\n <li class=\"rail-entry\"\n [attr.data-entry-id]=\"area.id\"\n [class.open]=\"openId() === area.id\"\n [class.pinned]=\"pinned() && openId() === area.id\"\n (mouseenter)=\"onPointerEnter(area)\"\n (mouseleave)=\"onPointerLeave(area)\"\n (focusout)=\"onEntryFocusOut(area, $event)\">\n <button type=\"button\"\n class=\"rail-item\"\n [attr.data-area-id]=\"area.id\"\n [attr.aria-label]=\"areaLabel(area)\"\n [attr.aria-current]=\"area.id === activeAreaId() ? 'true' : null\"\n [attr.aria-expanded]=\"hasFlyout(area) ? openId() === area.id : null\"\n [attr.aria-controls]=\"hasFlyout(area) ? flyoutId(area) : null\"\n [tabindex]=\"tabStopId() === area.id ? 0 : -1\"\n (focus)=\"onAreaFocus(area)\"\n (keydown)=\"onAreaKeydown(area, $event)\"\n (click)=\"onAreaClick(area, $event)\">\n @if (area.svgIcon) {\n <kendo-svgicon class=\"rail-icon\" [icon]=\"area.svgIcon\"></kendo-svgicon>\n }\n @if (badgeOf(area); as badge) {\n <span class=\"rail-badge\" [class.attention]=\"badge.attention\" [attr.data-badge]=\"area.id\" aria-hidden=\"true\">{{ badgeText(badge) }}</span>\n }\n </button>\n @if (hasFlyout(area)) {\n <!-- The host starts right at the icon's edge; its transparent padding bridges the gap to the panel. -->\n <div class=\"rail-flyout-host\">\n <div class=\"rail-flyout\" [id]=\"flyoutId(area)\">\n <div class=\"flyout-title\" aria-hidden=\"true\">{{ area.text }}</div>\n <ul class=\"flyout-list\" [attr.aria-label]=\"area.text\">\n @for (child of area.children; track child.id) {\n @if (child.separator) {\n <li class=\"flyout-separator\" aria-hidden=\"true\"></li>\n } @else {\n <li>\n <button type=\"button\"\n class=\"flyout-item\"\n [class.active]=\"child.active\"\n [attr.aria-current]=\"child.selected ? 'page' : null\"\n [title]=\"child.tooltip ?? ''\"\n (keydown)=\"onFlyoutKeydown(area, $event)\"\n (click)=\"onItemClick(area, child)\">\n <span class=\"flyout-text\">{{ child.text }}</span>\n @if (badgeOf(child); as badge) {\n <span class=\"flyout-badge\" [class.attention]=\"badge.attention\" [attr.data-badge]=\"child.id\" aria-hidden=\"true\">{{ badgeText(badge) }}</span><span class=\"visually-hidden\">, {{ badgeLabel(badge) }}</span>\n }\n @if (child.external) {\n <span class=\"flyout-external\" aria-hidden=\"true\">↗</span><span class=\"visually-hidden\">{{ m().opensInNewTab }}</span>\n }\n </button>\n </li>\n @for (nested of child.children; track nested.id) {\n @if (!nested.separator) {\n <li>\n <button type=\"button\"\n class=\"flyout-item nested\"\n [class.active]=\"nested.active\"\n [attr.aria-current]=\"nested.selected ? 'page' : null\"\n (keydown)=\"onFlyoutKeydown(area, $event)\"\n (click)=\"onItemClick(area, nested)\">\n <span class=\"flyout-text\">{{ nested.text }}</span>\n @if (badgeOf(nested); as badge) {\n <span class=\"flyout-badge\" [class.attention]=\"badge.attention\" [attr.data-badge]=\"nested.id\" aria-hidden=\"true\">{{ badgeText(badge) }}</span><span class=\"visually-hidden\">, {{ badgeLabel(badge) }}</span>\n }\n @if (nested.external) {\n <span class=\"flyout-external\" aria-hidden=\"true\">↗</span><span class=\"visually-hidden\">{{ m().opensInNewTab }}</span>\n }\n </button>\n </li>\n }\n }\n }\n }\n </ul>\n </div>\n </div>\n }\n </li>\n</ng-template>\n","import { afterNextRender, afterRenderEffect, ChangeDetectionStrategy, Component, computed, DestroyRef, ElementRef, HostListener, inject, input, output, signal } from '@angular/core';\nimport { ShellNavNode } from '../shell-navigation.service';\nimport { SpaceStatusChip } from '../space-header.service';\nimport { SpaceMetaItem } from '../home-greeting';\nimport { formatShellMessage, ShellMessages, shellMessages } from '../shell.messages';\n\ninterface MenuPosition {\n top: number;\n left: number;\n}\n\n/**\n * The header of a space (concept §3.3): breadcrumbs, the area title with\n * optional status chips and a primary-action slot, and the tab strip built\n * from the area's children — the same entries the rail flyout lists.\n *\n * Content projection:\n * - `[spaceCrumbs]` — the breadcrumb line above the title\n * - `[spaceActions]` — primary actions, right of the title\n *\n * Tabs are navigation, not ARIA tabs (there is no tab panel): a `nav` with\n * buttons and `aria-current=\"page\"` on the active one. A grouping tab\n * without its own page (e.g. Swagger) is a menu button: opening moves focus\n * into the menu, Arrow Up/Down/Home/End move, Escape (on the button or in the\n * menu) closes and returns focus to the button, Tab / focus leaving / a click\n * outside / scrolling or resizing closes it. The menu is positioned `fixed`\n * from the button's bounding box, so the scrollable tab strip cannot clip it.\n * Without an area (a page outside the current mode's navigation) only the\n * breadcrumbs and actions are shown. A `heading` replaces the area name and a `meta` line\n * follows it (Home greets the user and names the tenant, wireframe screen 1).\n *\n * On an object detail page (`objectDetail`, AB#5547) the page's own object header\n * (name, chips, actions, object tabs) replaces the area title, the status chips and\n * the tab strip: the space header shrinks to one line with a back link to the list\n * the object belongs to (`backTarget`, e.g. \"Adapters\"), the breadcrumbs and the\n * actions slot.\n *\n * An empty breadcrumb line (AB#5621) takes no height: when the `[spaceCrumbs]` content shows\n * nothing (no text, no list item, link, button or image — e.g. a Kendo breadcrumb without\n * items) and there is no back link, the line collapses. It stays in the DOM with its width, so\n * a breadcrumb that measures its width (Kendo's collapse mode) is laid out right once items arrive.\n */\n@Component({\n selector: 'mm-space-shell',\n templateUrl: './space-shell.component.html',\n styleUrl: './space-shell.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class SpaceShellComponent {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n readonly area = input<ShellNavNode | null>(null);\n readonly activeTabId = input<string | null>(null);\n readonly chips = input<SpaceStatusChip[]>([]);\n /** Replaces the area name as the title (Home: the greeting, AB#5558). */\n readonly heading = input<string | null>(null);\n /** A short meta line right of the title (Home: the tenant), hidden on phones. */\n readonly meta = input<SpaceMetaItem[]>([]);\n /** The page renders its own object header; area title, chips and tabs are left out. */\n readonly objectDetail = input(false);\n /** Show the area's tab strip; false when the page lists the same entries itself (Settings home). */\n readonly showTabs = input(true);\n /** Target of the back link on an object detail page (the list of the object). */\n readonly backTarget = input<ShellNavNode | null>(null);\n /** Translations; members left out fall back to {@link SHELL_MESSAGES}, then English. */\n readonly messages = input<Partial<ShellMessages> | null>(null);\n protected readonly m = shellMessages(this.messages);\n\n readonly tabSelected = output<ShellNavNode>();\n\n /** The grouping tab whose menu is open. */\n protected readonly openMenuId = signal<string | null>(null);\n protected readonly menuPosition = signal<MenuPosition>({ top: 0, left: 0 });\n\n protected readonly tabs = computed(() => this.area()?.children ?? []);\n\n /** The breadcrumb line shows something (projected crumbs or the back link). */\n protected readonly hasCrumbs = signal(true);\n\n constructor() {\n // The projected crumbs change outside this component (async items): watch the line itself.\n const destroyRef = inject(DestroyRef);\n afterNextRender(() => {\n const crumbs = this.crumbsElement();\n if (!crumbs) {\n return;\n }\n this.updateHasCrumbs();\n if (typeof MutationObserver === 'function') {\n const observer = new MutationObserver(() => this.updateHasCrumbs());\n observer.observe(crumbs, { childList: true, subtree: true, characterData: true });\n destroyRef.onDestroy(() => observer.disconnect());\n }\n });\n\n // A tab strip wider than the screen (phones) scrolls sideways: keep the active tab visible.\n afterRenderEffect(() => {\n const id = this.activeTabId();\n this.tabs();\n if (id) {\n this.revealTab(id);\n }\n });\n }\n\n /** Scrolls the tab strip (only it, never the page) so the tab is fully visible. */\n revealTab(id: string): void {\n const strip = this.host.nativeElement.querySelector<HTMLElement>('.space-tabs');\n const tab = Array.from(strip?.querySelectorAll<HTMLElement>('[data-tab-id]') ?? [])\n .find(button => button.getAttribute('data-tab-id') === id);\n if (!strip || !tab) {\n return;\n }\n const stripRect = strip.getBoundingClientRect();\n const tabRect = tab.getBoundingClientRect();\n const margin = 16;\n if (tabRect.left < stripRect.left) {\n strip.scrollLeft += tabRect.left - stripRect.left - margin;\n } else if (tabRect.right > stripRect.right) {\n strip.scrollLeft += tabRect.right - stripRect.right + margin;\n }\n }\n\n private crumbsElement(): HTMLElement | null {\n return this.host.nativeElement.querySelector<HTMLElement>('.space-crumbs');\n }\n\n private updateHasCrumbs(): void {\n const crumbs = this.crumbsElement();\n const visible = !!crumbs && (\n (crumbs.textContent ?? '').trim().length > 0 ||\n crumbs.querySelector('li, a, button, img, svg, input, [role=\"img\"]') !== null\n );\n if (visible !== this.hasCrumbs()) {\n this.hasCrumbs.set(visible);\n }\n }\n\n protected format(message: string, values: Record<string, string>): string {\n return formatShellMessage(message, values);\n }\n\n protected onBackClick(target: ShellNavNode): void {\n this.tabSelected.emit(target);\n }\n\n protected isGroup(tab: ShellNavNode): boolean {\n return !tab.navigable && tab.children.some(child => !child.separator);\n }\n\n protected menuId(tab: ShellNavNode): string {\n return `space-tab-menu-${tab.id}`;\n }\n\n protected onTabClick(tab: ShellNavNode, button: HTMLElement): void {\n if (this.isGroup(tab)) {\n if (this.openMenuId() === tab.id) {\n this.closeMenu(false);\n } else {\n this.openMenu(tab, button);\n }\n return;\n }\n this.closeMenu(false);\n this.tabSelected.emit(tab);\n }\n\n protected onTabKeydown(tab: ShellNavNode, button: HTMLElement, event: KeyboardEvent): void {\n if (!this.isGroup(tab)) {\n return;\n }\n if (event.key === 'ArrowDown') {\n event.preventDefault();\n this.openMenu(tab, button);\n } else if (event.key === 'Escape' && this.openMenuId() === tab.id) {\n event.preventDefault();\n this.closeMenu(true);\n }\n }\n\n protected onMenuItemClick(item: ShellNavNode): void {\n this.closeMenu(true);\n this.tabSelected.emit(item);\n }\n\n protected onMenuKeydown(event: KeyboardEvent): void {\n const items = this.menuItems();\n const index = items.indexOf(event.target as HTMLElement);\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n items[(index + 1) % items.length]?.focus();\n break;\n case 'ArrowUp':\n event.preventDefault();\n items[(index - 1 + items.length) % items.length]?.focus();\n break;\n case 'Home':\n event.preventDefault();\n items[0]?.focus();\n break;\n case 'End':\n event.preventDefault();\n items[items.length - 1]?.focus();\n break;\n case 'Escape':\n event.preventDefault();\n this.closeMenu(true);\n break;\n case 'Tab':\n this.closeMenu(false);\n break;\n }\n }\n\n protected onWrapperFocusOut(tab: ShellNavNode, event: FocusEvent): void {\n const next = event.relatedTarget;\n const wrapper = event.currentTarget as HTMLElement;\n if (this.openMenuId() === tab.id && !(next instanceof Node && wrapper.contains(next))) {\n this.openMenuId.set(null);\n }\n }\n\n @HostListener('document:click', ['$event.target'])\n protected onDocumentClick(target: EventTarget | null): void {\n if (!this.openMenuId()) {\n return;\n }\n const wrapper = this.openWrapper();\n if (!(target instanceof Node && wrapper?.contains(target))) {\n this.openMenuId.set(null);\n }\n }\n\n @HostListener('window:resize')\n @HostListener('window:scroll')\n protected onViewportChange(): void {\n this.openMenuId.set(null);\n }\n\n private openMenu(tab: ShellNavNode, button: HTMLElement): void {\n const rect = button.getBoundingClientRect();\n this.menuPosition.set({ top: rect.bottom + 4, left: rect.left });\n this.openMenuId.set(tab.id);\n // The menu renders on the next change detection; focus its first entry then.\n setTimeout(() => this.menuItems()[0]?.focus());\n }\n\n private closeMenu(returnFocus: boolean): void {\n const wrapper = this.openWrapper();\n this.openMenuId.set(null);\n if (returnFocus) {\n wrapper?.querySelector<HTMLElement>('.space-tab')?.focus();\n }\n }\n\n private openWrapper(): HTMLElement | null {\n const id = this.openMenuId();\n if (!id) {\n return null;\n }\n const wrappers = this.host.nativeElement.querySelectorAll<HTMLElement>('[data-wrapper-id]');\n return Array.from(wrappers).find(wrapper => wrapper.getAttribute('data-wrapper-id') === id) ?? null;\n }\n\n private menuItems(): HTMLElement[] {\n return Array.from(this.openWrapper()?.querySelectorAll<HTMLElement>('[role=\"menuitem\"]') ?? []);\n }\n}\n","<header class=\"space-head\" [class.no-area]=\"!area()\" [class.object-detail]=\"objectDetail()\" [class.no-crumbs]=\"!hasCrumbs()\">\n <div class=\"space-crumbs\" [class.is-empty]=\"!hasCrumbs()\">\n @if (objectDetail() && backTarget(); as back) {\n <button type=\"button\"\n class=\"space-back\"\n data-testid=\"space-back\"\n [attr.aria-label]=\"format(m().backTo, { target: back.text })\"\n (click)=\"onBackClick(back)\">\n <span aria-hidden=\"true\">←</span> {{ back.text }}\n </button>\n }\n <ng-content select=\"[spaceCrumbs]\"></ng-content>\n </div>\n <div class=\"space-title-row\">\n @if (!objectDetail()) {\n @if (area(); as current) {\n <h1 class=\"space-title\">{{ heading() ?? current.text }}</h1>\n @if (meta().length > 0) {\n <p class=\"space-meta\">\n @for (item of meta(); track item.label) {\n <span class=\"space-meta-item\">{{ item.label }} <span class=\"space-meta-value\">{{ item.value }}</span></span>\n }\n </p>\n }\n }\n }\n @if (!objectDetail() && chips().length > 0) {\n <ul class=\"space-chips\" [attr.aria-label]=\"m().statusChips\">\n @for (chip of chips(); track chip.label) {\n <li class=\"space-chip\" [class]=\"'space-chip status-' + chip.status\">{{ chip.label }}</li>\n }\n </ul>\n }\n <div class=\"space-actions\">\n <ng-content select=\"[spaceActions]\"></ng-content>\n </div>\n </div>\n @if (area(); as current) {\n @if (!objectDetail() && showTabs() && tabs().length > 0) {\n <nav class=\"space-tabs\" [attr.aria-label]=\"format(m().areaPages, { area: current.text })\" (scroll)=\"onViewportChange()\">\n @for (tab of tabs(); track tab.id) {\n @if (tab.separator) {\n <span class=\"tab-separator\" aria-hidden=\"true\"></span>\n } @else {\n <div class=\"tab-wrapper\" [attr.data-wrapper-id]=\"tab.id\" (focusout)=\"onWrapperFocusOut(tab, $event)\">\n <button #tabButton\n type=\"button\"\n class=\"space-tab\"\n [attr.data-tab-id]=\"tab.id\"\n [attr.aria-current]=\"tab.id === activeTabId() ? 'page' : null\"\n [attr.aria-haspopup]=\"isGroup(tab) ? 'menu' : null\"\n [attr.aria-expanded]=\"isGroup(tab) ? openMenuId() === tab.id : null\"\n [attr.aria-controls]=\"isGroup(tab) && openMenuId() === tab.id ? menuId(tab) : null\"\n [title]=\"tab.tooltip ?? ''\"\n (keydown)=\"onTabKeydown(tab, tabButton, $event)\"\n (click)=\"onTabClick(tab, tabButton)\">\n {{ tab.text }}\n @if (tab.external) {\n <span class=\"tab-external\" aria-hidden=\"true\">↗</span><span class=\"visually-hidden\">{{ m().opensInNewTab }}</span>\n }\n @if (isGroup(tab)) {\n <span class=\"tab-caret\" aria-hidden=\"true\">▾</span>\n }\n </button>\n @if (isGroup(tab) && openMenuId() === tab.id) {\n <ul class=\"tab-menu\"\n role=\"menu\"\n [id]=\"menuId(tab)\"\n [attr.aria-label]=\"tab.text\"\n [style.top.px]=\"menuPosition().top\"\n [style.left.px]=\"menuPosition().left\"\n (keydown)=\"onMenuKeydown($event)\">\n @for (item of tab.children; track item.id) {\n @if (!item.separator) {\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" tabindex=\"-1\" class=\"tab-menu-item\" (click)=\"onMenuItemClick(item)\">\n {{ item.text }}\n @if (item.external) {\n <span class=\"tab-external\" aria-hidden=\"true\">↗</span><span class=\"visually-hidden\">{{ m().opensInNewTab }}</span>\n }\n </button>\n </li>\n }\n }\n </ul>\n }\n </div>\n }\n }\n </nav>\n }\n }\n</header>\n","import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { ShellNavNode } from '../shell-navigation.service';\nimport { SettingsSideNavBadge } from './settings-side-nav-badges.service';\nimport { formatShellMessage, ShellMessages, shellMessages } from '../shell.messages';\n\nlet nextSideNavId = 0;\n\n/**\n * A heading over some categories of the Settings side navigation (AB#5621).\n */\nexport interface SettingsSideNavGroup {\n id: string;\n /** Visible heading (already translated by the host). */\n label: string;\n /** Tab ids of the categories under the heading, in display order. */\n tabIds: readonly string[];\n}\n\n/** One block of the side navigation: a group with its categories, or the ungrouped ones. */\ninterface SideNavSection {\n id: string;\n label: string | null;\n categories: ShellNavNode[];\n}\n\n/**\n * The one navigation of the Settings space (concept §5.6, AB#5523): \"All settings\" plus the\n * categories of the Settings area on the left, on every Settings page — the home, the category\n * pages, the generated forms and the hand-written pages (secrets, identity providers, …). The\n * space header shows no tab strip in Settings, so opening a category never switches between two\n * navigation layouts.\n *\n * The entries are the area's children from the command tree (the same entries as the rail\n * flyout); counts and the re-entry badge come from {@link SettingsSideNavBadgesService}.\n * Navigation, not ARIA tabs: a `nav` with buttons and `aria-current=\"page\"` on the active one.\n *\n * Groups (AB#5621, optional): `groups` puts headings over the categories they list (in the\n * group's order); categories in no group follow without a heading, groups without a visible\n * category are left out. Without groups the list is flat, as before.\n *\n * Labels are shown exactly as given (AB#5621): the area name, the categories and the group\n * headings keep the host's case — no lower-casing, no CSS `text-transform`. A language that\n * needs a different case in \"All {area}\" sets `allOfArea` to the whole text.\n */\n@Component({\n selector: 'mm-settings-side-nav',\n templateUrl: './settings-side-nav.component.html',\n styleUrl: './settings-side-nav.component.scss',\n imports: [NgTemplateOutlet],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SettingsSideNavComponent {\n readonly area = input.required<ShellNavNode>();\n readonly activeTabId = input<string | null>(null);\n /** The Settings home is open (\"All settings\" is the current entry). */\n readonly homeActive = input(false);\n readonly badges = input<Record<string, SettingsSideNavBadge>>({});\n /** Optional headings over the categories; empty keeps the flat list. */\n readonly groups = input<readonly SettingsSideNavGroup[]>([]);\n /** Translations; members left out fall back to {@link SHELL_MESSAGES}, then English. */\n readonly messages = input<Partial<ShellMessages> | null>(null);\n protected readonly m = shellMessages(this.messages);\n\n readonly homeSelected = output<void>();\n readonly tabSelected = output<ShellNavNode>();\n\n protected readonly categories = computed(() => this.area().children.filter((child) => !child.separator));\n protected readonly sections = computed<SideNavSection[]>(() => {\n const categories = this.categories();\n const groups = this.groups();\n if (groups.length === 0) {\n return [{ id: '', label: null, categories }];\n }\n const byId = new Map(categories.map((category) => [category.id, category]));\n const placed = new Set<string>();\n const sections: SideNavSection[] = [];\n for (const group of groups) {\n const members = group.tabIds\n .filter((id) => byId.has(id) && !placed.has(id))\n .map((id) => byId.get(id) as ShellNavNode);\n members.forEach((member) => placed.add(member.id));\n if (members.length > 0) {\n sections.push({ id: group.id, label: group.label, categories: members });\n }\n }\n const rest = categories.filter((category) => !placed.has(category.id));\n if (rest.length > 0) {\n sections.push({ id: '', label: null, categories: rest });\n }\n return sections;\n });\n\n /** Unique per instance, so two side navs on one page never share heading ids. */\n private readonly instanceId = nextSideNavId++;\n\n protected groupHeadingId(section: SideNavSection): string {\n return `mm-settings-side-nav-${this.instanceId}-group-${section.id}`;\n }\n\n protected readonly navLabel = computed(() => formatShellMessage(this.m().areaCategories, { area: this.area().text }));\n protected readonly homeLabel = computed(() => formatShellMessage(this.m().allOfArea, { area: this.area().text }));\n}\n","<nav class=\"side-nav\" [attr.aria-label]=\"navLabel()\">\n <button type=\"button\"\n class=\"side-nav__item\"\n data-side-nav=\"home\"\n [attr.aria-current]=\"homeActive() ? 'page' : null\"\n (click)=\"homeSelected.emit()\">\n <span>{{ homeLabel() }}</span>\n </button>\n @for (section of sections(); track section.id) {\n @if (section.label) {\n <div class=\"side-nav__group\" role=\"group\" [attr.data-group]=\"section.id\" [attr.aria-labelledby]=\"groupHeadingId(section)\">\n <span class=\"side-nav__group-label\" [id]=\"groupHeadingId(section)\">{{ section.label }}</span>\n @for (category of section.categories; track category.id) {\n <ng-container *ngTemplateOutlet=\"item; context: { $implicit: category }\"></ng-container>\n }\n </div>\n } @else {\n @for (category of section.categories; track category.id) {\n <ng-container *ngTemplateOutlet=\"item; context: { $implicit: category }\"></ng-container>\n }\n }\n }\n</nav>\n\n<ng-template #item let-category>\n <button type=\"button\"\n class=\"side-nav__item\"\n [attr.data-tab-id]=\"category.id\"\n [attr.aria-current]=\"!homeActive() && category.id === activeTabId() ? 'page' : null\"\n [title]=\"category.tooltip ?? ''\"\n (click)=\"tabSelected.emit(category)\">\n <span>{{ category.text }}</span>\n @if (badges()[category.id]; as badge) {\n <span class=\"side-nav__count\"\n [class.is-attention]=\"badge.attention\"\n [attr.data-badge]=\"category.id\"\n [attr.aria-label]=\"badge.label ?? null\">{{ badge.count }}</span>\n }\n </button>\n</ng-template>\n","import { Injectable, signal } from '@angular/core';\n\n/** Badge of one Settings category in the side navigation. */\nexport interface SettingsSideNavBadge {\n count: number;\n /** Needs attention (open re-entry tasks): rendered as a warning badge. */\n attention?: boolean;\n /** Accessible label of the badge; without one the count is read as is. */\n label?: string;\n}\n\n/**\n * Counts and badges of the Settings side navigation, keyed by shell tab id\n * (`settings-<category>`). The Settings home fills them when it has loaded its\n * categories (forms + custom pages) and the secrets inventory; until then, and on a\n * deep link to another Settings page, the categories are shown without counts.\n */\n@Injectable({ providedIn: 'root' })\nexport class SettingsSideNavBadgesService {\n private readonly _badges = signal<Record<string, SettingsSideNavBadge>>({});\n\n readonly badges = this._badges.asReadonly();\n\n set(badges: Record<string, SettingsSideNavBadge>): void {\n this._badges.set(badges);\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, ElementRef, HostListener, inject, input, output, signal } from '@angular/core';\nimport { SVGIconComponent } from '@progress/kendo-angular-icons';\nimport { SVGIcon } from '@progress/kendo-svg-icons';\nimport { formatShellMessage, ShellMessages, shellMessages } from '../shell.messages';\n\n/** One density choice of the user menu (the host owns the density modes and applies them). */\nexport interface ShellDensityOption {\n mode: string;\n label: string;\n}\n\n/** One language of the user menu's language choice. */\nexport interface ShellLanguage {\n /** Language code the host understands, e.g. `'en'` or `'de-AT'`. */\n code: string;\n /** Name of the language, ideally in that language (\"Deutsch\"). */\n label: string;\n}\n\n/** The default language list: English only, shown as a fact instead of a choice. */\nexport const DEFAULT_SHELL_LANGUAGES: readonly ShellLanguage[] = [{ code: 'en', label: 'English' }];\n\n/** Theme preference of the user menu (same values as octo-ui's `ThemeModePreference`). */\nexport type ShellThemePreference = 'system' | 'light' | 'dark';\n\n/** The signed-in user as the user menu shows it. */\nexport interface ShellUser {\n /** Avatar initials; empty shows \"?\". */\n initials?: string | null;\n /** Full name, e.g. \"Gerald Lochner\". */\n displayName?: string | null;\n /** Login / account name, e.g. \"gerald\". */\n userName?: string | null;\n /** Account page of the identity provider; null leaves \"Manage profile\" out. */\n profileUri?: string | null;\n}\n\n/**\n * A host entry of the user menu (AB#5621), e.g. \"My identities\" or \"Developer info\". Listed\n * above \"Manage profile\" and \"Sign out\".\n */\nexport interface ShellUserMenuItem {\n id: string;\n /** Visible label (already translated by the host). */\n text: string;\n svgIcon?: SVGIcon;\n /** External link, opened in a new tab; without one choosing the entry emits `itemSelected`. */\n href?: string;\n}\n\ninterface ThemeOption {\n value: ShellThemePreference;\n label: string;\n}\n\n/**\n * Avatar menu of the top bar. Besides sign-out and the profile link it holds\n * the personal settings (concept §3.1, §10): theme mode, density and\n * language. Tenant configuration belongs elsewhere (the Settings space).\n *\n * - **Session**: `sessionLoading` shows a placeholder, `user` null offers \"Sign in\"\n * (`signIn` output), otherwise the avatar opens the panel; \"Sign out\" emits `signOut`.\n * The host wires its auth service (e.g. shared-auth's `AuthorizeService`).\n * - **Theme**: `theme` is the current preference, a choice emits `themeChange` (e.g. wired to\n * octo-ui's `ThemeModeService`).\n * - **Density** lists `densityOptions` (none: the group is left out); a choice emits\n * `densityChange`, the host applies and stores it and feeds `density` back.\n * - **Language** lists `languages`. With one language (the default, English) the entry\n * states it instead of offering a choice that changes nothing; with several it is a\n * radio group that emits `languageChange`. Persisting the choice (per user) and\n * switching the translations is the host's job; it feeds the current code back\n * through `language`.\n * - **Version** shows `version` when set.\n * - **Host entries** (AB#5621): `items` lists the host's own entries above \"Manage profile\" and\n * \"Sign out\"; choosing one closes the panel and emits `itemSelected` (entries with `href`\n * open in a new tab instead). For richer content the host may project elements with the\n * `shellUserMenuItems` attribute into the same place; a click on a button or link there\n * closes the panel as well.\n *\n * Opening moves focus into the panel, Escape or the avatar button close it\n * and return focus to the avatar. Theme, density and language are native radio groups\n * (arrow keys move and select, one tab stop each).\n */\n@Component({\n selector: 'mm-shell-user-menu',\n templateUrl: './user-menu.component.html',\n styleUrl: './user-menu.component.scss',\n imports: [SVGIconComponent],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ShellUserMenuComponent {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /** The signed-in user; null shows the \"Sign in\" button. */\n readonly user = input<ShellUser | null>(null);\n /** The session is being restored: a placeholder instead of avatar or sign-in. */\n readonly sessionLoading = input(false);\n /** The current theme preference. */\n readonly theme = input<ShellThemePreference>('system');\n\n /** Density choices; empty leaves the density group out. */\n readonly densityOptions = input<readonly ShellDensityOption[]>([]);\n /** The current density mode (one of `densityOptions`). */\n readonly density = input<string | null>(null);\n /** Languages to choose from; one entry is shown as a fact, none hides the entry. */\n readonly languages = input<readonly ShellLanguage[]>(DEFAULT_SHELL_LANGUAGES);\n /** The current language code; defaults to the first of `languages`. */\n readonly language = input<string | null>(null);\n /** App version shown at the bottom of the panel; null leaves the line out. */\n readonly version = input<string | null>(null);\n /** Host entries above \"Manage profile\" / \"Sign out\"; empty leaves the list out. */\n readonly items = input<readonly ShellUserMenuItem[]>([]);\n /** Translations; members left out fall back to {@link SHELL_MESSAGES}, then English. */\n readonly messages = input<Partial<ShellMessages> | null>(null);\n\n readonly signIn = output<void>();\n readonly signOut = output<void>();\n /** The person picked a theme preference. */\n readonly themeChange = output<ShellThemePreference>();\n /** The person picked a density mode. */\n readonly densityChange = output<string>();\n /** The person picked a language (its code). */\n readonly languageChange = output<string>();\n /** The person chose a host entry without `href`. */\n readonly itemSelected = output<ShellUserMenuItem>();\n\n protected readonly m = shellMessages(this.messages);\n protected readonly open = signal(false);\n\n protected readonly initials = computed(() => this.user()?.initials || '?');\n protected readonly fullName = computed(() => this.user()?.displayName || null);\n protected readonly userName = computed(() => this.user()?.userName || null);\n protected readonly profileUri = computed(() => this.user()?.profileUri || null);\n\n protected readonly avatarLabel = computed(() => {\n const name = this.fullName();\n return name ? formatShellMessage(this.m().accountAndPreferencesOf, { name }) : this.m().accountAndPreferences;\n });\n\n protected readonly versionText = computed(() => {\n const version = this.version();\n return version ? formatShellMessage(this.m().version, { version }) : null;\n });\n\n protected readonly themeOptions = computed<readonly ThemeOption[]>(() => [\n { value: 'system', label: this.m().themeSystem },\n { value: 'light', label: this.m().themeLight },\n { value: 'dark', label: this.m().themeDark }\n ]);\n\n /** The code of the current language: `language`, else the first of `languages`. */\n protected readonly currentLanguage = computed(() => this.language() ?? this.languages()[0]?.code ?? null);\n\n protected readonly currentLanguageLabel = computed(() => {\n const code = this.currentLanguage();\n const languages = this.languages();\n return (languages.find(language => language.code === code) ?? languages[0])?.label ?? null;\n });\n\n protected toggle(): void {\n if (this.open()) {\n this.close(true);\n } else {\n this.open.set(true);\n // Move focus into the panel once it is rendered: the checked theme radio.\n setTimeout(() => this.host.nativeElement.querySelector<HTMLElement>('.user-panel input:checked')?.focus());\n }\n }\n\n /** Closes the panel; `restoreFocus` puts focus back on the avatar button. */\n private close(restoreFocus: boolean): void {\n this.open.set(false);\n if (restoreFocus) {\n this.host.nativeElement.querySelector<HTMLElement>('.avatar-button')?.focus();\n }\n }\n\n protected setTheme(value: ShellThemePreference): void {\n this.themeChange.emit(value);\n }\n\n protected setDensity(mode: string): void {\n this.densityChange.emit(mode);\n }\n\n protected setLanguage(code: string): void {\n if (code !== this.currentLanguage()) {\n this.languageChange.emit(code);\n }\n }\n\n /** A host entry: close the panel (focus back on the avatar), then let the host act. */\n protected selectItem(item: ShellUserMenuItem): void {\n this.close(true);\n this.itemSelected.emit(item);\n }\n\n /** An external host entry opens in a new tab; the panel closes and focus returns to the avatar. */\n protected followItemLink(): void {\n this.close(true);\n }\n\n /** A click on a button or link of the projected `shellUserMenuItems` content closes the panel. */\n protected onProjectedClick(event: Event): void {\n const target = event.target;\n if (target instanceof Element && target.closest('button, a[href]')) {\n this.close(true);\n }\n }\n\n protected login(): void {\n this.signIn.emit();\n }\n\n protected logout(): void {\n this.open.set(false);\n this.signOut.emit();\n }\n\n @HostListener('document:keydown.escape')\n protected onEscape(): void {\n if (this.open()) {\n this.close(true);\n }\n }\n\n /** A click outside closes without stealing focus from what was clicked. */\n @HostListener('document:click', ['$event.target'])\n protected onDocumentClick(target: EventTarget | null): void {\n if (this.open() && target instanceof Node && !this.host.nativeElement.contains(target)) {\n this.close(false);\n }\n }\n\n /** Tabbing out of the panel closes it. */\n protected onPanelFocusOut(event: FocusEvent): void {\n const next = event.relatedTarget;\n if (next instanceof Node && !this.host.nativeElement.contains(next)) {\n this.close(false);\n }\n }\n}\n","@if (sessionLoading()) {\n <span class=\"avatar placeholder\" aria-hidden=\"true\"></span>\n} @else if (!user()) {\n <button type=\"button\" class=\"sign-in\" (click)=\"login()\">{{ m().signIn }}</button>\n} @else {\n <button type=\"button\"\n class=\"avatar-button\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"open()\"\n aria-controls=\"user-menu-panel\"\n [attr.aria-label]=\"avatarLabel()\"\n (click)=\"toggle()\">\n <span class=\"avatar\">{{ initials() }}</span>\n </button>\n @if (open()) {\n <div class=\"user-panel\" id=\"user-menu-panel\" role=\"dialog\" [attr.aria-label]=\"m().accountAndPreferences\" (focusout)=\"onPanelFocusOut($event)\">\n <div class=\"user-identity\">\n <span class=\"avatar large\" aria-hidden=\"true\">{{ initials() }}</span>\n <div class=\"user-names\">\n @if (fullName(); as name) {\n <span class=\"user-full-name\">{{ name }}</span>\n }\n @if (userName(); as account) {\n <span class=\"user-login\">{{ account }}</span>\n }\n </div>\n </div>\n\n <fieldset class=\"pref\">\n <legend class=\"pref-label\">{{ m().theme }}</legend>\n <div class=\"segmented\">\n @for (option of themeOptions(); track option.value) {\n <label class=\"segment\">\n <input type=\"radio\"\n name=\"user-menu-theme\"\n class=\"pref-radio\"\n [value]=\"option.value\"\n [checked]=\"theme() === option.value\"\n (change)=\"setTheme(option.value)\" />\n <span>{{ option.label }}</span>\n </label>\n }\n </div>\n </fieldset>\n\n @if (densityOptions().length > 0) {\n <fieldset class=\"pref\">\n <legend class=\"pref-label\">{{ m().density }}</legend>\n <div class=\"option-list\">\n @for (option of densityOptions(); track option.mode) {\n <label class=\"option\">\n <input type=\"radio\"\n name=\"user-menu-density\"\n class=\"pref-radio\"\n [value]=\"option.mode\"\n [checked]=\"density() === option.mode\"\n (change)=\"setDensity(option.mode)\" />\n <span>{{ option.label }}</span>\n </label>\n }\n </div>\n </fieldset>\n }\n\n @if (languages().length > 1) {\n <fieldset class=\"pref\">\n <legend class=\"pref-label\">{{ m().language }}</legend>\n <div class=\"option-list\">\n @for (option of languages(); track option.code) {\n <label class=\"option\">\n <input type=\"radio\"\n name=\"user-menu-language\"\n class=\"pref-radio\"\n [value]=\"option.code\"\n [checked]=\"currentLanguage() === option.code\"\n (change)=\"setLanguage(option.code)\" />\n <span [attr.lang]=\"option.code\">{{ option.label }}</span>\n </label>\n }\n </div>\n </fieldset>\n } @else if (currentLanguageLabel(); as languageLabel) {\n <div class=\"pref\">\n <span class=\"pref-label\">{{ m().language }}</span>\n <span class=\"pref-value\">{{ languageLabel }}</span>\n </div>\n }\n\n @if (items().length > 0) {\n <ul class=\"user-items\" role=\"list\">\n @for (item of items(); track item.id) {\n <li>\n @if (item.href) {\n <a class=\"user-item\" [attr.data-user-item]=\"item.id\" [href]=\"item.href\" target=\"_blank\" rel=\"noopener noreferrer\" (click)=\"followItemLink()\">\n @if (item.svgIcon) {\n <kendo-svgicon class=\"user-item-icon\" [icon]=\"item.svgIcon\"></kendo-svgicon>\n }\n <span class=\"user-item-text\">{{ item.text }}</span>\n <span aria-hidden=\"true\">↗</span><span class=\"visually-hidden\">{{ m().opensInNewTab }}</span>\n </a>\n } @else {\n <button type=\"button\" class=\"user-item\" [attr.data-user-item]=\"item.id\" (click)=\"selectItem(item)\">\n @if (item.svgIcon) {\n <kendo-svgicon class=\"user-item-icon\" [icon]=\"item.svgIcon\"></kendo-svgicon>\n }\n <span class=\"user-item-text\">{{ item.text }}</span>\n </button>\n }\n </li>\n }\n </ul>\n }\n <div class=\"user-items-slot\" (click)=\"onProjectedClick($event)\">\n <ng-content select=\"[shellUserMenuItems]\"></ng-content>\n </div>\n\n <div class=\"user-actions\">\n @if (profileUri(); as uri) {\n <a class=\"action-link\" [href]=\"uri\" target=\"_blank\" rel=\"noopener noreferrer\">{{ m().manageProfile }} <span aria-hidden=\"true\">↗</span><span class=\"visually-hidden\">{{ m().opensInNewTab }}</span></a>\n }\n <button type=\"button\" class=\"action-button\" (click)=\"logout()\">{{ m().signOut }}</button>\n </div>\n\n @if (versionText(); as text) {\n <div class=\"user-version\">{{ text }}</div>\n }\n </div>\n }\n}\n","import { ChangeDetectionStrategy, Component, computed, inject, input, output } from '@angular/core';\nimport { ShellSearchTriggerService } from '../shell-search-trigger.service';\nimport {\n DEFAULT_SHELL_LANGUAGES,\n ShellDensityOption,\n ShellLanguage,\n ShellThemePreference,\n ShellUser,\n ShellUserMenuComponent,\n ShellUserMenuItem\n} from '../user-menu/user-menu.component';\nimport { ShellEnvironmentChip } from '../shell-environment';\nimport { ShellMessages, shellMessages } from '../shell.messages';\n\n/** One choice of the top bar's mode switch (e.g. Home | Studio). */\nexport interface ShellModeOption {\n id: string;\n label: string;\n /** Tooltip. */\n description?: string;\n}\n\n/**\n * Top bar (concept §3.1, wireframe): brand mark + name, tenant switcher with the\n * environment chip, the mode switch, the search trigger, the optional ✦ assistant\n * toggle and the avatar menu (`mm-shell-user-menu`) with the personal settings.\n *\n * Pure presentation; the host feeds everything in and handles the outputs:\n *\n * - **Brand**: `brandName` and `brandMarkSrc` (an image URL of the host; none: no mark).\n * - **Tenant**: inside a tenant (`tenantId`) the host projects its tenant switcher with the\n * `shellTenant` attribute (e.g. octo-ui's `<mm-tenant-switcher shellTenant …>`, which the\n * bar styles flat); the environment chip follows it.\n * - **Environment**: `environment` (e.g. from {@link shellEnvironmentChip}); null hides the\n * chip (also while the tenant mode is loading). `production: true` tints the bar.\n * - **Mode switch**: `modes` + `currentMode`; shown with two or more modes inside a tenant\n * the user may open. Picking the other mode emits `modeChange`; the host applies it.\n * - **Search**: the button calls {@link ShellSearchTriggerService.request} and emits\n * `searchRequested`; the host (or the palette) opens the command palette.\n * - **Assistant**: `assistantAvailable` shows the ✦ toggle (inside a tenant the user may\n * open); a click emits `assistantToggle`, `assistantOpen` reflects the panel state.\n * - **User menu**: `user`, `sessionLoading`, `theme`, `densityOptions`, `density`,\n * `languages`, `language`, `version` and the outputs `signIn`, `signOut`, `themeChange`,\n * `densityChange` and `languageChange` are passed through to `mm-shell-user-menu`, as are the\n * host entries (AB#5621): `userMenuItems` → `items`, `itemSelected` → `userMenuItemSelected`,\n * and content with the `shellUserMenuItems` attribute, projected into the panel.\n */\n@Component({\n selector: 'mm-shell-top-bar',\n imports: [ShellUserMenuComponent],\n templateUrl: './top-bar.component.html',\n styleUrl: './top-bar.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class ShellTopBarComponent {\n private readonly searchTrigger = inject(ShellSearchTriggerService);\n\n readonly tenantId = input<string | null>(null);\n readonly isDenied = input(false);\n\n /** Product name next to the mark, e.g. \"OctoMesh Studio\". */\n readonly brandName = input('OctoMesh');\n /** URL of the brand mark image (decorative); null leaves the mark out. */\n readonly brandMarkSrc = input<string | null>(null);\n /** The tenant's environment chip; null hides it. */\n readonly environment = input<ShellEnvironmentChip | null>(null);\n /** Choices of the mode switch; fewer than two hide it. */\n readonly modes = input<readonly ShellModeOption[]>([]);\n /** Id of the mode in effect. */\n readonly currentMode = input<string | null>(null);\n /** Shows the ✦ assistant toggle (feature flag on and the panel can be hosted). */\n readonly assistantAvailable = input(false);\n /** The assistant panel is open (`aria-expanded` of the toggle). */\n readonly assistantOpen = input(false);\n /** Id of the assistant panel element (`aria-controls` while open). */\n readonly assistantPanelId = input('assistant-panel');\n\n // --- passed through to mm-shell-user-menu ---\n readonly user = input<ShellUser | null>(null);\n readonly sessionLoading = input(false);\n readonly theme = input<ShellThemePreference>('system');\n readonly densityOptions = input<readonly ShellDensityOption[]>([]);\n readonly density = input<string | null>(null);\n readonly languages = input<readonly ShellLanguage[]>(DEFAULT_SHELL_LANGUAGES);\n readonly language = input<string | null>(null);\n readonly version = input<string | null>(null);\n /** Host entries of the user menu (its `items`). */\n readonly userMenuItems = input<readonly ShellUserMenuItem[]>([]);\n\n /** Translations; members left out fall back to {@link SHELL_MESSAGES}, then English. */\n readonly messages = input<Partial<ShellMessages> | null>(null);\n\n /** The person picked the other mode; the host applies it and rebuilds the navigation. */\n readonly modeChange = output<string>();\n /** The search trigger was used. */\n readonly searchRequested = output<void>();\n /** The ✦ toggle was used. */\n readonly assistantToggle = output<void>();\n readonly signIn = output<void>();\n readonly signOut = output<void>();\n readonly themeChange = output<ShellThemePreference>();\n readonly densityChange = output<string>();\n readonly languageChange = output<string>();\n /** A host entry of the user menu was chosen (its `itemSelected`). */\n readonly userMenuItemSelected = output<ShellUserMenuItem>();\n\n protected readonly m = shellMessages(this.messages);\n\n protected readonly isProduction = computed(() => this.environment()?.production === true);\n\n protected readonly showEnvironment = computed(() => !!this.environment() && !this.isDenied());\n\n /** A switch with one choice would be noise (e.g. users without builder roles). */\n protected readonly showModeSwitch = computed(() =>\n !!this.tenantId() && !this.isDenied() && this.modes().length > 1);\n\n /** The ✦ toggle: only when available and inside a tenant the user may open. */\n protected readonly showAssistant = computed(() =>\n this.assistantAvailable() && !!this.tenantId() && !this.isDenied());\n\n /** ⌘K on Apple platforms, Ctrl K elsewhere — the shortcut the palette binds. */\n private readonly isApple = /Mac|iPhone|iPad/i.test(navigator.platform ?? '');\n protected readonly shortcutLabel = this.isApple ? '⌘K' : 'Ctrl K';\n /** ⌘J / Ctrl J — the assistant shortcut the host binds. */\n protected readonly assistantShortcutLabel = this.isApple ? '⌘J' : 'Ctrl J';\n /** Both chords work everywhere; the platform's usual one is listed first. */\n protected readonly assistantKeyShortcut = this.isApple ? 'Meta+J Control+J' : 'Control+J Meta+J';\n\n protected selectMode(mode: string): void {\n if (mode !== this.currentMode()) {\n this.modeChange.emit(mode);\n }\n }\n\n protected toggleAssistant(): void {\n this.assistantToggle.emit();\n }\n\n protected requestSearch(): void {\n this.searchTrigger.request();\n this.searchRequested.emit();\n }\n}\n","<header class=\"top-bar\" [class.production]=\"isProduction()\">\n <div class=\"brand\">\n @if (brandMarkSrc(); as markSrc) {\n <img [src]=\"markSrc\" class=\"brand-mark\" alt=\"\" aria-hidden=\"true\" />\n }\n <span class=\"brand-name\">{{ brandName() }}</span>\n </div>\n\n @if (tenantId()) {\n <span class=\"separator\" aria-hidden=\"true\"></span>\n <div class=\"tenant\">\n <ng-content select=\"[shellTenant]\"></ng-content>\n @if (showEnvironment() && environment(); as env) {\n <span class=\"env-chip\" [class]=\"'env-chip status-' + env.status\" [title]=\"env.label\">\n <span class=\"env-label\">{{ env.label }}</span>\n <span class=\"env-short\" aria-hidden=\"true\">{{ env.short }}</span>\n </span>\n }\n </div>\n }\n\n @if (showModeSwitch()) {\n <div class=\"mode-switch\" role=\"group\" [attr.aria-label]=\"m().modeSwitch\">\n @for (option of modes(); track option.id) {\n <button type=\"button\"\n [attr.aria-pressed]=\"currentMode() === option.id\"\n [title]=\"option.description ?? ''\"\n (click)=\"selectMode(option.id)\">{{ option.label }}</button>\n }\n </div>\n }\n\n <button type=\"button\" class=\"search\" [attr.aria-label]=\"m().searchAriaLabel\" (click)=\"requestSearch()\">\n <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><circle cx=\"11\" cy=\"11\" r=\"7\" /><path d=\"m20 20-3.5-3.5\" /></svg>\n <span class=\"search-label\">{{ m().search }}</span>\n <kbd class=\"search-shortcut\">{{ shortcutLabel }}</kbd>\n </button>\n\n <div class=\"top-actions\">\n @if (showAssistant()) {\n <button type=\"button\" class=\"ai-btn\" data-assistant-toggle\n [attr.aria-expanded]=\"assistantOpen()\"\n [attr.aria-controls]=\"assistantOpen() ? assistantPanelId() : null\"\n [attr.aria-keyshortcuts]=\"assistantKeyShortcut\"\n (click)=\"toggleAssistant()\">\n <span class=\"ai-sparkle\" aria-hidden=\"true\">✦</span>\n <span class=\"ai-label\">{{ m().assistant }}</span>\n <kbd class=\"ai-shortcut\" aria-hidden=\"true\">{{ assistantShortcutLabel }}</kbd>\n </button>\n }\n <mm-shell-user-menu\n [user]=\"user()\"\n [sessionLoading]=\"sessionLoading()\"\n [theme]=\"theme()\"\n [densityOptions]=\"densityOptions()\"\n [density]=\"density()\"\n [languages]=\"languages()\"\n [language]=\"language()\"\n [version]=\"version()\"\n [items]=\"userMenuItems()\"\n [messages]=\"messages()\"\n (signIn)=\"signIn.emit()\"\n (signOut)=\"signOut.emit()\"\n (themeChange)=\"themeChange.emit($event)\"\n (densityChange)=\"densityChange.emit($event)\"\n (languageChange)=\"languageChange.emit($event)\"\n (itemSelected)=\"userMenuItemSelected.emit($event)\">\n <ng-container ngProjectAs=\"[shellUserMenuItems]\">\n <ng-content select=\"[shellUserMenuItems]\"></ng-content>\n </ng-container>\n </mm-shell-user-menu>\n </div>\n</header>\n","/*\n * Public API Surface of @meshmakers/shared-ui/shell (AB#5621)\n */\n\n/**\n * App shell building blocks of the OctoMesh Refinery Studio, usable by any host app\n * (independent of OctoMesh: no octo-* or shared-auth imports):\n * rail, space header with tab strip, settings side navigation, top bar and user menu,\n * plus the services that turn the host's command tree into areas and tabs.\n *\n * Usage (host AppComponent):\n *\n * ```ts\n * import {\n * ShellNavigationService, SpaceHeaderService, ShellRailComponent, SpaceShellComponent,\n * ShellTopBarComponent, SettingsSideNavComponent, shellEnvironmentChip\n * } from '@meshmakers/shared-ui/shell';\n *\n * @Component({\n * imports: [ShellTopBarComponent, ShellRailComponent, SpaceShellComponent, SettingsSideNavComponent, RouterOutlet],\n * template: `\n * <mm-shell-top-bar brandName=\"My App\" brandMarkSrc=\"assets/mark.svg\"\n * [tenantId]=\"tenantId()\" [environment]=\"environment()\"\n * [user]=\"user()\" [sessionLoading]=\"auth.sessionLoading()\" (signIn)=\"auth.login()\" (signOut)=\"auth.logout()\"\n * [theme]=\"themeMode.preference()\" (themeChange)=\"themeMode.setPreference($event)\"\n * [languages]=\"languages\" [language]=\"language()\" (languageChange)=\"setLanguage($event)\"\n * (searchRequested)=\"palette.open()\">\n * <mm-tenant-switcher shellTenant [currentTenantId]=\"tenantId()\" (tenantSelected)=\"openTenant($event)\" />\n * </mm-shell-top-bar>\n * <mm-shell-rail [areas]=\"nav.topAreas()\" [bottomAreas]=\"nav.bottomAreas()\"\n * [activeAreaId]=\"nav.activeArea()?.id ?? null\" [badges]=\"{ 'area-inbox': inboxCount() }\"\n * (areaSelected)=\"nav.openArea($event)\" (itemSelected)=\"nav.open($event)\" />\n * <mm-space-shell [area]=\"nav.activeArea()\" [activeTabId]=\"nav.activeTab()?.id ?? null\"\n * [chips]=\"spaceHeader.chips()\" [showTabs]=\"nav.showTabs()\" (tabSelected)=\"nav.open($event)\">\n * <kendo-breadcrumb spaceCrumbs [items]=\"crumbs()\" />\n * </mm-space-shell>\n * <router-outlet />`\n * })\n * export class AppComponent {\n * protected readonly nav = inject(ShellNavigationService);\n * protected readonly spaceHeader = inject(SpaceHeaderService);\n * }\n * ```\n *\n * The navigation model is the host's `CommandSettingsService` command tree (shared-services):\n * top-level items with id `areaId('<space>')` become rail areas, their children\n * (`tabId('<space>', '<tab>')`) tabs; a top-level separator with id `RAIL_BOTTOM_SEPARATOR_ID`\n * pins the following areas to the bottom. Route data `{ space, tab, objectDetail, spaceTabs }`\n * refines the active area/tab.\n *\n * Optional providers:\n * - `SHELL_MESSAGES` — translations (`Partial<ShellMessages>`, English defaults; every component\n * also has a `messages` input that wins over the token);\n * - `SHELL_SETTINGS_SPACE` — the space that uses the settings side navigation (default `'settings'`,\n * `null` for none);\n * - `NOTIFICATION_DISPLAY_OPTIONS` (shared-ui) with `SHELL_NOTIFICATION_OPTIONS` for the toast stacking.\n *\n * User, theme, mode, density, language and environment are inputs with matching outputs;\n * applying and persisting them (per user) is the host's job.\n */\n\n// --- Messages / i18n ---\nexport {\n DEFAULT_SHELL_MESSAGES,\n SHELL_MESSAGES,\n resolveShellMessages,\n formatShellMessage,\n} from './shell.messages';\nexport type { ShellMessages } from './shell.messages';\n\n// --- Navigation model ---\nexport { areaId, spaceOfAreaId, tabId, RAIL_BOTTOM_SEPARATOR_ID, SHELL_SETTINGS_SPACE } from './shell-areas';\nexport { ShellNavigationService } from './shell-navigation.service';\nexport type { ShellNavNode, ShellRouteData, ShellNavItemKind } from './shell-navigation.service';\nexport { resolveShellBadge, shellBadgeText, SHELL_BADGE_MAX } from './shell-badges';\nexport type { ShellNavBadge, ShellNavBadges } from './shell-badges';\nexport { SpaceHeaderService } from './space-header.service';\nexport type { SpaceStatusChip } from './space-header.service';\nexport { ShellSearchTriggerService } from './shell-search-trigger.service';\nexport { shellBreadcrumbs, crumbPath, isAreaCrumb } from './shell-breadcrumbs';\nexport type { ShellAreaCrumb, ShellBreadcrumbOptions } from './shell-breadcrumbs';\n\n// --- Pure helpers / configuration ---\nexport { greetingPhrase, firstNameOf, homeGreeting, homeMeta } from './home-greeting';\nexport type { SpaceMetaItem, GreetingUser } from './home-greeting';\nexport { shellEnvironmentChip } from './shell-environment';\nexport type { ShellEnvironmentChip, ShellEnvironmentMode, ShellStatus } from './shell-environment';\nexport { SHELL_NOTIFICATION_OPTIONS } from './shell-notifications';\n\n// --- Components ---\nexport { ShellRailComponent, RAIL_FLYOUT_OPEN_DELAY, RAIL_FLYOUT_CLOSE_DELAY } from './rail/rail.component';\nexport { SpaceShellComponent } from './space-shell/space-shell.component';\nexport { SettingsSideNavComponent } from './settings-side-nav/settings-side-nav.component';\nexport type { SettingsSideNavGroup } from './settings-side-nav/settings-side-nav.component';\nexport { SettingsSideNavBadgesService } from './settings-side-nav/settings-side-nav-badges.service';\nexport type { SettingsSideNavBadge } from './settings-side-nav/settings-side-nav-badges.service';\nexport { ShellTopBarComponent } from './top-bar/top-bar.component';\nexport type { ShellModeOption } from './top-bar/top-bar.component';\nexport { ShellUserMenuComponent, DEFAULT_SHELL_LANGUAGES } from './user-menu/user-menu.component';\nexport type { ShellDensityOption, ShellLanguage, ShellThemePreference, ShellUser, ShellUserMenuItem } from './user-menu/user-menu.component';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ /** Kendo widget-internal buttons (not authored by the host template). */
2
+ const KENDO_INTERNAL_SELECTOR = '.k-input-button, .k-spinner-increase, .k-spinner-decrease, .k-clear-value, .k-pager-nav, .k-pager-numbers button';
3
+ /** Elements that act as buttons. */
4
+ const BUTTON_SELECTOR = 'button, a.k-button, [role="button"]';
5
+ /** Icon content of a button. */
6
+ const ICON_SELECTOR = 'svg, kendo-svgicon, kendo-svg-icon, kendo-icon, .k-icon, .k-svg-icon';
7
+ function rootElement(root) {
8
+ if (root instanceof Element || (typeof Document !== 'undefined' && root instanceof Document)) {
9
+ return root;
10
+ }
11
+ const fixture = root;
12
+ fixture.detectChanges();
13
+ return fixture.nativeElement;
14
+ }
15
+ /** Visible text of a button (without visually hidden helper text such as disabled reasons). */
16
+ function visibleText(button) {
17
+ return (button.textContent ?? '').replace(/\s+/g, ' ').trim();
18
+ }
19
+ function accessibleName(button) {
20
+ const label = button.getAttribute('aria-label')?.trim();
21
+ if (label)
22
+ return label;
23
+ const labelledBy = button.getAttribute('aria-labelledby');
24
+ if (labelledBy) {
25
+ const scope = button.getRootNode();
26
+ return labelledBy.split(/\s+/)
27
+ .map((id) => (button.ownerDocument.getElementById(id) ?? scope.querySelector?.(`[id="${id}"]`))?.textContent?.trim() ?? '')
28
+ .join(' ').trim();
29
+ }
30
+ return '';
31
+ }
32
+ function describe(button) {
33
+ const html = button.outerHTML.replace(/\s+/g, ' ');
34
+ return html.length > 160 ? `${html.slice(0, 157)}...` : html;
35
+ }
36
+ /**
37
+ * Icon-only buttons (an icon, no visible text) that miss an accessible name (`aria-label` /
38
+ * `aria-labelledby`) or — unless `requireTooltip: false` — a tooltip (`title`). Returns one
39
+ * message per offending button.
40
+ */
41
+ function findInaccessibleIconButtons(root, options = {}) {
42
+ const requireTooltip = options.requireTooltip ?? true;
43
+ const problems = [];
44
+ for (const button of Array.from(rootElement(root).querySelectorAll(BUTTON_SELECTOR))) {
45
+ if (options.ignore && button.closest(options.ignore))
46
+ continue;
47
+ if (!options.includeKendoInternals && button.matches(KENDO_INTERNAL_SELECTOR))
48
+ continue;
49
+ if (!button.querySelector(ICON_SELECTOR) || visibleText(button) !== '')
50
+ continue;
51
+ const missing = [];
52
+ if (!accessibleName(button))
53
+ missing.push('aria-label');
54
+ if (requireTooltip && !button.getAttribute('title')?.trim())
55
+ missing.push('title/tooltip');
56
+ if (missing.length) {
57
+ problems.push(`icon-only button without ${missing.join(' and ')}: ${describe(button)}`);
58
+ }
59
+ }
60
+ return problems;
61
+ }
62
+ /**
63
+ * Fails (throws) when the rendered fixture / element contains an icon-only button without an
64
+ * accessible name and a tooltip (Studio action guideline §2.2, AB#5581). Runs `detectChanges()`
65
+ * on a fixture first.
66
+ *
67
+ * ```ts
68
+ * import { expectIconButtonsAccessible } from '@meshmakers/shared-ui/testing';
69
+ *
70
+ * it('names every icon-only button', () => {
71
+ * expectIconButtonsAccessible(fixture);
72
+ * });
73
+ * ```
74
+ */
75
+ function expectIconButtonsAccessible(root, options = {}) {
76
+ const problems = findInaccessibleIconButtons(root, options);
77
+ if (problems.length) {
78
+ throw new Error(`${problems.length} inaccessible icon-only button(s):\n- ${problems.join('\n- ')}`);
79
+ }
80
+ }
81
+
82
+ /*
83
+ * Public API Surface of @meshmakers/shared-ui/testing (AB#5581): spec helpers, framework-agnostic
84
+ * (they throw an Error instead of calling a test runner's expect).
85
+ */
86
+
87
+ /**
88
+ * Generated bundle index. Do not edit.
89
+ */
90
+
91
+ export { expectIconButtonsAccessible, findInaccessibleIconButtons };
92
+ //# sourceMappingURL=meshmakers-shared-ui-testing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meshmakers-shared-ui-testing.mjs","sources":["../../../../projects/meshmakers/shared-ui/testing/src/icon-button-a11y.ts","../../../../projects/meshmakers/shared-ui/testing/src/public-api.ts","../../../../projects/meshmakers/shared-ui/testing/src/meshmakers-shared-ui-testing.ts"],"sourcesContent":["import type {ComponentFixture} from '@angular/core/testing';\n\n/** Options of {@link expectIconButtonsAccessible} / {@link findInaccessibleIconButtons}. */\nexport interface IconButtonA11yOptions {\n /**\n * Also require a tooltip (`title`) next to the accessible name — the Studio action guideline\n * (§2.2) wants both: tooltip = label for sighted users, `aria-label` = label + target. Default `true`.\n */\n requireTooltip?: boolean;\n /** CSS selector of elements to skip (e.g. third-party widgets the spec does not own). */\n ignore?: string;\n /**\n * Also check Kendo's widget-internal buttons (dropdown arrows, spinners, pager selects — named by\n * Kendo with `aria-label` only, not in the host's hands). Default `false`.\n */\n includeKendoInternals?: boolean;\n}\n\n/** Kendo widget-internal buttons (not authored by the host template). */\nconst KENDO_INTERNAL_SELECTOR = '.k-input-button, .k-spinner-increase, .k-spinner-decrease, .k-clear-value, .k-pager-nav, .k-pager-numbers button';\n\n/** Elements that act as buttons. */\nconst BUTTON_SELECTOR = 'button, a.k-button, [role=\"button\"]';\n/** Icon content of a button. */\nconst ICON_SELECTOR = 'svg, kendo-svgicon, kendo-svg-icon, kendo-icon, .k-icon, .k-svg-icon';\n\ntype Root = ComponentFixture<unknown> | Element | Document;\n\nfunction rootElement(root: Root): ParentNode {\n if (root instanceof Element || (typeof Document !== 'undefined' && root instanceof Document)) {\n return root;\n }\n const fixture = root as ComponentFixture<unknown>;\n fixture.detectChanges();\n return fixture.nativeElement as Element;\n}\n\n/** Visible text of a button (without visually hidden helper text such as disabled reasons). */\nfunction visibleText(button: Element): string {\n return (button.textContent ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction accessibleName(button: Element): string {\n const label = button.getAttribute('aria-label')?.trim();\n if (label) return label;\n const labelledBy = button.getAttribute('aria-labelledby');\n if (labelledBy) {\n const scope = button.getRootNode() as ParentNode;\n return labelledBy.split(/\\s+/)\n .map((id) => (button.ownerDocument.getElementById(id) ?? scope.querySelector?.(`[id=\"${id}\"]`))?.textContent?.trim() ?? '')\n .join(' ').trim();\n }\n return '';\n}\n\nfunction describe(button: Element): string {\n const html = button.outerHTML.replace(/\\s+/g, ' ');\n return html.length > 160 ? `${html.slice(0, 157)}...` : html;\n}\n\n/**\n * Icon-only buttons (an icon, no visible text) that miss an accessible name (`aria-label` /\n * `aria-labelledby`) or — unless `requireTooltip: false` — a tooltip (`title`). Returns one\n * message per offending button.\n */\nexport function findInaccessibleIconButtons(root: Root, options: IconButtonA11yOptions = {}): string[] {\n const requireTooltip = options.requireTooltip ?? true;\n const problems: string[] = [];\n for (const button of Array.from(rootElement(root).querySelectorAll(BUTTON_SELECTOR))) {\n if (options.ignore && button.closest(options.ignore)) continue;\n if (!options.includeKendoInternals && button.matches(KENDO_INTERNAL_SELECTOR)) continue;\n if (!button.querySelector(ICON_SELECTOR) || visibleText(button) !== '') continue;\n const missing: string[] = [];\n if (!accessibleName(button)) missing.push('aria-label');\n if (requireTooltip && !button.getAttribute('title')?.trim()) missing.push('title/tooltip');\n if (missing.length) {\n problems.push(`icon-only button without ${missing.join(' and ')}: ${describe(button)}`);\n }\n }\n return problems;\n}\n\n/**\n * Fails (throws) when the rendered fixture / element contains an icon-only button without an\n * accessible name and a tooltip (Studio action guideline §2.2, AB#5581). Runs `detectChanges()`\n * on a fixture first.\n *\n * ```ts\n * import { expectIconButtonsAccessible } from '@meshmakers/shared-ui/testing';\n *\n * it('names every icon-only button', () => {\n * expectIconButtonsAccessible(fixture);\n * });\n * ```\n */\nexport function expectIconButtonsAccessible(root: Root, options: IconButtonA11yOptions = {}): void {\n const problems = findInaccessibleIconButtons(root, options);\n if (problems.length) {\n throw new Error(`${problems.length} inaccessible icon-only button(s):\\n- ${problems.join('\\n- ')}`);\n }\n}\n","/*\n * Public API Surface of @meshmakers/shared-ui/testing (AB#5581): spec helpers, framework-agnostic\n * (they throw an Error instead of calling a test runner's expect).\n */\nexport * from './icon-button-a11y';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}