diff --git a/ui/litellm-dashboard/e2e_tests/fixtures/migratedPages.ts b/ui/litellm-dashboard/e2e_tests/fixtures/migratedPages.ts index 749c3cde17..38b9a87582 100644 --- a/ui/litellm-dashboard/e2e_tests/fixtures/migratedPages.ts +++ b/ui/litellm-dashboard/e2e_tests/fixtures/migratedPages.ts @@ -11,13 +11,15 @@ * Keep this in lockstep with MIGRATED_PAGES in src/utils/migratedPages.ts. * Pending (add as each PR lands): the leaf-pages batch * (budgets, caching, cost-tracking, guardrails, guardrails-monitor, logs, - * mcp-servers, memory, policies, projects, prompts, search-tools, skills, + * mcp-servers, memory, policies, prompts, search-tools, skills, * tag-management, tool-policies, transform-request, ui-theme, vector-stores, - * workflows, access-groups). + * workflows). */ export const MIGRATED_E2E_PAGES: Record = { api_ref: "api-reference", "llm-playground": "playground", + projects: "projects", + "access-groups": "access-groups", }; export const MIGRATED_E2E_SEGMENTS: string[] = [...new Set(Object.values(MIGRATED_E2E_PAGES))]; diff --git a/ui/litellm-dashboard/e2e_tests/globalSetup.ts b/ui/litellm-dashboard/e2e_tests/globalSetup.ts index 0b3fa7e880..661155b761 100644 --- a/ui/litellm-dashboard/e2e_tests/globalSetup.ts +++ b/ui/litellm-dashboard/e2e_tests/globalSetup.ts @@ -1,4 +1,4 @@ -import { chromium, expect } from "@playwright/test"; +import { chromium, expect, request } from "@playwright/test"; import { users, Role, STORAGE_PATHS } from "./fixtures/users"; import * as fs from "fs"; @@ -6,6 +6,21 @@ async function globalSetup() { const browser = await chromium.launch(); const rootPath = process.env.SERVER_ROOT_PATH ?? ""; + // The Projects sidebar item is hidden unless the enterprise-gated + // enable_projects_ui setting is on, and the seeded DB starts with it off. + // The proxy runs with LITELLM_LICENSE in CI, so enable it the same way + // the admin UI toggle does; the projects migration smoke needs the link. + const masterKey = process.env.LITELLM_MASTER_KEY || "sk-1234"; + const api = await request.newContext(); + const settingsRes = await api.patch(`http://localhost:4000${rootPath}/update/ui_settings`, { + headers: { Authorization: `Bearer ${masterKey}` }, + data: { enable_projects_ui: true }, + }); + if (!settingsRes.ok()) { + throw new Error(`Enabling enable_projects_ui failed (${settingsRes.status()}): ${await settingsRes.text()}`); + } + await api.dispose(); + for (const role of Object.values(Role)) { const { email, password } = users[role]; const storagePath = STORAGE_PATHS[role]; diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 358064c00a..8f865915e4 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -472,22 +472,22 @@ "count": 4 } }, - "src/components/Projects/ProjectDetailsPage.tsx": { + "src/app/(dashboard)/projects/components/ProjectDetailsPage.tsx": { "no-restricted-imports": { "count": 1 } }, - "src/components/Projects/ProjectKeysSection.tsx": { + "src/app/(dashboard)/projects/components/ProjectKeysSection.tsx": { "react-hooks/set-state-in-effect": { "count": 1 } }, - "src/components/Projects/ProjectModals/ProjectBaseForm.tsx": { + "src/app/(dashboard)/projects/components/ProjectModals/ProjectBaseForm.tsx": { "react-hooks/set-state-in-effect": { "count": 2 } }, - "src/components/Projects/ProjectsPage.tsx": { + "src/app/(dashboard)/projects/components/ProjectsPage.tsx": { "react-hooks/set-state-in-effect": { "count": 1 } diff --git a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsDetailsPage.test.tsx similarity index 99% rename from ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.test.tsx rename to ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsDetailsPage.test.tsx index ee8a8d0ffc..cf41f623fd 100644 --- a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsDetailsPage.test.tsx @@ -3,7 +3,7 @@ import { AccessGroupResponse } from "@/app/(dashboard)/hooks/accessGroups/useAcc import { screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { renderWithProviders } from "../../../tests/test-utils"; +import { renderWithProviders } from "../../../../../tests/test-utils"; import { AccessGroupDetail } from "./AccessGroupsDetailsPage"; vi.mock("@/app/(dashboard)/hooks/accessGroups/useAccessGroupDetails"); diff --git a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.tsx b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsDetailsPage.tsx similarity index 99% rename from ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.tsx rename to ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsDetailsPage.tsx index ae0cd8cd61..72a89093bd 100644 --- a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsDetailsPage.tsx @@ -17,7 +17,7 @@ import { } from "antd"; import { ArrowLeftIcon, BotIcon, EditIcon, KeyIcon, LayersIcon, ServerIcon, UsersIcon } from "lucide-react"; import { useState } from "react"; -import DefaultProxyAdminTag from "../common_components/DefaultProxyAdminTag"; +import DefaultProxyAdminTag from "@/components/common_components/DefaultProxyAdminTag"; import { AccessGroupEditModal } from "./AccessGroupsModal/AccessGroupEditModal"; const { Title, Text } = Typography; diff --git a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupBaseForm.tsx b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsModal/AccessGroupBaseForm.tsx similarity index 100% rename from ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupBaseForm.tsx rename to ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsModal/AccessGroupBaseForm.tsx diff --git a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupCreateModal.tsx b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsModal/AccessGroupCreateModal.tsx similarity index 100% rename from ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupCreateModal.tsx rename to ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsModal/AccessGroupCreateModal.tsx diff --git a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupEditModal.tsx b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsModal/AccessGroupEditModal.tsx similarity index 100% rename from ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupEditModal.tsx rename to ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsModal/AccessGroupEditModal.tsx diff --git a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsPage.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsPage.test.tsx similarity index 99% rename from ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsPage.test.tsx rename to ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsPage.test.tsx index d50811949f..7c8aaa2b78 100644 --- a/ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsPage.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/access-groups/components/AccessGroupsPage.test.tsx @@ -65,7 +65,7 @@ vi.mock("./AccessGroupsModal/AccessGroupCreateModal", () => ({ ) : null, })); -vi.mock("../common_components/IconActionButton/TableIconActionButtons/TableIconActionButton", () => ({ +vi.mock("@/components/common_components/IconActionButton/TableIconActionButtons/TableIconActionButton", () => ({ default: ({ variant, tooltipText, onClick }: { variant: string; tooltipText: string; onClick: () => void }) => (