93 lines
2.9 KiB
TypeScript
93 lines
2.9 KiB
TypeScript
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)
|
|
}
|
|
}
|