mirror of
https://github.com/BerriAI/litellm.git
synced 2025-04-25 18:54:30 +00:00
Litellm user daily activity allow non admin usage (#9695)
* feat(internal_user_endpoints.py): allow non-admin to view their own usage via `/user/daily/activity` route * fix(leftnav.tsx): allow users to view their own usage via new_usage.tsx allows internal users to see their usage via new api Handles 1m+ spend logs scenario * fix(leftnav.tsx): allow all users to see new usage tab
This commit is contained in:
parent
23051d89dd
commit
3d0313b15b
3 changed files with 68 additions and 46 deletions
|
@ -432,6 +432,7 @@ class LiteLLMRoutes(enum.Enum):
|
||||||
"/model/new",
|
"/model/new",
|
||||||
"/model/update",
|
"/model/update",
|
||||||
"/model/delete",
|
"/model/delete",
|
||||||
|
"/user/daily/activity",
|
||||||
] # routes that manage their own allowed/disallowed logic
|
] # routes that manage their own allowed/disallowed logic
|
||||||
|
|
||||||
## Org Admin Routes ##
|
## Org Admin Routes ##
|
||||||
|
|
|
@ -1480,6 +1480,14 @@ async def get_user_daily_activity(
|
||||||
if api_key:
|
if api_key:
|
||||||
where_conditions["api_key"] = api_key
|
where_conditions["api_key"] = api_key
|
||||||
|
|
||||||
|
if (
|
||||||
|
user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN
|
||||||
|
and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY
|
||||||
|
):
|
||||||
|
where_conditions[
|
||||||
|
"user_id"
|
||||||
|
] = user_api_key_dict.user_id # only allow access to own data
|
||||||
|
|
||||||
# Get total count for pagination
|
# Get total count for pagination
|
||||||
total_count = await prisma_client.db.litellm_dailyuserspend.count(
|
total_count = await prisma_client.db.litellm_dailyuserspend.count(
|
||||||
where=where_conditions
|
where=where_conditions
|
||||||
|
|
|
@ -23,7 +23,7 @@ import {
|
||||||
LockOutlined,
|
LockOutlined,
|
||||||
ToolOutlined,
|
ToolOutlined,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { old_admin_roles, v2_admin_role_names, all_admin_roles, rolesAllowedToSeeUsage, rolesWithWriteAccess } from '../utils/roles';
|
import { old_admin_roles, v2_admin_role_names, all_admin_roles, rolesAllowedToSeeUsage, rolesWithWriteAccess, internalUserRoles } from '../utils/roles';
|
||||||
|
|
||||||
const { Sider } = Layout;
|
const { Sider } = Layout;
|
||||||
|
|
||||||
|
@ -44,55 +44,55 @@ interface MenuItem {
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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", icon: <BlockOutlined />, roles: rolesWithWriteAccess },
|
|
||||||
{ key: "4", page: "usage", label: "Usage", icon: <BarChartOutlined /> },
|
|
||||||
{ 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: "16", page: "model-hub", label: "Model Hub", icon: <AppstoreOutlined /> },
|
|
||||||
{ key: "15", page: "logs", label: "Logs", icon: <LineChartOutlined />},
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
key: "experimental",
|
|
||||||
page: "experimental",
|
|
||||||
label: "Experimental",
|
|
||||||
icon: <ExperimentOutlined />,
|
|
||||||
roles: all_admin_roles,
|
|
||||||
children: [
|
|
||||||
{ key: "9", page: "caching", label: "Caching", icon: <DatabaseOutlined />, roles: all_admin_roles },
|
|
||||||
{ key: "10", page: "budgets", label: "Budgets", icon: <BankOutlined />, roles: all_admin_roles },
|
|
||||||
{ key: "11", page: "guardrails", label: "Guardrails", icon: <SafetyOutlined />, roles: all_admin_roles },
|
|
||||||
{ key: "12", page: "new_usage", label: "New Usage", icon: <BarChartOutlined />, roles: all_admin_roles },
|
|
||||||
{ key: "18", page: "mcp-tools", label: "MCP Tools", icon: <ToolOutlined />, roles: all_admin_roles },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "settings",
|
|
||||||
page: "settings",
|
|
||||||
label: "Settings",
|
|
||||||
icon: <SettingOutlined />,
|
|
||||||
roles: all_admin_roles,
|
|
||||||
children: [
|
|
||||||
{ key: "11", page: "general-settings", label: "Router Settings", icon: <SettingOutlined />, roles: all_admin_roles },
|
|
||||||
{ key: "12", page: "pass-through-settings", label: "Pass-Through", icon: <ApiOutlined />, 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 },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const Sidebar: React.FC<SidebarProps> = ({
|
const Sidebar: React.FC<SidebarProps> = ({
|
||||||
setPage,
|
setPage,
|
||||||
userRole,
|
userRole,
|
||||||
defaultSelectedKey,
|
defaultSelectedKey,
|
||||||
}) => {
|
}) => {
|
||||||
|
// 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", icon: <BlockOutlined />, roles: rolesWithWriteAccess },
|
||||||
|
{ key: "4", page: "usage", label: "Usage", icon: <BarChartOutlined /> },
|
||||||
|
{ 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: "16", page: "model-hub", label: "Model Hub", icon: <AppstoreOutlined /> },
|
||||||
|
{ key: "15", page: "logs", label: "Logs", icon: <LineChartOutlined />},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
key: "experimental",
|
||||||
|
page: "experimental",
|
||||||
|
label: "Experimental",
|
||||||
|
icon: <ExperimentOutlined />,
|
||||||
|
children: [
|
||||||
|
{ key: "9", page: "caching", label: "Caching", icon: <DatabaseOutlined />, roles: all_admin_roles },
|
||||||
|
{ key: "10", page: "budgets", label: "Budgets", icon: <BankOutlined />, roles: all_admin_roles },
|
||||||
|
{ key: "11", page: "guardrails", label: "Guardrails", icon: <SafetyOutlined />, roles: all_admin_roles },
|
||||||
|
{ key: "12", page: "new_usage", label: "New Usage", icon: <BarChartOutlined />, roles: [...all_admin_roles, ...internalUserRoles] },
|
||||||
|
{ key: "18", page: "mcp-tools", label: "MCP Tools", icon: <ToolOutlined />, roles: all_admin_roles },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "settings",
|
||||||
|
page: "settings",
|
||||||
|
label: "Settings",
|
||||||
|
icon: <SettingOutlined />,
|
||||||
|
roles: all_admin_roles,
|
||||||
|
children: [
|
||||||
|
{ key: "11", page: "general-settings", label: "Router Settings", icon: <SettingOutlined />, roles: all_admin_roles },
|
||||||
|
{ key: "12", page: "pass-through-settings", label: "Pass-Through", icon: <ApiOutlined />, 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 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
// Find the menu item that matches the default page, including in submenus
|
// Find the menu item that matches the default page, including in submenus
|
||||||
const findMenuItemKey = (page: string): string => {
|
const findMenuItemKey = (page: string): string => {
|
||||||
// Check top-level items
|
// Check top-level items
|
||||||
|
@ -111,9 +111,22 @@ const Sidebar: React.FC<SidebarProps> = ({
|
||||||
|
|
||||||
const selectedMenuKey = findMenuItemKey(defaultSelectedKey);
|
const selectedMenuKey = findMenuItemKey(defaultSelectedKey);
|
||||||
|
|
||||||
const filteredMenuItems = menuItems.filter(item =>
|
const filteredMenuItems = menuItems.filter(item => {
|
||||||
!item.roles || item.roles.includes(userRole)
|
// Check if parent item has roles and user has access
|
||||||
);
|
const hasParentAccess = !item.roles || item.roles.includes(userRole);
|
||||||
|
|
||||||
|
if (!hasParentAccess) return false;
|
||||||
|
|
||||||
|
// Filter children if they exist
|
||||||
|
if (item.children) {
|
||||||
|
item.children = item.children.filter(child =>
|
||||||
|
!child.roles || child.roles.includes(userRole)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout style={{ minHeight: "100vh" }}>
|
<Layout style={{ minHeight: "100vh" }}>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue