forked from phoenix/litellm-mirror
build(ui): allow admin_viewer to view teams tab
Allows admin viewe role to see available teams on proxy ui
This commit is contained in:
parent
7fa25c443a
commit
1080c7014e
5 changed files with 72 additions and 13 deletions
|
@ -1037,14 +1037,7 @@ async def user_api_key_auth(
|
||||||
# /model/info just shows models user has access to
|
# /model/info just shows models user has access to
|
||||||
pass
|
pass
|
||||||
elif route == "/team/info":
|
elif route == "/team/info":
|
||||||
# check if key can access this team's info
|
pass # handled by function itself
|
||||||
query_params = request.query_params
|
|
||||||
team_id = query_params.get("team_id")
|
|
||||||
if team_id != valid_token.team_id:
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=status.HTTP_403_FORBIDDEN,
|
|
||||||
detail="key not allowed to access this team's info",
|
|
||||||
)
|
|
||||||
elif (
|
elif (
|
||||||
_has_user_setup_sso()
|
_has_user_setup_sso()
|
||||||
and route in LiteLLMRoutes.sso_only_routes.value
|
and route in LiteLLMRoutes.sso_only_routes.value
|
||||||
|
@ -1171,6 +1164,7 @@ async def user_api_key_auth(
|
||||||
# No token was found when looking up in the DB
|
# No token was found when looking up in the DB
|
||||||
raise Exception("Invalid proxy server token passed")
|
raise Exception("Invalid proxy server token passed")
|
||||||
if valid_token_dict is not None:
|
if valid_token_dict is not None:
|
||||||
|
user_role = _get_user_role(user_id_information=user_id_information)
|
||||||
if user_id_information is not None and _is_user_proxy_admin(
|
if user_id_information is not None and _is_user_proxy_admin(
|
||||||
user_id_information
|
user_id_information
|
||||||
):
|
):
|
||||||
|
@ -1183,14 +1177,14 @@ async def user_api_key_auth(
|
||||||
elif _has_user_setup_sso() and route in LiteLLMRoutes.sso_only_routes.value:
|
elif _has_user_setup_sso() and route in LiteLLMRoutes.sso_only_routes.value:
|
||||||
return UserAPIKeyAuth(
|
return UserAPIKeyAuth(
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
user_role=LitellmUserRoles.INTERNAL_USER,
|
user_role=user_role or LitellmUserRoles.INTERNAL_USER,
|
||||||
parent_otel_span=parent_otel_span,
|
parent_otel_span=parent_otel_span,
|
||||||
**valid_token_dict,
|
**valid_token_dict,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return UserAPIKeyAuth(
|
return UserAPIKeyAuth(
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
user_role=LitellmUserRoles.INTERNAL_USER,
|
user_role=user_role or LitellmUserRoles.INTERNAL_USER,
|
||||||
parent_otel_span=parent_otel_span,
|
parent_otel_span=parent_otel_span,
|
||||||
**valid_token_dict,
|
**valid_token_dict,
|
||||||
)
|
)
|
||||||
|
@ -1282,7 +1276,7 @@ def _is_user_proxy_admin(user_id_information: Optional[list]):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _get_user_role(user_id_information: Optional[list]):
|
def _get_user_role(user_id_information: Optional[list]) -> Optional[str]:
|
||||||
if user_id_information is None:
|
if user_id_information is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -766,7 +766,11 @@ async def team_info(
|
||||||
detail={"message": "Malformed request. No team id passed in."},
|
detail={"message": "Malformed request. No team id passed in."},
|
||||||
)
|
)
|
||||||
|
|
||||||
if user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value:
|
if (
|
||||||
|
user_api_key_dict.user_role == LitellmUserRoles.PROXY_ADMIN.value
|
||||||
|
or user_api_key_dict.user_role
|
||||||
|
== LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY.value
|
||||||
|
):
|
||||||
pass
|
pass
|
||||||
elif user_api_key_dict.team_id is None or (
|
elif user_api_key_dict.team_id is None or (
|
||||||
team_id != user_api_key_dict.team_id
|
team_id != user_api_key_dict.team_id
|
||||||
|
@ -916,7 +920,10 @@ async def list_team(
|
||||||
prisma_client,
|
prisma_client,
|
||||||
)
|
)
|
||||||
|
|
||||||
if user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN:
|
if (
|
||||||
|
user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN
|
||||||
|
and user_api_key_dict.user_role != LitellmUserRoles.PROXY_ADMIN_VIEW_ONLY
|
||||||
|
):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=401,
|
status_code=401,
|
||||||
detail={
|
detail={
|
||||||
|
|
|
@ -31,6 +31,9 @@ const Sidebar: React.FC<SidebarProps> = ({
|
||||||
<Menu.Item key="1" onClick={() => setPage("usage")}>
|
<Menu.Item key="1" onClick={() => setPage("usage")}>
|
||||||
Usage
|
Usage
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item key="6" onClick={() => setPage("teams")}>
|
||||||
|
<Text>Teams</Text>
|
||||||
|
</Menu.Item>
|
||||||
<Menu.Item key="9" onClick={() => setPage("caching")}>
|
<Menu.Item key="9" onClick={() => setPage("caching")}>
|
||||||
<Text>Caching</Text>
|
<Text>Caching</Text>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
|
|
@ -636,6 +636,39 @@ export const teamInfoCall = async (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const teamListCall = async (
|
||||||
|
accessToken: String,
|
||||||
|
) => {
|
||||||
|
/**
|
||||||
|
* Get all available teams on proxy
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
let url = proxyBaseUrl ? `${proxyBaseUrl}/team/list` : `/team/list`;
|
||||||
|
console.log("in teamInfoCall");
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
[globalLitellmHeaderName]: `Bearer ${accessToken}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.text();
|
||||||
|
handleError(errorData);
|
||||||
|
throw new Error("Network response was not ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("API Response:", data);
|
||||||
|
return data;
|
||||||
|
// Handle success - you might want to update some state or UI based on the created key
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to create key:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const getTotalSpendCall = async (accessToken: String) => {
|
export const getTotalSpendCall = async (accessToken: String) => {
|
||||||
/**
|
/**
|
||||||
* Get all models on proxy
|
* Get all models on proxy
|
||||||
|
|
|
@ -62,6 +62,7 @@ import {
|
||||||
teamMemberAddCall,
|
teamMemberAddCall,
|
||||||
Member,
|
Member,
|
||||||
modelAvailableCall,
|
modelAvailableCall,
|
||||||
|
teamListCall
|
||||||
} from "./networking";
|
} from "./networking";
|
||||||
|
|
||||||
const Team: React.FC<TeamProps> = ({
|
const Team: React.FC<TeamProps> = ({
|
||||||
|
@ -72,6 +73,27 @@ const Team: React.FC<TeamProps> = ({
|
||||||
userID,
|
userID,
|
||||||
userRole,
|
userRole,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
|
if (teams && teams.length > 0) {
|
||||||
|
console.log(`Received teams: ${JSON.stringify(teams, null, 2)}`);
|
||||||
|
} else {
|
||||||
|
console.log("No teams received or teams array is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(`inside useeffect - ${teams}`)
|
||||||
|
if (teams === null && accessToken) {
|
||||||
|
// Call your function here
|
||||||
|
const fetchData = async () => {
|
||||||
|
const givenTeams = await teamListCall(accessToken)
|
||||||
|
console.log(`givenTeams: ${givenTeams}`)
|
||||||
|
|
||||||
|
setTeams(givenTeams)
|
||||||
|
}
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
}, [teams]);
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [memberForm] = Form.useForm();
|
const [memberForm] = Form.useForm();
|
||||||
const { Title, Paragraph } = Typography;
|
const { Title, Paragraph } = Typography;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue