[Feature] UI - Projects: Add Project Details Page#22360
Conversation
- Add ProjectDetailsPage with header, details card, spend/budget progress, model spend bar chart, keys placeholder, and team info card - Refactor CreateProjectModal into base form pattern (ProjectBaseForm) shared between Create and Edit flows - Add EditProjectModal with pre-filled form data from backend - Add useProjectDetails and useUpdateProject hooks - Add duplicate key validation for model limits and metadata - Wire project ID click in table to navigate to detail view - Move pagination inline with search bar Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR adds a Project Details page to the UI, following the Access Groups detail page pattern. It introduces a detail view with project info, spend/budget visualization (with tremor
Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useProjectDetails.ts | New hook for fetching project details with React Query. Clean implementation using projectKeys.detail(), seeding from list cache via initialData. No issues found. |
| ui/litellm-dashboard/src/app/(dashboard)/hooks/projects/useUpdateProject.ts | New mutation hook for updating projects via POST to /project/update. Follows existing codebase patterns with proper cache invalidation. No issues found. |
| ui/litellm-dashboard/src/components/Projects/ProjectDetailsPage.tsx | New project details page with header, spend/budget display, team info card, and edit modal. Fragile team data type-casting via as unknown as but follows existing patterns in the codebase. |
| ui/litellm-dashboard/src/components/Projects/ProjectModals/CreateProjectModal.tsx | Refactored to use shared ProjectBaseForm and buildProjectApiParams. Uses deprecated destroyOnClose instead of destroyOnHidden. |
| ui/litellm-dashboard/src/components/Projects/ProjectModals/EditProjectModal.tsx | New edit modal with a bug: reads model RPM/TPM limits from project.metadata instead of the top-level project.model_rpm_limit/project.model_tpm_limit fields, causing limits to not pre-fill on edit. |
| ui/litellm-dashboard/src/components/Projects/ProjectModals/ProjectBaseForm.tsx | Shared form component extracted from CreateProjectModal with team sync, model fetching, duplicate key validation. Clean refactor with no issues. |
| ui/litellm-dashboard/src/components/Projects/ProjectModals/projectFormUtils.ts | Utility to transform form values to API params. Shared by create and update flows. Correctly sends model limits as top-level fields. |
| ui/litellm-dashboard/src/components/Projects/ProjectsPage.tsx | Added project detail navigation via selectedProjectId state, moved pagination outside table for a cleaner layout, added team loading spinner. No issues found. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[ProjectsPage] -->|click project ID| B[ProjectDetail]
B -->|useProjectDetails| C[GET /project/info]
B -->|useTeam| D[GET /team/info]
B -->|click Edit| E[EditProjectModal]
E -->|ProjectBaseForm| F[Shared Form Component]
E -->|useUpdateProject| G[POST /project/update]
G -->|invalidateQueries| H[Refresh project cache]
A -->|click Create| I[CreateProjectModal]
I -->|ProjectBaseForm| F
I -->|useCreateProject| J[POST /project/new]
J -->|invalidateQueries| H
F -->|buildProjectApiParams| K[projectFormUtils]
Last reviewed commit: 061703a
| const metadataObj = (project.metadata ?? {}) as Record<string, unknown>; | ||
| const rpmLimits = (metadataObj.model_rpm_limit ?? {}) as Record<string, number>; | ||
| const tpmLimits = (metadataObj.model_tpm_limit ?? {}) as Record<string, number>; |
There was a problem hiding this comment.
Model limits read from wrong field
The edit form reads model_rpm_limit and model_tpm_limit from project.metadata, but the backend stores these as top-level fields on LiteLLM_ProjectTable (see litellm/proxy/_types.py:2662-2663), not inside metadata. The ProjectResponse type also defines them at the top level (model_rpm_limit, model_tpm_limit).
As a result, when editing an existing project the model-specific RPM/TPM limits will always appear empty in the form, even if the project has limits set.
| const metadataObj = (project.metadata ?? {}) as Record<string, unknown>; | |
| const rpmLimits = (metadataObj.model_rpm_limit ?? {}) as Record<string, number>; | |
| const tpmLimits = (metadataObj.model_tpm_limit ?? {}) as Record<string, number>; | |
| const rpmLimits = (project.model_rpm_limit ?? {}) as Record<string, number>; | |
| const tpmLimits = (project.model_tpm_limit ?? {}) as Record<string, number>; |
ui/litellm-dashboard/src/components/Projects/ProjectModals/CreateProjectModal.tsx
Outdated
Show resolved
Hide resolved
…ateProjectModal.tsx Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Relevant issues
Summary
Problem
The Projects page only had a list view with no way to inspect or edit individual project details.
Fix
Added a Project Details page following the Access Groups detail page pattern, with:
Testing
Type
🆕 New Feature
🧹 Refactoring