90 lines
3.6 KiB
TypeScript
90 lines
3.6 KiB
TypeScript
import { Activity, FileText, Folder, Form, LayoutDashboard, MailCheck, Users, type LucideIcon } from "lucide-react";
|
|
import campaignModule from "@govoplan/campaign-webui";
|
|
import filesModule from "@govoplan/files-webui";
|
|
import mailModule from "@govoplan/mail-webui";
|
|
import type { AuthInfo, PlatformModuleInfo, PlatformNavItem, PlatformWebModule } from "../types";
|
|
import { adminReadScopes, hasAnyScope, hasScope } from "../utils/permissions";
|
|
|
|
export const shellNavItems: PlatformNavItem[] = [
|
|
{ to: "/dashboard", label: "Dashboard", icon: LayoutDashboard, order: 10 }
|
|
];
|
|
|
|
const legacyModules: PlatformWebModule[] = [campaignModule, filesModule, mailModule];
|
|
|
|
const iconByName: Record<string, LucideIcon> = {
|
|
activity: Activity,
|
|
campaign: MailCheck,
|
|
file: Folder,
|
|
files: Folder,
|
|
folder: Folder,
|
|
form: Form,
|
|
mail: MailCheck,
|
|
reports: FileText,
|
|
users: Users
|
|
};
|
|
|
|
function navFromMetadata(item: PlatformModuleInfo["nav"][number]): PlatformNavItem {
|
|
return {
|
|
to: item.path,
|
|
label: item.label,
|
|
icon: item.icon ? iconByName[item.icon] : undefined,
|
|
allOf: item.required_all,
|
|
anyOf: item.required_any,
|
|
order: item.order
|
|
};
|
|
}
|
|
|
|
function applyServerMetadata(module: PlatformWebModule, info: PlatformModuleInfo): PlatformWebModule {
|
|
const backendNav = info.frontend?.nav.length ? info.frontend.nav : info.nav;
|
|
return {
|
|
...module,
|
|
label: info.name,
|
|
version: info.version,
|
|
dependencies: info.dependencies,
|
|
optionalDependencies: info.optional_dependencies,
|
|
navItems: backendNav.length ? backendNav.map(navFromMetadata) : module.navItems
|
|
};
|
|
}
|
|
|
|
export function resolveInstalledWebModules(platformModules: PlatformModuleInfo[] | null | undefined): PlatformWebModule[] {
|
|
if (!platformModules?.length) return legacyModules;
|
|
|
|
const localById = new Map(legacyModules.map((module) => [module.id, module]));
|
|
return platformModules
|
|
.filter((module) => module.enabled)
|
|
.map((module) => {
|
|
const local = localById.get(module.id);
|
|
return local ? applyServerMetadata(local, module) : null;
|
|
})
|
|
.filter((module): module is PlatformWebModule => module !== null);
|
|
}
|
|
|
|
export function moduleInstalled(moduleId: string, modules: PlatformWebModule[] = legacyModules): boolean {
|
|
return modules.some((module) => module.id === moduleId);
|
|
}
|
|
|
|
export function moduleIntegrationEnabled(moduleId: string, dependencyId: string, modules: PlatformWebModule[] = legacyModules): boolean {
|
|
const module = modules.find((item) => item.id === moduleId);
|
|
if (!module) return false;
|
|
return Boolean(module.dependencies?.includes(dependencyId) || (module.optionalDependencies?.includes(dependencyId) && moduleInstalled(dependencyId, modules)));
|
|
}
|
|
|
|
export function navItemsForModules(modules: PlatformWebModule[]): PlatformNavItem[] {
|
|
return [...shellNavItems, ...modules.flatMap((module) => module.navItems ?? [])].sort((left, right) => (left.order ?? 100) - (right.order ?? 100));
|
|
}
|
|
|
|
export function visibleNavItems(auth: AuthInfo | null | undefined, modules: PlatformWebModule[] = legacyModules): PlatformNavItem[] {
|
|
return navItemsForModules(modules).filter((item) => {
|
|
if (item.allOf?.length && !item.allOf.every((scope) => hasScope(auth, scope))) return false;
|
|
if (item.anyOf?.length && !hasAnyScope(auth, item.anyOf)) return false;
|
|
return true;
|
|
});
|
|
}
|
|
|
|
export function firstAccessibleRoute(auth: AuthInfo, modules: PlatformWebModule[] = legacyModules): string {
|
|
const preferred = visibleNavItems(auth, modules).find((item) => item.to !== "/dashboard");
|
|
if (preferred) return preferred.to;
|
|
if (hasAnyScope(auth, adminReadScopes)) return "/admin";
|
|
return "/dashboard";
|
|
}
|