mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
feat(ui): cut the teams page over to the /ui/teams path route (#30343)
* feat(ui): cut the teams page over to the /ui/teams path route OldTeams renders from app/(dashboard)/teams/page.tsx via useAuthorized. The component already fetched its own paginated, filtered team list through v2TeamListCall; setTeams was only a round-trip back into the shell's lifted state, so it becomes internal useState. The organizations prop was redundant with the useOrganizations hook the component already calls, and searchParams was never read, so both are dropped. The shell keeps its own teams state and fetch for the still-coupled api-keys and models arms. Tests no longer inject teams through a prop; they mock teamListCall to drive what the component renders. * test(ui): drop unnecessary as-any casts on teamListCall mocks teamListCall returns Promise<any>, so mockResolvedValue already accepts the payload untyped. The casts pushed the repo-wide no-explicit-any lint budget over its ceiling in CI. * test(ui): drop redundant as-any casts from team mock fixtures The mocked teamListCall resolves an any-typed payload, so the inner team fixtures no longer need casts to carry a null organization_id, a keys_count field, or partial key objects.
This commit is contained in:
parent
039a2d8bf5
commit
5c41aabab0
7 changed files with 310 additions and 384 deletions
|
|
@ -40,6 +40,7 @@ export const MIGRATED_E2E_PAGES: Record<string, string> = {
|
|||
agents: "agents",
|
||||
"router-settings": "router-settings",
|
||||
users: "users",
|
||||
teams: "teams",
|
||||
organizations: "organizations",
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { useUISettings } from "@/app/(dashboard)/hooks/uiSettings/useUISettings"
|
|||
import LoadingScreen from "@/components/common_components/LoadingScreen";
|
||||
import { Team } from "@/components/key_team_helpers/key_list";
|
||||
import { Organization, proxyBaseUrl, getInProductNudgesCall } from "@/components/networking";
|
||||
import OldTeams from "@/components/OldTeams";
|
||||
import { CreateKeyPrefillData } from "@/components/organisms/create_key_button";
|
||||
import { fetchOrganizations } from "@/components/organizations";
|
||||
import PassThroughSettings from "@/components/pass_through_settings";
|
||||
|
|
@ -318,17 +317,6 @@ function CreateKeyPageContent() {
|
|||
premiumUser={premiumUser}
|
||||
teams={teams}
|
||||
/>
|
||||
) : page == "teams" ? (
|
||||
<OldTeams
|
||||
teams={teams}
|
||||
setTeams={setTeams}
|
||||
accessToken={accessToken}
|
||||
userID={userID}
|
||||
userRole={userRole}
|
||||
organizations={organizations}
|
||||
premiumUser={premiumUser}
|
||||
searchParams={searchParams}
|
||||
/>
|
||||
) : page == "pass-through-settings" ? (
|
||||
<PassThroughSettings
|
||||
userID={userID}
|
||||
|
|
|
|||
9
ui/litellm-dashboard/src/app/(dashboard)/teams/page.tsx
Normal file
9
ui/litellm-dashboard/src/app/(dashboard)/teams/page.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
"use client";
|
||||
|
||||
import OldTeams from "@/components/OldTeams";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
|
||||
export default function TeamsPage() {
|
||||
const { accessToken, userId, userRole, premiumUser } = useAuthorized();
|
||||
return <OldTeams accessToken={accessToken} userID={userId} userRole={userRole} premiumUser={premiumUser ?? false} />;
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
|||
import { fetchAvailableModelsForTeamOrKey } from "./key_team_helpers/fetch_available_models_team_key";
|
||||
import { fetchMCPAccessGroups, getGuardrailsList, teamCreateCall } from "./networking";
|
||||
import OldTeams from "./OldTeams";
|
||||
import { teamListCall } from "@/app/(dashboard)/hooks/teams/useTeams";
|
||||
|
||||
const mockTeamInfoView = vi.fn();
|
||||
const mockUseOrganizations = vi.fn();
|
||||
|
|
@ -349,32 +350,29 @@ describe("OldTeams - handleCreate organization handling", () => {
|
|||
|
||||
it("should clear the delete modal when the cancel button is clicked", async () => {
|
||||
mockUseOrganizations.mockReturnValue({ data: [] });
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId("delete-team-button")).toBeInTheDocument();
|
||||
});
|
||||
|
|
@ -393,17 +391,8 @@ describe("OldTeams - empty state", () => {
|
|||
});
|
||||
|
||||
it("should display empty state message when teams array is empty", async () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({ teams: [], total: 0, page: 1, page_size: 100, total_pages: 1 });
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("No teams yet")).toBeInTheDocument();
|
||||
|
|
@ -414,17 +403,8 @@ describe("OldTeams - empty state", () => {
|
|||
});
|
||||
|
||||
it("should display empty state message when teams is null", async () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={null}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({ teams: [], total: 0, page: 1, page_size: 100, total_pages: 1 });
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("No teams yet")).toBeInTheDocument();
|
||||
|
|
@ -435,32 +415,29 @@ describe("OldTeams - empty state", () => {
|
|||
});
|
||||
|
||||
it("should not display empty state when teams array has items", async () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Test Team")).toBeInTheDocument();
|
||||
|
|
@ -608,33 +585,29 @@ describe("OldTeams - premium props", () => {
|
|||
});
|
||||
|
||||
it("passes premiumUser flag to TeamInfoView", async () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "team-123456789",
|
||||
team_alias: "Premium Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
premiumUser={true}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "team-123456789",
|
||||
team_alias: "Premium Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" premiumUser={true} />);
|
||||
|
||||
const teamIdElement = await screen.findByText("team-123456789");
|
||||
act(() => {
|
||||
|
|
@ -654,125 +627,113 @@ describe("OldTeams - Default Team Settings tab visibility", () => {
|
|||
});
|
||||
|
||||
it("should show Default Team Settings tab for Admin role", () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
expect(screen.getByRole("tab", { name: "Default Team Settings" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should show Default Team Settings tab for proxy_admin role", () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="proxy_admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="proxy_admin" />);
|
||||
|
||||
expect(screen.getByRole("tab", { name: "Default Team Settings" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not show Default Team Settings tab for proxy_admin_viewer role", () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="proxy_admin_viewer"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="proxy_admin_viewer" />);
|
||||
|
||||
expect(screen.queryByRole("tab", { name: "Default Team Settings" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should not show Default Team Settings tab for Admin Viewer role", () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin Viewer"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin Viewer" />);
|
||||
|
||||
expect(screen.queryByRole("tab", { name: "Default Team Settings" })).not.toBeInTheDocument();
|
||||
});
|
||||
|
|
@ -793,24 +754,15 @@ describe("OldTeams - access_group_ids in team create", () => {
|
|||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
} as any);
|
||||
});
|
||||
mockUseOrganizations.mockReturnValue({
|
||||
data: [{ organization_id: "org-1", organization_alias: "Org 1", models: [], members: [] }],
|
||||
});
|
||||
});
|
||||
|
||||
it("should pass access_group_ids to teamCreateCall when creating team", async () => {
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[{ organization_id: "org-1", organization_alias: "Org 1", models: [], members: [] }]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({ teams: [], total: 0, page: 1, page_size: 100, total_pages: 1 });
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
const createButton = screen.getAllByRole("button", { name: /create team/i })[0];
|
||||
act(() => {
|
||||
|
|
@ -864,17 +816,8 @@ describe("OldTeams - models dropdown options", () => {
|
|||
it("should not render all-proxy-models option in models select", async () => {
|
||||
vi.mocked(fetchAvailableModelsForTeamOrKey).mockResolvedValue(["gpt-4", "gpt-3.5-turbo"]);
|
||||
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({ teams: [], total: 0, page: 1, page_size: 100, total_pages: 1 });
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(fetchAvailableModelsForTeamOrKey).toHaveBeenCalled();
|
||||
|
|
@ -922,32 +865,29 @@ describe("OldTeams - organization alias display", () => {
|
|||
|
||||
mockUseOrganizations.mockReturnValue({ data: mockOrganizations });
|
||||
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={mockOrganizations}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("Test Organization")).toBeInTheDocument();
|
||||
|
|
@ -958,32 +898,29 @@ describe("OldTeams - organization alias display", () => {
|
|||
it("should display organization id when alias is not found", async () => {
|
||||
mockUseOrganizations.mockReturnValue({ data: [] });
|
||||
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-unknown",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: "org-unknown",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText("org-unknown")).toBeInTheDocument();
|
||||
|
|
@ -993,32 +930,29 @@ describe("OldTeams - organization alias display", () => {
|
|||
it("should display N/A when organization_id is null", async () => {
|
||||
mockUseOrganizations.mockReturnValue({ data: [] });
|
||||
|
||||
renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: null as any,
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
);
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Test Team",
|
||||
organization_id: null,
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
renderWithQueryClient(<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />);
|
||||
|
||||
await waitFor(() => {
|
||||
// When organization_id is null, the table shows "—" in the Organization column
|
||||
|
|
@ -1034,32 +968,31 @@ describe("OldTeams - Resources column keys badge", () => {
|
|||
});
|
||||
|
||||
it("renders keys_count from the v2 payload in the Resources badge", async () => {
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Team With Keys",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
keys_count: 3,
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
const { container } = renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "1",
|
||||
team_alias: "Team With Keys",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [],
|
||||
keys_count: 3,
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
} as any,
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
|
|
@ -1071,31 +1004,30 @@ describe("OldTeams - Resources column keys badge", () => {
|
|||
});
|
||||
|
||||
it("falls back to keys.length when keys_count is absent", async () => {
|
||||
vi.mocked(teamListCall).mockResolvedValue({
|
||||
teams: [
|
||||
{
|
||||
team_id: "2",
|
||||
team_alias: "Legacy Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [{ token: "t1" }, { token: "t2" }],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
},
|
||||
],
|
||||
total: 1,
|
||||
page: 1,
|
||||
page_size: 100,
|
||||
total_pages: 1,
|
||||
});
|
||||
const { container } = renderWithQueryClient(
|
||||
<OldTeams
|
||||
teams={[
|
||||
{
|
||||
team_id: "2",
|
||||
team_alias: "Legacy Team",
|
||||
organization_id: "org-123",
|
||||
models: ["gpt-4"],
|
||||
max_budget: 100,
|
||||
budget_duration: "1d",
|
||||
tpm_limit: 1000,
|
||||
rpm_limit: 1000,
|
||||
created_at: new Date().toISOString(),
|
||||
keys: [{ token: "t1" } as any, { token: "t2" } as any],
|
||||
members_with_roles: [],
|
||||
spend: 0,
|
||||
} as any,
|
||||
]}
|
||||
searchParams={{}}
|
||||
accessToken="test-token"
|
||||
setTeams={vi.fn()}
|
||||
userID="user-123"
|
||||
userRole="Admin"
|
||||
organizations={[]}
|
||||
/>,
|
||||
<OldTeams accessToken="test-token" userID="user-123" userRole="Admin" />,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
|
|
|
|||
|
|
@ -54,13 +54,9 @@ import VectorStoreSelector from "./vector_store_management/VectorStoreSelector";
|
|||
import SearchToolSelector from "./SearchTools/SearchToolSelector";
|
||||
|
||||
interface TeamProps {
|
||||
teams: Team[] | null;
|
||||
searchParams: any;
|
||||
accessToken: string | null;
|
||||
setTeams: React.Dispatch<React.SetStateAction<Team[] | null>>;
|
||||
userID: string | null;
|
||||
userRole: string | null;
|
||||
organizations: Organization[] | null;
|
||||
premiumUser?: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -165,18 +161,10 @@ const getOrganizationAlias = (
|
|||
};
|
||||
|
||||
// @deprecated
|
||||
const Teams: React.FC<TeamProps> = ({
|
||||
teams,
|
||||
searchParams,
|
||||
accessToken,
|
||||
setTeams,
|
||||
userID,
|
||||
userRole,
|
||||
organizations,
|
||||
premiumUser = false,
|
||||
}) => {
|
||||
console.log(`organizations: ${JSON.stringify(organizations)}`);
|
||||
const Teams: React.FC<TeamProps> = ({ accessToken, userID, userRole, premiumUser = false }) => {
|
||||
const { data: organizationsData } = useOrganizations();
|
||||
const organizations = organizationsData ?? null;
|
||||
const [teams, setTeams] = useState<Team[] | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [fetchError, setFetchError] = useState<string | null>(null);
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
|
|
@ -721,7 +709,7 @@ const Teams: React.FC<TeamProps> = ({
|
|||
width: 160,
|
||||
ellipsis: true,
|
||||
render: (_: unknown, record: Team) => {
|
||||
const orgAlias = getOrganizationAlias(record.organization_id, organizationsData || organizations);
|
||||
const orgAlias = getOrganizationAlias(record.organization_id, organizations);
|
||||
return record.organization_id ? (
|
||||
<Text ellipsis style={{ fontSize: 14 }}>
|
||||
{orgAlias}
|
||||
|
|
@ -860,7 +848,7 @@ const Teams: React.FC<TeamProps> = ({
|
|||
),
|
||||
},
|
||||
],
|
||||
[userRole, perTeamInfo, organizationsData, organizations],
|
||||
[userRole, perTeamInfo, organizations],
|
||||
);
|
||||
|
||||
const displayTeams = useMemo(() => teams ?? [], [teams]);
|
||||
|
|
|
|||
|
|
@ -127,6 +127,13 @@ describe("migratedHref / legacyPageHref", () => {
|
|||
expect(MIGRATED_PAGES.users).toBe("users");
|
||||
});
|
||||
|
||||
it("maps the teams id to its route", async () => {
|
||||
vi.doMock("@/components/networking", () => ({ serverRootPath: "/" }));
|
||||
const { MIGRATED_PAGES } = await import("./migratedPages");
|
||||
|
||||
expect(MIGRATED_PAGES.teams).toBe("teams");
|
||||
});
|
||||
|
||||
it("maps the organizations id to its route", async () => {
|
||||
vi.doMock("@/components/networking", () => ({ serverRootPath: "/" }));
|
||||
const { MIGRATED_PAGES } = await import("./migratedPages");
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ export const MIGRATED_PAGES: Record<string, string> = {
|
|||
agents: "agents",
|
||||
"router-settings": "router-settings",
|
||||
users: "users",
|
||||
teams: "teams",
|
||||
organizations: "organizations",
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue