= ({
return limits.length > 0 ? limits.join(" / ") : "No Limits";
};
+ const { data: uiSettingsData } = useUISettings();
+ const { userId, userRole } = useAuthorized();
+ const disableTeamAdminDeleteTeamUser = Boolean(uiSettingsData?.values?.disable_team_admin_delete_team_user);
+ const isUserTeamAdmin = isUserTeamAdminForSingleTeam(teamData.team_info.members_with_roles, userId || "");
+ const isProxyAdmin = isProxyAdminRole(userRole || "");
+
return (
@@ -161,12 +171,14 @@ const TeamMembersComponent: React.FC = ({
}}
className="cursor-pointer hover:text-blue-600"
/>
- handleMemberDelete(member)}
- className="cursor-pointer hover:text-red-600"
- />
+ {(isProxyAdmin || (isUserTeamAdmin && !disableTeamAdminDeleteTeamUser)) && (
+ handleMemberDelete(member)}
+ className="cursor-pointer hover:text-red-600"
+ />
+ )}
)}
diff --git a/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx b/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx
index 96d4b574a1..ebb664e18c 100644
--- a/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx
+++ b/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx
@@ -276,4 +276,48 @@ describe("KeyInfoView", () => {
expect(screen.queryByText("Delete Key")).not.toBeInTheDocument();
});
});
+
+ it("should handle case when teamsData exists but no team matches key team_id", async () => {
+ const differentTeamId = "different-team-id";
+ const mockTeam: Team = {
+ team_id: differentTeamId,
+ team_alias: "Different Team",
+ models: [],
+ max_budget: null,
+ budget_duration: null,
+ tpm_limit: null,
+ rpm_limit: null,
+ organization_id: "org-1",
+ created_at: "2025-01-01T00:00:00Z",
+ keys: [],
+ members_with_roles: [
+ {
+ user_id: "team-admin-user",
+ role: "admin",
+ },
+ ],
+ };
+
+ vi.mocked(useTeams).mockReturnValue({
+ teams: [mockTeam],
+ setTeams: vi.fn(),
+ });
+
+ vi.mocked(useAuthorized).mockReturnValue({
+ ...baseUseAuthorizedMock,
+ userId: "team-admin-user",
+ userRole: "user",
+ });
+
+ // Key has a different team_id that doesn't match any team in teamsData
+ const keyData = { ...MOCK_KEY_DATA, team_id: "non-matching-team-id", user_id: "other-user-id" };
+ render(
+ {}} keyId={"test-key-id"} onKeyDataUpdate={() => {}} teams={[]} />,
+ );
+
+ await waitFor(() => {
+ expect(screen.queryByText("Regenerate Key")).not.toBeInTheDocument();
+ expect(screen.queryByText("Delete Key")).not.toBeInTheDocument();
+ });
+ });
});
diff --git a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx
index 76361cca2f..e22ec226fc 100644
--- a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx
+++ b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx
@@ -304,7 +304,7 @@ export default function KeyInfoView({
isProxyAdminRole(userRole || "") ||
(teamsData &&
isUserTeamAdminForSingleTeam(
- teamsData?.filter((team) => team.team_id === currentKeyData.team_id)[0],
+ teamsData?.filter((team) => team.team_id === currentKeyData.team_id)[0]?.members_with_roles,
userID || "",
)) ||
(userID === currentKeyData.user_id && userRole !== "Internal Viewer");
diff --git a/ui/litellm-dashboard/src/utils/roles.test.ts b/ui/litellm-dashboard/src/utils/roles.test.ts
index f2d1812714..38343094b9 100644
--- a/ui/litellm-dashboard/src/utils/roles.test.ts
+++ b/ui/litellm-dashboard/src/utils/roles.test.ts
@@ -42,81 +42,32 @@ describe("roles", () => {
describe("isUserTeamAdminForSingleTeam", () => {
it("should return true when user is team admin", () => {
- const team: Team = {
- team_id: "team-1",
- team_alias: "Test Team",
- models: [],
- max_budget: null,
- budget_duration: null,
- tpm_limit: null,
- rpm_limit: null,
- organization_id: "org-1",
- created_at: "2024-01-01",
- keys: [],
- members_with_roles: [
- { user_id: "user-1", user_email: "user1@test.com", role: "admin" },
- { user_id: "user-2", user_email: "user2@test.com", role: "user" },
- ],
- };
- expect(isUserTeamAdminForSingleTeam(team, "user-1")).toBe(true);
+ const members_with_roles = [
+ { user_id: "user-1", user_email: "user1@test.com", role: "admin" },
+ { user_id: "user-2", user_email: "user2@test.com", role: "user" },
+ ];
+ expect(isUserTeamAdminForSingleTeam(members_with_roles, "user-1")).toBe(true);
});
it("should return false when user is not team admin", () => {
- const team: Team = {
- team_id: "team-1",
- team_alias: "Test Team",
- models: [],
- max_budget: null,
- budget_duration: null,
- tpm_limit: null,
- rpm_limit: null,
- organization_id: "org-1",
- created_at: "2024-01-01",
- keys: [],
- members_with_roles: [
- { user_id: "user-1", user_email: "user1@test.com", role: "user" },
- { user_id: "user-2", user_email: "user2@test.com", role: "user" },
- ],
- };
- expect(isUserTeamAdminForSingleTeam(team, "user-1")).toBe(false);
+ const members_with_roles = [
+ { user_id: "user-1", user_email: "user1@test.com", role: "user" },
+ { user_id: "user-2", user_email: "user2@test.com", role: "user" },
+ ];
+ expect(isUserTeamAdminForSingleTeam(members_with_roles, "user-1")).toBe(false);
});
it("should return false when user is not in team", () => {
- const team: Team = {
- team_id: "team-1",
- team_alias: "Test Team",
- models: [],
- max_budget: null,
- budget_duration: null,
- tpm_limit: null,
- rpm_limit: null,
- organization_id: "org-1",
- created_at: "2024-01-01",
- keys: [],
- members_with_roles: [{ user_id: "user-2", user_email: "user2@test.com", role: "admin" }],
- };
- expect(isUserTeamAdminForSingleTeam(team, "user-1")).toBe(false);
- });
-
- it("should return false when team is null", () => {
- expect(isUserTeamAdminForSingleTeam(null, "user-1")).toBe(false);
+ const members_with_roles = [{ user_id: "user-2", user_email: "user2@test.com", role: "admin" }];
+ expect(isUserTeamAdminForSingleTeam(members_with_roles, "user-1")).toBe(false);
});
it("should return false when members_with_roles is null", () => {
- const team = {
- team_id: "team-1",
- team_alias: "Test Team",
- models: [],
- max_budget: null,
- budget_duration: null,
- tpm_limit: null,
- rpm_limit: null,
- organization_id: "org-1",
- created_at: "2024-01-01",
- keys: [],
- members_with_roles: [],
- } as Team;
- expect(isUserTeamAdminForSingleTeam(team, "user-1")).toBe(false);
+ expect(isUserTeamAdminForSingleTeam(null, "user-1")).toBe(false);
+ });
+
+ it("should return false when members_with_roles is empty array", () => {
+ expect(isUserTeamAdminForSingleTeam([], "user-1")).toBe(false);
});
});
diff --git a/ui/litellm-dashboard/src/utils/roles.ts b/ui/litellm-dashboard/src/utils/roles.ts
index 7667a5b207..580b4568c5 100644
--- a/ui/litellm-dashboard/src/utils/roles.ts
+++ b/ui/litellm-dashboard/src/utils/roles.ts
@@ -1,4 +1,4 @@
-import { Team } from "@/components/networking";
+import { Member, Team } from "@/components/networking";
// Define admin roles and permissions
export const old_admin_roles = ["Admin", "Admin Viewer"];
@@ -22,12 +22,12 @@ export const isUserTeamAdminForAnyTeam = (teams: Team[] | null, userID: string):
if (teams == null) {
return false;
}
- return teams.some((team) => isUserTeamAdminForSingleTeam(team, userID));
+ return teams.some((team) => isUserTeamAdminForSingleTeam(team.members_with_roles, userID));
};
-export const isUserTeamAdminForSingleTeam = (team: Team | null, userID: string): boolean => {
- if (team == null || team.members_with_roles == null) {
+export const isUserTeamAdminForSingleTeam = (teamMemberWithRoles: Member[] | null, userID: string): boolean => {
+ if (teamMemberWithRoles == null) {
return false;
}
- return team.members_with_roles.some((member) => member.user_id === userID && member.role === "admin");
+ return teamMemberWithRoles.some((member) => member.user_id === userID && member.role === "admin");
};