[ Proxy - User Management]: If user assigned to a team don't show Default Team (#5791)

* rename endpoint to ui_settings

* ui allow DEFAULT_TEAM_DISABLED

* fix logic

* docs Set `default_team_disabled: true` on your litellm config.yaml
This commit is contained in:
Ishaan Jaff 2024-09-19 17:13:58 -07:00 committed by GitHub
parent 91e58d9049
commit e6018a464f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 56 additions and 12 deletions

View file

@ -239,6 +239,22 @@ If you don't see all your keys this could be due to a cached token. So just re-l
::: :::
### Disable `Default Team` on Admin UI
Use this if you want to hide the Default Team on the Admin UI
The following logic will apply
- If team assigned don't show `Default Team`
- If no team assigned then they should see `Default Team`
Set `default_team_disabled: true` on your litellm config.yaml
```yaml
general_settings:
master_key: sk-1234
default_team_disabled: true # OR you can set env var PROXY_DEFAULT_TEAM_DISABLED="true"
```
### Sign in with Username, Password when SSO is on ### Sign in with Username, Password when SSO is on
If you need to access the UI via username/password when SSO is on navigate to `/fallback/login`. This route will allow you to sign in with your username/password credentials. If you need to access the UI via username/password when SSO is on navigate to `/fallback/login`. This route will allow you to sign in with your username/password credentials.

View file

