From cf32eb573746f39035aa15a8e7af9a373014afab Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Thu, 15 Jan 2026 22:08:45 -0800 Subject: [PATCH] refactor team member icon buttons --- .../components/team/team_member_view.test.tsx | 28 +++++++++++++++ .../src/components/team/team_member_view.tsx | 35 +++++++++---------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/ui/litellm-dashboard/src/components/team/team_member_view.test.tsx b/ui/litellm-dashboard/src/components/team/team_member_view.test.tsx index ba0f3132f64..30a06179c2f 100644 --- a/ui/litellm-dashboard/src/components/team/team_member_view.test.tsx +++ b/ui/litellm-dashboard/src/components/team/team_member_view.test.tsx @@ -20,6 +20,7 @@ vi.mock("@/utils/roles", () => ({ import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; +import { isProxyAdminRole, isUserTeamAdminForSingleTeam } from "@/utils/roles"; describe("TeamMembersComponent", () => { const mockHandleMemberDelete = vi.fn(); @@ -162,4 +163,31 @@ describe("TeamMembersComponent", () => { expect(screen.getByText("Add Member")).toBeInTheDocument(); }); + + it("should show delete button for proxy admin when canEditTeam is true", () => { + vi.mocked(isProxyAdminRole).mockReturnValue(true); + vi.mocked(isUserTeamAdminForSingleTeam).mockReturnValue(false); + + const { container } = renderWithProviders( + , + ); + + // Verify that action buttons are rendered when canEditTeam is true + // For proxy admin, both edit and delete buttons should be visible + // Check for clickable icon elements (Tremor Icon components with cursor-pointer class) + const clickableIcons = container.querySelectorAll('[class*="cursor-pointer"]'); + // Should have at least 4 icons: 2 edit buttons + 2 delete buttons for 2 members + expect(clickableIcons.length).toBeGreaterThanOrEqual(4); + + // Verify members are rendered + expect(screen.getAllByText("user1@test.com").length).toBeGreaterThan(0); + expect(screen.getAllByText("user2@test.com").length).toBeGreaterThan(0); + }); }); diff --git a/ui/litellm-dashboard/src/components/team/team_member_view.tsx b/ui/litellm-dashboard/src/components/team/team_member_view.tsx index 534d4c67e64..10b3cbd83e6 100644 --- a/ui/litellm-dashboard/src/components/team/team_member_view.tsx +++ b/ui/litellm-dashboard/src/components/team/team_member_view.tsx @@ -1,25 +1,24 @@ -import React from "react"; +import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings"; +import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; import { Member } from "@/components/networking"; +import { formatNumberWithCommas } from "@/utils/dataUtils"; +import { isProxyAdminRole, isUserTeamAdminForSingleTeam } from "@/utils/roles"; +import { InfoCircleOutlined } from "@ant-design/icons"; import { Card, Table, - TableHead, - TableRow, - TableHeaderCell, TableBody, TableCell, + TableHead, + TableHeaderCell, + TableRow, Text, - Icon, Button as TremorButton, } from "@tremor/react"; -import { InfoCircleOutlined } from "@ant-design/icons"; import { Tooltip } from "antd"; +import React from "react"; +import TableIconActionButton from "../common_components/IconActionButton/TableIconActionButtons/TableIconActionButton"; import { TeamData } from "./team_info"; -import { PencilAltIcon, TrashIcon } from "@heroicons/react/outline"; -import { formatNumberWithCommas } from "@/utils/dataUtils"; -import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings"; -import { isUserTeamAdminForSingleTeam, isProxyAdminRole } from "@/utils/roles"; -import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; interface TeamMembersComponentProps { teamData: TeamData; @@ -154,9 +153,9 @@ const TeamMembersComponent: React.FC = ({ {canEditTeam && (
- { // Get budget and rate limit data from team membership const membership = teamData.team_memberships.find((tm) => tm.user_id === member.user_id); @@ -169,14 +168,12 @@ const TeamMembersComponent: React.FC = ({ setSelectedEditMember(enhancedMember); setIsEditMemberModalVisible(true); }} - className="cursor-pointer hover:text-blue-600" /> {(isProxyAdmin || (isUserTeamAdmin && !disableTeamAdminDeleteTeamUser)) && ( - handleMemberDelete(member)} - className="cursor-pointer hover:text-red-600" /> )}