move the menu button to top nav+ change the icon size

This commit is contained in:
tanjiro
2025-08-30 01:34:30 +09:00
parent 539b94ad4e
commit 9682f76474
4 changed files with 101 additions and 115 deletions
+9 -1
View File
@@ -136,6 +136,11 @@ export default function CreateKeyPage() {
}
const [accessToken, setAccessToken] = useState<string | null>(null)
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
const toggleSidebar = () => {
setSidebarCollapsed(!sidebarCollapsed);
};
const addKey = (data: any) => {
setKeys((prevData) => (prevData ? [...prevData, data] : [data]))
@@ -248,14 +253,17 @@ export default function CreateKeyPage() {
proxySettings={proxySettings}
accessToken={accessToken}
isPublicPage={false}
sidebarCollapsed={sidebarCollapsed}
onToggleSidebar={toggleSidebar}
/>
<div className="flex flex-1 overflow-auto">
<div className="mt-8">
<div className="mt-2">
<Sidebar
accessToken={accessToken}
setPage={updatePage}
userRole={userRole}
defaultSelectedKey={page}
collapsed={sidebarCollapsed}
/>
</div>
+64 -105
View File
@@ -30,6 +30,7 @@ import {
} from '@ant-design/icons';
import { old_admin_roles, v2_admin_role_names, all_admin_roles, rolesAllowedToSeeUsage, rolesWithWriteAccess, internalUserRoles, isAdminRole } from '../utils/roles';
import UsageIndicator from './usage_indicator';
import { ConfigProvider } from 'antd';
const { Sider } = Layout;
// Define the props type
@@ -38,6 +39,7 @@ interface SidebarProps {
setPage: (page: string) => void;
userRole: string;
defaultSelectedKey: string;
collapsed?: boolean;
}
// Create a more comprehensive menu item configuration
@@ -57,65 +59,73 @@ const Sidebar: React.FC<SidebarProps> = ({
setPage,
userRole,
defaultSelectedKey,
collapsed = false,
}) => {
const [collapsed, setCollapsed] = useState(false);
const toggleCollapse = () => {
setCollapsed(!collapsed);
};
// Note: If a menu item does not have a role, it is visible to all roles.
const menuItems: MenuItem[] = [
{ key: "1", page: "api-keys", label: "Virtual Keys", icon: <KeyOutlined /> },
{ key: "3", page: "llm-playground", label: "Test Key", icon: <PlayCircleOutlined />, roles: rolesWithWriteAccess },
{ key: "2", page: "models", label: "Models + Endpoints", icon: <BlockOutlined />, roles: rolesWithWriteAccess },
{ key: "12", page: "new_usage", label: "Usage", icon: <BarChartOutlined />, roles: [...all_admin_roles, ...internalUserRoles] },
{ key: "6", page: "teams", label: "Teams", icon: <TeamOutlined /> },
{ key: "17", page: "organizations", label: "Organizations", icon: <BankOutlined />, roles: all_admin_roles },
{ key: "5", page: "users", label: "Internal Users", icon: <UserOutlined />, roles: all_admin_roles },
{ key: "14", page: "api_ref", label: "API Reference", icon: <ApiOutlined /> },
{
key: "1",
page: "api-keys",
label: "Virtual Keys",
icon: <KeyOutlined style={{ fontSize: '18px' }} />
},
{
key: "3",
page: "llm-playground",
label: "Test Key",
icon: <PlayCircleOutlined style={{ fontSize: '18px' }} />,
roles: rolesWithWriteAccess
},
{ key: "2", page: "models", label: "Models + Endpoints", icon: <BlockOutlined style={{ fontSize: '18px' }} />, roles: rolesWithWriteAccess },
{ key: "12", page: "new_usage", label: "Usage", icon: <BarChartOutlined style={{ fontSize: '18px' }} />, roles: [...all_admin_roles, ...internalUserRoles] },
{ key: "6", page: "teams", label: "Teams", icon: <TeamOutlined style={{ fontSize: '18px' }} /> },
{ key: "17", page: "organizations", label: "Organizations", icon: <BankOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "5", page: "users", label: "Internal Users", icon: <UserOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "14", page: "api_ref", label: "API Reference", icon: <ApiOutlined style={{ fontSize: '18px' }} /> },
{
key: "16",
page: "model-hub-table",
label: "Model Hub",
icon: <AppstoreOutlined />
icon: <AppstoreOutlined style={{ fontSize: '18px' }} />
},
{ key: "15", page: "logs", label: "Logs", icon: <LineChartOutlined />},
{ key: "11", page: "guardrails", label: "Guardrails", icon: <SafetyOutlined />, roles: all_admin_roles },
{ key: "15", page: "logs", label: "Logs", icon: <LineChartOutlined style={{ fontSize: '18px' }} />},
{ key: "11", page: "guardrails", label: "Guardrails", icon: <SafetyOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{
key: "26",
page: "tools",
label: "Tools",
icon: <ToolOutlined />,
icon: <ToolOutlined style={{ fontSize: '18px' }} />,
children: [
{ key: "18", page: "mcp-servers", label: "MCP Servers", icon: <ToolOutlined /> },
{ key: "21", page: "vector-stores", label: "Vector Stores", icon: <DatabaseOutlined />, roles: all_admin_roles },
{ key: "18", page: "mcp-servers", label: "MCP Servers", icon: <ToolOutlined style={{ fontSize: '18px' }} /> },
{ key: "21", page: "vector-stores", label: "Vector Stores", icon: <DatabaseOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
]
},
{
key: "experimental",
page: "experimental",
label: "Experimental",
icon: <ExperimentOutlined />,
icon: <ExperimentOutlined style={{ fontSize: '18px' }} />,
children: [
{ key: "9", page: "caching", label: "Caching", icon: <DatabaseOutlined />, roles: all_admin_roles },
{ key: "25", page: "prompts", label: "Prompts", icon: <FileTextOutlined />, roles: all_admin_roles },
{ key: "10", page: "budgets", label: "Budgets", icon: <BankOutlined />, roles: all_admin_roles },
{ key: "20", page: "transform-request", label: "API Playground", icon: <ApiOutlined />, roles: [...all_admin_roles, ...internalUserRoles] },
{ key: "19", page: "tag-management", label: "Tag Management", icon: <TagsOutlined />, roles: all_admin_roles },
{ key: "4", page: "usage", label: "Old Usage", icon: <BarChartOutlined /> },
{ key: "9", page: "caching", label: "Caching", icon: <DatabaseOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "25", page: "prompts", label: "Prompts", icon: <FileTextOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "10", page: "budgets", label: "Budgets", icon: <BankOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "20", page: "transform-request", label: "API Playground", icon: <ApiOutlined style={{ fontSize: '18px' }} />, roles: [...all_admin_roles, ...internalUserRoles] },
{ key: "19", page: "tag-management", label: "Tag Management", icon: <TagsOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "4", page: "usage", label: "Old Usage", icon: <BarChartOutlined style={{ fontSize: '18px' }} /> },
]
},
{
key: "settings",
page: "settings",
label: "Settings",
icon: <SettingOutlined />,
icon: <SettingOutlined style={{ fontSize: '18px' }} />,
roles: all_admin_roles,
children: [
{ key: "11", page: "general-settings", label: "Router Settings", icon: <SettingOutlined />, roles: all_admin_roles },
{ key: "8", page: "settings", label: "Logging & Alerts", icon: <SettingOutlined />, roles: all_admin_roles },
{ key: "13", page: "admin-panel", label: "Admin Settings", icon: <SettingOutlined />, roles: all_admin_roles },
{ key: "14", page: "ui-theme", label: "UI Theme", icon: <BgColorsOutlined />, roles: all_admin_roles },
{ key: "11", page: "general-settings", label: "Router Settings", icon: <SettingOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "8", page: "settings", label: "Logging & Alerts", icon: <SettingOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "13", page: "admin-panel", label: "Admin Settings", icon: <SettingOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
{ key: "14", page: "ui-theme", label: "UI Theme", icon: <BgColorsOutlined style={{ fontSize: '18px' }} />, roles: all_admin_roles },
]
}
];
@@ -166,83 +176,32 @@ const Sidebar: React.FC<SidebarProps> = ({
collapsible
trigger={null}
style={{
transition: 'all 0.2s',
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)', // Material Design easing
position: 'relative',
}}
>
<Menu
mode="inline"
selectedKeys={[selectedMenuKey]}
defaultOpenKeys={collapsed ? [] : ["llm-tools"]}
inlineCollapsed={collapsed}
style={{
borderRight: 0,
backgroundColor: 'transparent',
fontSize: '14px',
}}
items={[
// Expand button row when collapsed, or first menu item when expanded
collapsed ? {
key: 'expand-toggle',
icon: <MenuUnfoldOutlined />,
label: '',
onClick: toggleCollapse,
style: {
cursor: 'pointer',
<ConfigProvider
theme={{
components: {
Menu: {
iconSize: 18,
fontSize: 14,
},
title: "Expand navigation sidebar"
} : {
key: filteredMenuItems[0]?.key,
icon: filteredMenuItems[0]?.icon,
label: (
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%'
}}>
<span>{filteredMenuItems[0]?.label}</span>
<div
onClick={(e) => {
e.stopPropagation();
toggleCollapse();
}}
style={{
cursor: 'pointer',
padding: '8px 12px',
borderRadius: '4px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '12px',
color: '#888',
transition: 'all 0.2s',
marginLeft: '8px',
marginRight: '-8px',
}}
onMouseEnter={(e) => {
e.currentTarget.style.background = 'rgba(0, 0, 0, 0.04)';
e.currentTarget.style.color = '#666';
}}
onMouseLeave={(e) => {
e.currentTarget.style.background = 'transparent';
e.currentTarget.style.color = '#888';
}}
title="Collapse navigation sidebar"
>
<MenuFoldOutlined />
</div>
</div>
),
onClick: !filteredMenuItems[0]?.children ? () => {
const newSearchParams = new URLSearchParams(window.location.search);
newSearchParams.set('page', filteredMenuItems[0]?.page || '');
window.history.pushState(null, '', `?${newSearchParams.toString()}`);
setPage(filteredMenuItems[0]?.page || '');
} : undefined
},
// Rest of the menu items (or all items when collapsed)
...(collapsed ? filteredMenuItems : filteredMenuItems.slice(1)).map(item => ({
}}
>
<Menu
mode="inline"
selectedKeys={[selectedMenuKey]}
defaultOpenKeys={collapsed ? [] : ["llm-tools"]}
inlineCollapsed={collapsed}
className="custom-sidebar-menu"
style={{
borderRight: 0,
backgroundColor: 'transparent',
fontSize: '14px',
}}
items={filteredMenuItems.map(item => ({
key: item.key,
icon: item.icon,
label: item.label,
@@ -263,9 +222,9 @@ const Sidebar: React.FC<SidebarProps> = ({
window.history.pushState(null, '', `?${newSearchParams.toString()}`);
setPage(item.page);
} : undefined
}))
]}
/>
}))}
/>
</ConfigProvider>
{
isAdminRole(userRole) && !collapsed && (
<UsageIndicator accessToken={accessToken} width={220}/>
+27 -8
View File
@@ -11,7 +11,9 @@ import {
BgColorsOutlined,
CrownOutlined,
MailOutlined,
SafetyOutlined
SafetyOutlined,
MenuFoldOutlined,
MenuUnfoldOutlined,
} from '@ant-design/icons'
import { clearTokenCookies } from "@/utils/cookieUtils"
import { fetchProxySettings } from "@/utils/proxyUtils"
@@ -23,10 +25,12 @@ interface NavbarProps {
userEmail: string | null;
userRole: string | null;
premiumUser: boolean;
setProxySettings: React.Dispatch<React.SetStateAction<any>>;
proxySettings: any;
setProxySettings: React.Dispatch<React.SetStateAction<any>>;
accessToken: string | null;
isPublicPage: boolean;
sidebarCollapsed?: boolean;
onToggleSidebar?: () => void;
}
const Navbar: React.FC<NavbarProps> = ({
@@ -38,6 +42,8 @@ const Navbar: React.FC<NavbarProps> = ({
setProxySettings,
accessToken,
isPublicPage = false,
sidebarCollapsed = false,
onToggleSidebar,
}) => {
const baseUrl = getProxyBaseUrl();
const [logoutUrl, setLogoutUrl] = useState("");
@@ -128,14 +134,27 @@ const Navbar: React.FC<NavbarProps> = ({
return (
<nav className="bg-white border-b border-gray-200 sticky top-0 z-10">
<div className="w-full">
<div className="flex items-center h-12 px-4">
{/* Left side with correct logo positioning */}
<div className="flex items-center h-14 px-4"> {/* Increased height from h-12 to h-14 */}
{/* Left side with collapse toggle and logo */}
<div className="flex items-center flex-shrink-0">
{/* Collapse/Expand Toggle Button - Larger */}
{onToggleSidebar && (
<button
onClick={onToggleSidebar}
className="flex items-center justify-center w-10 h-10 mr-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded transition-colors"
title={sidebarCollapsed ? "Expand sidebar" : "Collapse sidebar"}
>
<span className="text-lg">
{sidebarCollapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
</span>
</button>
)}
<Link href="/" className="flex items-center">
<img
src={imageUrl}
alt="LiteLLM Brand"
className="h-8 w-auto"
className="h-10 w-auto"
/>
</Link>
</div>
@@ -146,7 +165,7 @@ const Navbar: React.FC<NavbarProps> = ({
href="https://docs.litellm.ai/docs/"
target="_blank"
rel="noopener noreferrer"
className="text-[13px] text-gray-600 hover:text-gray-900 transition-colors"
className="text-sm text-gray-600 hover:text-gray-900 transition-colors"
>
Docs
</a>
@@ -167,10 +186,10 @@ const Navbar: React.FC<NavbarProps> = ({
minWidth: '200px'
}}
>
<button className="inline-flex items-center text-[13px] text-gray-600 hover:text-gray-900 transition-colors">
<button className="inline-flex items-center text-sm text-gray-600 hover:text-gray-900 transition-colors">
User
<svg
className="ml-1 w-4 h-4 text-gray-500"
className="ml-1 w-5 h-5 text-gray-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
@@ -354,7 +354,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
console.log("All cookies after redirect:", document.cookie)
return (
<div className="w-full mx-4 h-[75vh]">
<Grid numItems={1} className="gap-2 p-8 w-full mt-2">
<Grid numItems={1} className="gap-2 p-2 w-full mt-2">
<Col numColSpan={1} className="flex flex-col gap-2">
<CreateKey
key={selectedTeam ? selectedTeam.team_id : null}