Files
client-web/src/navigation/clientNavigation.ts
T

93 lines
2.9 KiB
TypeScript
Raw Normal View History

2026-08-03 18:52:30 +08:00
import { clientModuleRegistry } from '../modules/registry.ts'
import type { ClientModuleManifest } from '../modules/types.ts'
2026-07-30 17:59:42 +08:00
import {
2026-08-03 18:52:30 +08:00
getNavigationLeaves,
isNavigationGroup,
type ClientNavigationGroup,
type ClientNavigationLeaf,
type ClientNavigationNode,
} from './tree.ts'
2026-07-30 17:59:42 +08:00
2026-08-03 18:52:30 +08:00
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[]],
}]
2026-07-30 17:59:42 +08:00
}
2026-08-03 18:52:30 +08:00
export const clientNavigation: ClientNavigationNode[] = clientModuleRegistry.flatMap(buildModuleNavigation)
2026-07-30 17:59:42 +08:00
export function filterNavigationByPermissions(
nodes: readonly ClientNavigationNode[],
permissions: readonly string[],
): ClientNavigationNode[] {
const allowed = new Set(permissions)
const result: ClientNavigationNode[] = []
for (const node of nodes) {
2026-08-03 11:44:50 +08:00
if (node.hidden) continue
2026-07-30 17:59:42 +08:00
if (!isNavigationGroup(node)) {
2026-08-03 12:02:15 +08:00
if (allowed.has(node.permission)) result.push(node)
2026-07-30 17:59:42 +08:00
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[]) {
2026-08-03 12:02:15 +08:00
return getNavigationLeaves(filterNavigationByPermissions(clientNavigation, permissions))[0]?.path ?? '/forbidden'
2026-07-30 17:59:42 +08:00
}
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)
}
}