@ -289,7 +289,7 @@ class LiteLLMRoutes(enum.Enum):
"/key/delete", "/key/delete",
"/global/spend/logs", "/global/spend/logs",
"/global/predict/spend/logs", "/global/predict/spend/logs",
"/sso/get/logout_url", "/sso/get/ui_settings",
] ]
management_routes = [ # key management_routes = [ # key

View file

@ -1038,7 +1038,7 @@ async def user_api_key_auth(
# this token is only used for managing the ui # this token is only used for managing the ui
allowed_routes = [ allowed_routes = [
"/sso", "/sso",
"/sso/get/logout_url", "/sso/get/ui_settings",
"/login", "/login",
"/key/generate", "/key/generate",
"/key/update", "/key/update",

View file

@ -21,6 +21,11 @@ model_list:
api_base: https://exampleopenaiendpoint-production.up.railway.app api_base: https://exampleopenaiendpoint-production.up.railway.app
general_settings:
master_key: sk-1234
default_team_disabled: true
litellm_settings: litellm_settings:
success_callback: ["prometheus"] success_callback: ["prometheus"]

View file

@ -659,6 +659,11 @@ def load_from_azure_key_vault(use_azure_key_vault: bool = False):
# Set your Azure Key Vault URI # Set your Azure Key Vault URI
KVUri = os.getenv("AZURE_KEY_VAULT_URI", None) KVUri = os.getenv("AZURE_KEY_VAULT_URI", None)
if KVUri is None:
raise Exception(
"Error when loading keys from Azure Key Vault: AZURE_KEY_VAULT_URI is not set."
)
credential = DefaultAzureCredential() credential = DefaultAzureCredential()
# Create the SecretClient using the credential # Create the SecretClient using the credential
@ -8342,16 +8347,25 @@ async def login(request: Request):
@app.get( @app.get(
"/sso/get/logout_url", "/sso/get/ui_settings",
tags=["experimental"], tags=["experimental"],
include_in_schema=False, include_in_schema=False,
dependencies=[Depends(user_api_key_auth)], dependencies=[Depends(user_api_key_auth)],
) )
async def get_logout_url(request: Request): async def get_ui_settings(request: Request):
_proxy_base_url = os.getenv("PROXY_BASE_URL", None) _proxy_base_url = os.getenv("PROXY_BASE_URL", None)
_logout_url = os.getenv("PROXY_LOGOUT_URL", None) _logout_url = os.getenv("PROXY_LOGOUT_URL", None)
return {"PROXY_BASE_URL": _proxy_base_url, "PROXY_LOGOUT_URL": _logout_url} default_team_disabled = general_settings.get("default_team_disabled", False)
if "PROXY_DEFAULT_TEAM_DISABLED" in os.environ:
if os.environ["PROXY_DEFAULT_TEAM_DISABLED"].lower() == "true":
default_team_disabled = True
return {
"PROXY_BASE_URL": _proxy_base_url,
"PROXY_LOGOUT_URL": _logout_url,
"DEFAULT_TEAM_DISABLED": default_team_disabled,
}
@app.get("/onboarding/get_token", include_in_schema=False) @app.get("/onboarding/get_token", include_in_schema=False)

View file

@ -1,10 +1,12 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Select, SelectItem, Text, Title } from "@tremor/react"; import { Select, SelectItem, Text, Title } from "@tremor/react";
import { ProxySettings } from "./user_dashboard";
interface DashboardTeamProps { interface DashboardTeamProps {
teams: Object[] | null; teams: Object[] | null;
setSelectedTeam: React.Dispatch<React.SetStateAction<any | null>>; setSelectedTeam: React.Dispatch<React.SetStateAction<any | null>>;
userRole: string | null; userRole: string | null;
proxySettings: ProxySettings | null;
} }
type TeamInterface = { type TeamInterface = {
@ -17,6 +19,7 @@ const DashboardTeam: React.FC<DashboardTeamProps> = ({
teams, teams,
setSelectedTeam, setSelectedTeam,
userRole, userRole,
proxySettings,
}) => { }) => {
const defaultTeam: TeamInterface = { const defaultTeam: TeamInterface = {
models: [], models: [],
@ -31,6 +34,8 @@ const DashboardTeam: React.FC<DashboardTeamProps> = ({
if (userRole === "App User") { if (userRole === "App User") {
// Non-Admin SSO users should only see their own team - they should not see "Default Team" // Non-Admin SSO users should only see their own team - they should not see "Default Team"
updatedTeams = teams; updatedTeams = teams;
} else if (proxySettings && proxySettings.DEFAULT_TEAM_DISABLED === true) {
updatedTeams = teams ? [...teams] : [defaultTeam];
} else { } else {
updatedTeams = teams ? [...teams, defaultTeam] : [defaultTeam]; updatedTeams = teams ? [...teams, defaultTeam] : [defaultTeam];
} }

View file

@ -2752,8 +2752,8 @@ export const getProxyBaseUrlAndLogoutUrl = async (
*/ */
try { try {
let url = proxyBaseUrl let url = proxyBaseUrl
? `${proxyBaseUrl}/sso/get/logout_url` ? `${proxyBaseUrl}/sso/get/ui_settings`
: `/sso/get/logout_url`; : `sso/get/ui_settings`;
//message.info("Requesting model data"); //message.info("Requesting model data");
const response = await fetch(url, { const response = await fetch(url, {

View file

@ -28,6 +28,12 @@ type UserSpendData = {
max_budget?: number | null; max_budget?: number | null;
}; };
export interface ProxySettings {
PROXY_BASE_URL: string | null;
PROXY_LOGOUT_URL: string | null;
DEFAULT_TEAM_DISABLED: boolean;
}
function getCookie(name: string) { function getCookie(name: string) {
console.log("COOKIES", document.cookie) console.log("COOKIES", document.cookie)
const cookieValue = document.cookie const cookieValue = document.cookie
@ -46,8 +52,6 @@ interface UserDashboardProps {
setUserEmail: React.Dispatch<React.SetStateAction<string | null>>; setUserEmail: React.Dispatch<React.SetStateAction<string | null>>;
setTeams: React.Dispatch<React.SetStateAction<Object[] | null>>; setTeams: React.Dispatch<React.SetStateAction<Object[] | null>>;
setKeys: React.Dispatch<React.SetStateAction<Object[] | null>>; setKeys: React.Dispatch<React.SetStateAction<Object[] | null>>;
setProxySettings: React.Dispatch<React.SetStateAction<any>>;
proxySettings: any;
premiumUser: boolean; premiumUser: boolean;
} }
@ -67,8 +71,6 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
setUserEmail, setUserEmail,
setTeams, setTeams,
setKeys, setKeys,
setProxySettings,
proxySettings,
premiumUser, premiumUser,
}) => { }) => {
const [userSpendData, setUserSpendData] = useState<UserSpendData | null>( const [userSpendData, setUserSpendData] = useState<UserSpendData | null>(
@ -87,6 +89,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
const [accessToken, setAccessToken] = useState<string | null>(null); const [accessToken, setAccessToken] = useState<string | null>(null);
const [teamSpend, setTeamSpend] = useState<number | null>(null); const [teamSpend, setTeamSpend] = useState<number | null>(null);
const [userModels, setUserModels] = useState<string[]>([]); const [userModels, setUserModels] = useState<string[]>([]);
const [proxySettings, setProxySettings] = useState<ProxySettings | null>(null);
const defaultTeam: TeamInterface = { const defaultTeam: TeamInterface = {
models: [], models: [],
team_alias: "Default Team", team_alias: "Default Team",
@ -166,7 +169,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
} else { } else {
const fetchData = async () => { const fetchData = async () => {
try { try {
const proxy_settings = await getProxyBaseUrlAndLogoutUrl(accessToken); const proxy_settings: ProxySettings = await getProxyBaseUrlAndLogoutUrl(accessToken);
setProxySettings(proxy_settings); setProxySettings(proxy_settings);
const response = await userInfoCall( const response = await userInfoCall(
@ -347,6 +350,7 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
teams={teams} teams={teams}
setSelectedTeam={setSelectedTeam} setSelectedTeam={setSelectedTeam}
userRole={userRole} userRole={userRole}
proxySettings={proxySettings}
/> />
</Col> </Col>
</Grid> </Grid>