initial commit after split
This commit is contained in:
89
webui/src/platform/modules.ts
Normal file
89
webui/src/platform/modules.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
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";
|
||||
}
|
||||
Reference in New Issue
Block a user