diff --git a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.test.tsx
index 29c9b17cb21..5a5fb475f08 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.test.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.test.tsx
@@ -42,8 +42,16 @@ const MOCK_USER_DATA_NO_TEAMS = {
teams: [],
};
+vi.mock("next/navigation", () => ({
+ useRouter: () => ({ push: vi.fn() }),
+ usePathname: () => "/users",
+ useSearchParams: () => new URLSearchParams(window.location.search),
+}));
+
+// entityLinks -> migratedPages imports serverRootPath from the same module, so the mock must export it too.
vi.mock("@/components/networking", () => {
return {
+ serverRootPath: "/",
userGetInfoV2: (...args: any[]) => mockUserGetInfoV2(...args),
userDeleteCall: vi.fn(),
userUpdateUserCall: (...args: unknown[]) => mockUserUpdateUserCall(...args),
@@ -145,6 +153,21 @@ describe("UserInfoView", () => {
});
});
+ it("should link each team name to its team page", async () => {
+ render();
+
+ await waitFor(() => {
+ expect(screen.getByRole("link", { name: "Alpha Team" })).toHaveAttribute(
+ "href",
+ expect.stringContaining("/teams?team=team-1"),
+ );
+ expect(screen.getByRole("link", { name: "Beta Team" })).toHaveAttribute(
+ "href",
+ expect.stringContaining("/teams?team=team-2"),
+ );
+ });
+ });
+
it("should show 'No teams' when user has no teams", async () => {
mockUserGetInfoV2.mockResolvedValue(MOCK_USER_DATA_NO_TEAMS);
render();
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.tsx b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.tsx
index 34b34066f14..853dc570796 100644
--- a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.tsx
+++ b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/user_info_view.tsx
@@ -34,6 +34,8 @@ import {
} from "@/components/networking";
import { Button as AntdButton, Modal, Select as AntdSelect, Form, Tooltip } from "antd";
import { rolesWithWriteAccess } from "@/utils/roles";
+import { teamDetailHref } from "@/utils/entityLinks";
+import { BadgeLink } from "@/components/shared/BadgeLink";
import { UserEditView } from "../user_edit_view";
import OnboardingModal, { InvitationLink } from "@/components/onboarding_link";
import { formatNumberWithCommas, copyToClipboard as utilCopyToClipboard } from "@/utils/dataUtils";
@@ -484,7 +486,11 @@ export default function UserInfoView({
{teamDetails.slice(0, isTeamsExpanded ? teamDetails.length : 20).map((team) => (
- {team.team_alias || team.team_id}
+
+
+ {team.team_alias || team.team_id}
+
+
{isProxyAdmin && (