navigations.js
1 import { authRoles } from "app/auth/authRoles"; 2 import { usePlatformCapabilities } from "app/contexts/PlatformContext"; 3 import { useTranslation } from "react-i18next"; 4 5 // Default navigations without conditional items 6 // Internal: the static nav tree. `nameKey`/`labelKey` are i18n keys; the 7 // `name`/`label` fallbacks are used when i18n is not yet initialized or 8 // a key is missing. `useNavigations()` below resolves the keys. 9 export const defaultNavigations = [ 10 { name: "Home", nameKey: "nav.home", path: "/home", icon: "dashboard" }, 11 { 12 name: "Library", nameKey: "nav.library", 13 icon: "library_books", 14 path: "/projects/library", 15 }, 16 { label: "AIaaS", type: "label" }, 17 { 18 name: "Projects", nameKey: "nav.projects", 19 icon: "assignment", 20 path: "/projects", 21 }, 22 { 23 name: "Teams", nameKey: "nav.teams", 24 icon: "groups", 25 path: "/teams", 26 }, 27 { 28 name: "Users", nameKey: "nav.users", 29 icon: "person", 30 path: "/users", 31 auth: authRoles.admin, 32 }, 33 { label: "AI", type: "label" }, 34 { 35 name: "LLMs", nameKey: "nav.llms", 36 icon: "psychology", 37 path: "/llms", 38 }, 39 { 40 name: "Embeddings", nameKey: "nav.embeddings", 41 icon: "psychology", 42 path: "/embeddings", 43 }, 44 { 45 name: "Tools", nameKey: "nav.tools", 46 icon: "build", 47 path: "/projects/tools", 48 }, 49 { 50 name: "Classifiers", nameKey: "nav.classifiers", 51 icon: "category", 52 path: "/classifier", 53 }, 54 { 55 name: "Direct Access", nameKey: "nav.directAccess", 56 icon: "api", 57 path: "/direct", 58 }, 59 { 60 name: "Generators", nameKey: "nav.generators", 61 icon: "memory", 62 children: [ 63 { name: "Image Generators", nameKey: "nav.imageGenerators", iconText: "IG", path: "/generators/image" }, 64 { name: "Speech-to-Text", nameKey: "nav.speechToText", iconText: "ST", path: "/generators/speech2text" }, 65 { name: "GPU", nameKey: "nav.gpu", iconText: "GP", path: "/gpu", auth: authRoles.admin }, 66 ] 67 }, 68 { label: "Admin", labelKey: "nav.adminLabel", type: "label", auth: authRoles.teamAdmin }, 69 { 70 name: "Settings", nameKey: "nav.settings", 71 icon: "settings", 72 path: "/settings", 73 auth: authRoles.admin, 74 }, 75 { 76 name: "Audit Log", nameKey: "nav.auditLog", 77 icon: "history", 78 path: "/audit", 79 auth: authRoles.admin, 80 }, 81 { 82 name: "Cron Logs", nameKey: "nav.cronLogs", 83 icon: "schedule", 84 path: "/admin/cron-logs", 85 auth: authRoles.admin, 86 }, 87 { 88 name: "Permissions", nameKey: "nav.permissionMatrix", 89 icon: "lock", 90 path: "/admin/permissions", 91 auth: authRoles.teamAdmin, 92 }, 93 { label: "Docs", labelKey: "nav.docsLabel", type: "label" }, 94 { 95 name: "Swagger", nameKey: "nav.swagger", 96 icon: "launch", 97 type: "extLink", 98 path: "/docs/" 99 } 100 ]; 101 102 // Pure function to build navigation structure based on gpu capability 103 // This doesn't use any hooks 104 export const buildNavigations = (hasGpu, hasProxy) => { 105 const navigations = [...defaultNavigations.map(item => { 106 // Deep clone the Generators item so we can modify its children 107 if (item.name === "Generators") { 108 return { ...item, children: [...item.children] }; 109 } 110 return item; 111 })]; 112 113 // The Image Gen and Audio Gen playgrounds are reachable from the 114 // Image Generators / Speech-to-Text pages themselves (Playground 115 // button), so they don't need dedicated nav entries. 116 117 // Show AI Proxy after Tools when proxy is enabled 118 if (hasProxy) { 119 const toolsIndex = navigations.findIndex(item => item.path === "/projects/tools"); 120 navigations.splice(toolsIndex + 1, 0, { 121 name: "AI Proxy", nameKey: "nav.aiProxy", 122 icon: "route", 123 path: "/proxy/keys", 124 auth: authRoles.admin, 125 }); 126 } 127 128 return navigations; 129 }; 130 131 // Walks the nav tree and swaps each `name`/`label` with its translated 132 // counterpart. Keeps other fields untouched so downstream renderers 133 // that read `item.icon`, `item.path`, etc. still work. 134 const translateNav = (items, t) => 135 items.map((item) => { 136 const out = { ...item }; 137 if (item.nameKey) out.name = t(item.nameKey, item.name); 138 if (item.labelKey) out.label = t(item.labelKey, item.label); 139 if (item.children) out.children = translateNav(item.children, t); 140 return out; 141 }); 142 143 // Custom React hook that follows the rules of hooks 144 export const useNavigations = () => { 145 const { platformCapabilities } = usePlatformCapabilities(); 146 const { t } = useTranslation(); 147 const hasGpu = platformCapabilities?.gpu ?? false; 148 const hasProxy = platformCapabilities?.proxy ?? false; 149 return translateNav(buildNavigations(hasGpu, hasProxy), t); 150 }; 151 152 // For compatibility with direct imports (non-component files) 153 // This will not have dynamic GPU features but prevents errors 154 export const navigations = defaultNavigations;