Files
ai-agent/web/lib/navigation.tsx
T

302 lines
7.7 KiB
TypeScript
Raw Normal View History

2026-04-09 10:01:23 +08:00
import {
ActivitySquareIcon,
BotMessageSquareIcon,
BrainCircuitIcon,
Building2Icon,
CalendarClockIcon,
FileTextIcon,
GlobeIcon,
KeyRoundIcon,
LayoutDashboardIcon,
MessageSquareCodeIcon,
MessageSquareMoreIcon,
ShieldCheckIcon,
TagsIcon,
UserCogIcon,
UsersIcon,
} from "lucide-react";
import type { ReactNode } from "react";
2026-05-25 12:06:15 +08:00
/** Keep in sync with backend internal/pkg/constants/auth.go RoleCodeSuperAdmin. */
2026-04-09 10:01:23 +08:00
export const DASHBOARD_ROLE_SUPER_ADMIN = "super_admin";
export type DashboardNavMenuItem = {
title: string;
2026-05-25 12:06:15 +08:00
titleKey: string;
2026-04-09 10:01:23 +08:00
url: string;
icon: ReactNode;
};
2026-05-25 12:06:15 +08:00
export type DashboardNavItemConfig = Omit<DashboardNavMenuItem, "title"> & {
2026-04-09 10:01:23 +08:00
/**
2026-05-25 12:06:15 +08:00
* Keep in sync with backend Permission.Code. Missing value means any signed-in
* admin can see the module.
2026-04-09 10:01:23 +08:00
*/
requiredPermission?: string;
};
export type DashboardNavSectionConfig = {
2026-05-25 12:06:15 +08:00
titleKey: string;
icon: ReactNode;
2026-04-09 10:01:23 +08:00
items: DashboardNavItemConfig[];
};
function navItemVisible(
item: DashboardNavItemConfig,
superAdmin: boolean,
permissionSet: Set<string>,
): boolean {
if (superAdmin) {
return true;
}
if (!item.requiredPermission) {
return true;
}
return permissionSet.has(item.requiredPermission);
}
export function filterDashboardNavForSession(
permissions: readonly string[] | undefined,
roles: readonly string[] | undefined,
): { titleKey: string; icon: ReactNode; items: DashboardNavMenuItem[] }[] {
2026-04-09 10:01:23 +08:00
const superAdmin = roles?.includes(DASHBOARD_ROLE_SUPER_ADMIN) ?? false;
const permissionSet = new Set(permissions ?? []);
return dashboardNavSections
.map((section) => ({
2026-05-25 12:06:15 +08:00
titleKey: section.titleKey,
icon: section.icon,
2026-04-09 10:01:23 +08:00
items: section.items
.filter((item) => navItemVisible(item, superAdmin, permissionSet))
2026-05-25 12:06:15 +08:00
.map(({ titleKey, url, icon }) => ({ title: titleKey, titleKey, url, icon })),
2026-04-09 10:01:23 +08:00
}))
.filter((section) => section.items.length > 0);
}
export function filterDashboardSecondaryNavForSession(
permissions: readonly string[] | undefined,
roles: readonly string[] | undefined,
): DashboardNavMenuItem[] {
const superAdmin = roles?.includes(DASHBOARD_ROLE_SUPER_ADMIN) ?? false;
const permissionSet = new Set(permissions ?? []);
return dashboardSecondaryNav
.filter((item) => navItemVisible(item, superAdmin, permissionSet))
2026-05-25 12:06:15 +08:00
.map(({ titleKey, url, icon }) => ({ title: titleKey, titleKey, url, icon }));
2026-04-09 10:01:23 +08:00
}
export const dashboardNavSections: DashboardNavSectionConfig[] = [
// {
2026-05-25 12:06:15 +08:00
// title: "Overview",
2026-04-09 10:01:23 +08:00
// items: [
// {
2026-05-25 12:06:15 +08:00
// title: "Overview",
2026-04-09 10:01:23 +08:00
// url: "/",
// icon: <LayoutDashboardIcon />,
// },
// ],
// },
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.receptionCenter",
icon: <BotMessageSquareIcon />,
2026-04-09 10:01:23 +08:00
items: [
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.overview",
2026-04-24 11:27:49 +08:00
url: "/dashboard",
2026-04-09 10:01:23 +08:00
icon: <LayoutDashboardIcon />,
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.conversations",
2026-04-24 11:27:49 +08:00
url: "/dashboard/conversations",
2026-04-09 10:01:23 +08:00
icon: <BotMessageSquareIcon />,
requiredPermission: "conversation.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.tickets",
2026-04-24 11:27:49 +08:00
url: "/dashboard/tickets",
2026-04-09 10:01:23 +08:00
icon: <FileTextIcon />,
requiredPermission: "ticket.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.conversationMonitor",
2026-04-24 11:27:49 +08:00
url: "/dashboard/conversation-monitor",
2026-04-09 10:01:23 +08:00
icon: <BotMessageSquareIcon />,
requiredPermission: "conversation.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.customers",
2026-04-24 11:27:49 +08:00
url: "/dashboard/customers",
2026-04-09 10:01:23 +08:00
icon: <UsersIcon />,
requiredPermission: "customer.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.companies",
2026-04-24 11:27:49 +08:00
url: "/dashboard/companies",
2026-04-09 10:01:23 +08:00
icon: <Building2Icon />,
requiredPermission: "company.view",
},
],
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.agentConfig",
icon: <UserCogIcon />,
2026-04-09 10:01:23 +08:00
items: [
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.tags",
2026-04-24 11:27:49 +08:00
url: "/dashboard/tags",
2026-04-09 10:01:23 +08:00
icon: <TagsIcon />,
requiredPermission: "tag.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.quickReplies",
2026-04-24 11:27:49 +08:00
url: "/dashboard/quick-replies",
2026-04-09 10:01:23 +08:00
icon: <MessageSquareMoreIcon />,
requiredPermission: "quickReply.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.agents",
2026-04-24 11:27:49 +08:00
url: "/dashboard/agents",
2026-04-09 10:01:23 +08:00
icon: <UserCogIcon />,
requiredPermission: "agent.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.agentTeamSchedules",
2026-04-24 11:27:49 +08:00
url: "/dashboard/agent-team-schedules",
2026-04-09 10:01:23 +08:00
icon: <CalendarClockIcon />,
requiredPermission: "agentTeamSchedule.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.channels",
2026-04-24 11:27:49 +08:00
url: "/dashboard/channels",
2026-04-09 10:01:23 +08:00
icon: <GlobeIcon />,
requiredPermission: "channel.view",
2026-04-09 10:01:23 +08:00
},
],
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.aiCapabilities",
icon: <BrainCircuitIcon />,
2026-04-09 10:01:23 +08:00
items: [
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.knowledge",
2026-04-24 11:27:49 +08:00
url: "/dashboard/knowledge",
2026-04-09 10:01:23 +08:00
icon: <FileTextIcon />,
requiredPermission: "knowledgeBase.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.aiConfigs",
2026-04-24 11:27:49 +08:00
url: "/dashboard/ai-configs",
2026-04-09 10:01:23 +08:00
icon: <BrainCircuitIcon />,
requiredPermission: "aiConfig.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.aiAgents",
2026-04-24 11:27:49 +08:00
url: "/dashboard/ai-agents",
2026-04-09 10:01:23 +08:00
icon: <MessageSquareMoreIcon />,
requiredPermission: "aiAgent.view",
2026-04-09 10:01:23 +08:00
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.skillDefinition",
2026-04-24 11:27:49 +08:00
url: "/dashboard/skill-definition",
2026-04-09 10:01:23 +08:00
icon: <MessageSquareCodeIcon />,
requiredPermission: "skillDefinition.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.mcp",
2026-04-24 11:27:49 +08:00
url: "/dashboard/mcp",
2026-04-09 10:01:23 +08:00
icon: <MessageSquareCodeIcon />,
requiredPermission: "mcp.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.agentRunLogs",
2026-04-24 11:27:49 +08:00
url: "/dashboard/agent-run-logs",
2026-04-09 10:01:23 +08:00
icon: <ActivitySquareIcon />,
requiredPermission: "conversation.view",
},
],
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.system",
icon: <ShieldCheckIcon />,
2026-04-09 10:01:23 +08:00
items: [
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.users",
2026-04-24 11:27:49 +08:00
url: "/dashboard/users",
2026-04-09 10:01:23 +08:00
icon: <UsersIcon />,
requiredPermission: "user.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.roles",
2026-04-24 11:27:49 +08:00
url: "/dashboard/roles",
2026-04-09 10:01:23 +08:00
icon: <ShieldCheckIcon />,
requiredPermission: "role.view",
},
{
2026-05-25 12:06:15 +08:00
titleKey: "nav.permissions",
2026-04-24 11:27:49 +08:00
url: "/dashboard/permissions",
2026-04-09 10:01:23 +08:00
icon: <KeyRoundIcon />,
requiredPermission: "permission.view",
},
],
},
];
export const dashboardSecondaryNav: DashboardNavItemConfig[] = [
// {
2026-05-25 12:06:15 +08:00
// title: "System Settings",
2026-04-09 10:01:23 +08:00
// url: "/settings",
// icon: <Settings2Icon />,
// },
// {
2026-05-25 12:06:15 +08:00
// title: "Help Center",
2026-04-09 10:01:23 +08:00
// url: "/help",
// icon: <LifeBuoyIcon />,
// },
];
export const dashboardQuickActions = [
{
2026-05-25 12:06:15 +08:00
title: "View Conversations",
2026-04-09 10:01:23 +08:00
icon: <BotMessageSquareIcon />,
},
{
2026-05-25 12:06:15 +08:00
title: "Invite Members",
2026-04-09 10:01:23 +08:00
icon: <UserCogIcon />,
},
{
2026-05-25 12:06:15 +08:00
title: "Connect Bot",
2026-04-09 10:01:23 +08:00
icon: <MessageSquareCodeIcon />,
},
] as const;
export function getPageTitle(pathname: string): string {
2026-05-25 12:06:15 +08:00
return getPageTitleKey(pathname);
}
export function getPageTitleKey(pathname: string): string {
let matchedTitle = "nav.dashboardHome";
2026-04-09 10:01:23 +08:00
let longestMatch = 0;
for (const section of dashboardNavSections) {
for (const item of section.items) {
if (pathname === item.url || pathname.startsWith(item.url + "/")) {
const matchLength = item.url.length;
if (matchLength > longestMatch) {
longestMatch = matchLength;
2026-05-25 12:06:15 +08:00
matchedTitle = item.titleKey;
2026-04-09 10:01:23 +08:00
}
}
}
}
for (const item of dashboardSecondaryNav) {
if (pathname === item.url || pathname.startsWith(item.url + "/")) {
const matchLength = item.url.length;
if (matchLength > longestMatch) {
longestMatch = matchLength;
2026-05-25 12:06:15 +08:00
matchedTitle = item.titleKey;
2026-04-09 10:01:23 +08:00
}
}
}
return matchedTitle;
}