From 11f009a5a479209fe7a1500b537f20b31f5bab76 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Mon, 17 Nov 2025 19:49:33 -0800 Subject: [PATCH] Teams table empty state (#16738) --- .../src/components/OldTeams.test.tsx | 72 +++ .../src/components/OldTeams.tsx | 409 +++++++++--------- 2 files changed, 280 insertions(+), 201 deletions(-) diff --git a/ui/litellm-dashboard/src/components/OldTeams.test.tsx b/ui/litellm-dashboard/src/components/OldTeams.test.tsx index c055a2f85f7..b9320f69779 100644 --- a/ui/litellm-dashboard/src/components/OldTeams.test.tsx +++ b/ui/litellm-dashboard/src/components/OldTeams.test.tsx @@ -270,6 +270,78 @@ describe("OldTeams - handleCreate organization handling", () => { }); }); +describe("OldTeams - empty state", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should display empty state message when teams array is empty", () => { + const { getByText } = render( + , + ); + + expect(getByText("No teams found")).toBeInTheDocument(); + expect(getByText("Adjust your filters or create a new team")).toBeInTheDocument(); + }); + + it("should display empty state message when teams is null", () => { + const { getByText } = render( + , + ); + + expect(getByText("No teams found")).toBeInTheDocument(); + expect(getByText("Adjust your filters or create a new team")).toBeInTheDocument(); + }); + + it("should not display empty state when teams array has items", () => { + const { queryByText, getByText } = render( + , + ); + + expect(queryByText("No teams found")).not.toBeInTheDocument(); + expect(queryByText("Adjust your filters or create a new team")).not.toBeInTheDocument(); + expect(getByText("Test Team")).toBeInTheDocument(); + }); +}); + describe("OldTeams - helper functions", () => { describe("getAdminOrganizations", () => { it("should return all organizations for Admin role", () => { diff --git a/ui/litellm-dashboard/src/components/OldTeams.tsx b/ui/litellm-dashboard/src/components/OldTeams.tsx index df56ab5a5e7..fa979e992e4 100644 --- a/ui/litellm-dashboard/src/components/OldTeams.tsx +++ b/ui/litellm-dashboard/src/components/OldTeams.tsx @@ -760,212 +760,219 @@ const Teams: React.FC = ({ - {teams && teams.length > 0 - ? teams - .filter((team) => { - if (!currentOrg) return true; - return team.organization_id === currentOrg.organization_id; - }) - .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) - .map((team: any) => ( - - - {team["team_alias"]} - - -
- - - -
-
- - {team.created_at ? new Date(team.created_at).toLocaleDateString() : "N/A"} - - - {formatNumberWithCommas(team["spend"], 4)} - - - {team["max_budget"] !== null && team["max_budget"] !== undefined - ? team["max_budget"] - : "No limit"} - - 3 ? "px-0" : ""} - > -
- {Array.isArray(team.models) ? ( -
- {team.models.length === 0 ? ( - - All Proxy Models - - ) : ( - <> -
- {team.models.length > 3 && ( -
- { - setExpandedAccordions((prev) => ({ - ...prev, - [team.team_id]: !prev[team.team_id], - })); - }} - /> -
- )} -
- {team.models.slice(0, 3).map((model: string, index: number) => - model === "all-proxy-models" ? ( - - All Proxy Models - - ) : ( - - - {model.length > 30 - ? `${getModelDisplayName(model).slice(0, 30)}...` - : getModelDisplayName(model)} - - - ), - )} - {team.models.length > 3 && !expandedAccordions[team.team_id] && ( - + {teams && teams.length > 0 ? ( + teams + .filter((team) => { + if (!currentOrg) return true; + return team.organization_id === currentOrg.organization_id; + }) + .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()) + .map((team: any) => ( + + + {team["team_alias"]} + + +
+ + + +
+
+ + {team.created_at ? new Date(team.created_at).toLocaleDateString() : "N/A"} + + + {formatNumberWithCommas(team["spend"], 4)} + + + {team["max_budget"] !== null && team["max_budget"] !== undefined + ? team["max_budget"] + : "No limit"} + + 3 ? "px-0" : ""} + > +
+ {Array.isArray(team.models) ? ( +
+ {team.models.length === 0 ? ( + + All Proxy Models + + ) : ( + <> +
+ {team.models.length > 3 && ( +
+ { + setExpandedAccordions((prev) => ({ + ...prev, + [team.team_id]: !prev[team.team_id], + })); + }} + /> +
+ )} +
+ {team.models.slice(0, 3).map((model: string, index: number) => + model === "all-proxy-models" ? ( + + All Proxy Models + + ) : ( + - +{team.models.length - 3}{" "} - {team.models.length - 3 === 1 - ? "more model" - : "more models"} + {model.length > 30 + ? `${getModelDisplayName(model).slice(0, 30)}...` + : getModelDisplayName(model)} - )} - {expandedAccordions[team.team_id] && ( -
- {team.models.slice(3).map((model: string, index: number) => - model === "all-proxy-models" ? ( - - All Proxy Models - - ) : ( - - - {model.length > 30 - ? `${getModelDisplayName(model).slice(0, 30)}...` - : getModelDisplayName(model)} - - - ), - )} -
- )} -
+ ), + )} + {team.models.length > 3 && !expandedAccordions[team.team_id] && ( + + + +{team.models.length - 3}{" "} + {team.models.length - 3 === 1 ? "more model" : "more models"} + + + )} + {expandedAccordions[team.team_id] && ( +
+ {team.models.slice(3).map((model: string, index: number) => + model === "all-proxy-models" ? ( + + All Proxy Models + + ) : ( + + + {model.length > 30 + ? `${getModelDisplayName(model).slice(0, 30)}...` + : getModelDisplayName(model)} + + + ), + )} +
+ )}
- - )} -
- ) : null} -
-
- - {team.organization_id} - - - {perTeamInfo && - team.team_id && - perTeamInfo[team.team_id] && - perTeamInfo[team.team_id].keys && - perTeamInfo[team.team_id].keys.length}{" "} - Keys - - - {perTeamInfo && - team.team_id && - perTeamInfo[team.team_id] && - perTeamInfo[team.team_id].team_info && - perTeamInfo[team.team_id].team_info.members_with_roles && - perTeamInfo[team.team_id].team_info.members_with_roles.length}{" "} - Members - - - - {userRole == "Admin" ? ( - <> - - {" "} - { - setSelectedTeamId(team.team_id); - setEditTeam(true); - }} - /> - - - {" "} - handleDelete(team.team_id)} - icon={TrashIcon} - size="sm" - className="cursor-pointer hover:text-red-600" - data-testid="delete-team-button" - /> - - +
+ + )} +
) : null} - - - )) - : null} +
+ + + {team.organization_id} + + + {perTeamInfo && + team.team_id && + perTeamInfo[team.team_id] && + perTeamInfo[team.team_id].keys && + perTeamInfo[team.team_id].keys.length}{" "} + Keys + + + {perTeamInfo && + team.team_id && + perTeamInfo[team.team_id] && + perTeamInfo[team.team_id].team_info && + perTeamInfo[team.team_id].team_info.members_with_roles && + perTeamInfo[team.team_id].team_info.members_with_roles.length}{" "} + Members + + + + {userRole == "Admin" ? ( + <> + + {" "} + { + setSelectedTeamId(team.team_id); + setEditTeam(true); + }} + /> + + + {" "} + handleDelete(team.team_id)} + icon={TrashIcon} + size="sm" + className="cursor-pointer hover:text-red-600" + data-testid="delete-team-button" + /> + + + ) : null} + + + )) + ) : ( + + +
+ No teams found + Adjust your filters or create a new team +
+
+
+ )} {isDeleteModalOpen &&