import { clientModuleRegistry } from '../modules/registry.ts' import type { ClientModuleManifest } from '../modules/types.ts' import { getNavigationLeaves, isNavigationGroup, type ClientNavigationGroup, type ClientNavigationLeaf, type ClientNavigationNode, } from './tree.ts' export { getNavigationLeaves, type ClientNavigationGroup, type ClientNavigationLeaf, type ClientNavigationNode, } from './tree.ts' function buildModuleNavigation(module: ClientModuleManifest): ClientNavigationNode[] { const leaves: ClientNavigationLeaf[] = [] for (const route of module.routes) { if (route.release !== 'active' || !route.navigation) continue leaves.push({ key: route.navigation.key, title: route.navigation.title ?? route.meta.title, icon: route.navigation.icon, path: route.path ? `/${route.path}` : '/', permission: route.meta.permission, }) } if (!module.navigationGroup) return leaves if (leaves.length === 0) return [] return [{ key: module.key, title: module.navigationGroup.title, icon: module.navigationGroup.icon, dividerBefore: module.navigationGroup.dividerBefore, children: leaves as [ClientNavigationNode, ...ClientNavigationNode[]], }] } export const clientNavigation: ClientNavigationNode[] = clientModuleRegistry.flatMap(buildModuleNavigation) export function filterNavigationByPermissions( nodes: readonly ClientNavigationNode[], permissions: readonly string[], ): ClientNavigationNode[] { const allowed = new Set(permissions) const result: ClientNavigationNode[] = [] for (const node of nodes) { if (node.hidden) continue if (!isNavigationGroup(node)) { if (allowed.has(node.permission)) result.push(node) continue } const children = filterNavigationByPermissions(node.children, permissions) if (children.length > 0) result.push({ ...node, children: children as [ClientNavigationNode, ...ClientNavigationNode[]] }) } return result } export function getFirstAccessiblePath(permissions: readonly string[]) { return getNavigationLeaves(filterNavigationByPermissions(clientNavigation, permissions))[0]?.path ?? '/forbidden' } function findNavigationParentKeys( nodes: readonly ClientNavigationNode[], path: string, parentKeys: readonly string[], ): string[] | undefined { for (const node of nodes) { if (isNavigationGroup(node)) { const result = findNavigationParentKeys(node.children, path, [...parentKeys, node.key]) if (result) return result } else if (node.path === path) { return [...parentKeys] } } } export function getNavigationParentKeys(nodes: readonly ClientNavigationNode[], path: string): string[] { return findNavigationParentKeys(nodes, path, []) ?? [] } export function openNavigationParentKeys( path: string, nodes: readonly ClientNavigationNode[], open: (key: string) => void, ) { for (const key of getNavigationParentKeys(nodes, path)) { open(key) } }