Skip to content

[Feature] UI - Access Groups: Table and Details Page#21165

Merged
yuneng-jiang merged 4 commits intomainfrom
litellm_access_group_ui
Feb 14, 2026
Merged

[Feature] UI - Access Groups: Table and Details Page#21165
yuneng-jiang merged 4 commits intomainfrom
litellm_access_group_ui

Conversation

@yuneng-jiang
Copy link
Collaborator

Relevant issues

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem

CI (LiteLLM team)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Type

🆕 New Feature
✅ Test

Changes

Adds an Access Groups management UI to the LiteLLM dashboard. Admins can list, create, edit, and delete access groups from a new "Access Groups" page in the left nav. The UI includes a list page with search and sorting, a details page for each group, and create/edit modals. Introduces DefaultProxyAdminTag to display "Default Proxy Admin" when the user ID is default_user_id. Moves the New badge from Logs to Access Groups. Adds unit tests for AccessGroupsPage, AccessGroupsDetailsPage, and useAccessGroups.

Screenshots

image image image

@vercel
Copy link

vercel bot commented Feb 14, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
litellm Error Error Feb 14, 2026 1:00am

Request Review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 14, 2026

Greptile Overview

Greptile Summary

This PR adds a full Access Groups management UI to the LiteLLM dashboard, including a list page with search/sort/pagination, a details page, and create/edit/delete modals. It also introduces a reusable DefaultProxyAdminTag component and moves the NewBadge from Logs to Access Groups.

The implementation follows established codebase patterns well — hooks use createQueryKeys, proper auth gating, and consistent error handling. Tests are thorough across the hook, list page, and details page.

Issues found:

  • Bug — wrong user ID in "Created by": In AccessGroupsDetailsPage.tsx, line 231 passes accessGroup.updated_by instead of accessGroup.created_by to the DefaultProxyAdminTag for the "Created" row. This is a copy-paste error that will show the wrong user.
  • Bug — name field editable in edit modal but not persisted: The edit modal does not pass isNameDisabled={true} to AccessGroupBaseForm, allowing users to change the group name. However, the backend AccessGroupUpdateRequest does not accept access_group_name, so changes to the name are silently discarded.

Confidence Score: 3/5

  • This PR is generally well-structured but has two bugs that should be fixed before merging: incorrect user attribution in the "Created by" field and a misleading editable name field in the edit modal.
  • Score of 3 reflects that the overall architecture, hook patterns, and test coverage are solid, but two distinct bugs — a copy-paste error showing the wrong user in "Created by" and a silently non-functional name edit — would cause user-facing data integrity and UX issues. Both are straightforward fixes.
  • AccessGroupsDetailsPage.tsx (wrong userId prop on line 231) and AccessGroupEditModal.tsx (missing isNameDisabled prop on line 82)

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsDetailsPage.tsx Bug: "Created by" section uses updated_by instead of created_by on line 231, displaying incorrect user attribution.
ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupEditModal.tsx Bug: Missing isNameDisabled prop — users can edit the name field, but the backend ignores access_group_name in the update request, so the change silently doesn't persist.
ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsPage.tsx Main access groups list page with search, sorting, pagination, and CRUD actions. Well-structured with TanStack table integration and proper Antd bridge pattern.
ui/litellm-dashboard/src/app/(dashboard)/hooks/accessGroups/useAccessGroups.ts Standard list query hook following established patterns. Uses proper auth gating, query key factory, and error handling.
ui/litellm-dashboard/src/app/(dashboard)/hooks/accessGroups/useEditAccessGroup.ts Edit mutation hook includes access_group_name in AccessGroupUpdateParams, but the backend does not accept this field. Sending it is harmless but misleading.
ui/litellm-dashboard/src/components/AccessGroups/AccessGroupsModal/AccessGroupBaseForm.tsx Shared form component with tabbed layout for group info, models, MCP servers, and agents. Has the isNameDisabled prop designed for edit mode but not currently utilized by the edit modal.
ui/litellm-dashboard/src/components/leftnav.tsx Adds "Access Groups" nav item with NewBadge under admin roles. Removes NewBadge from Logs. Clean changes.
ui/litellm-dashboard/src/app/page.tsx Adds routing for the "access-groups" page to render AccessGroupsPage. Follows existing conditional rendering pattern.

Flowchart

flowchart TD
    subgraph LeftNav
        LN[Left Nav] -->|click 'Access Groups'| AG_PAGE
    end

    subgraph AccessGroupsPage
        AG_PAGE[AccessGroupsPage] -->|useAccessGroups| FETCH_LIST["GET /v1/access_group"]
        AG_PAGE -->|click group ID| DETAIL[AccessGroupDetail]
        AG_PAGE -->|click 'Create'| CREATE_MODAL[AccessGroupCreateModal]
        AG_PAGE -->|click 'Delete'| DELETE_MODAL[DeleteResourceModal]
    end

    subgraph AccessGroupDetail
        DETAIL -->|useAccessGroupDetails| FETCH_DETAIL["GET /v1/access_group/:id"]
        DETAIL -->|click 'Edit'| EDIT_MODAL[AccessGroupEditModal]
    end

    subgraph Modals
        CREATE_MODAL -->|AccessGroupBaseForm| BASE_FORM[AccessGroupBaseForm]
        EDIT_MODAL -->|AccessGroupBaseForm| BASE_FORM
        CREATE_MODAL -->|useCreateAccessGroup| POST_CREATE["POST /v1/access_group"]
        EDIT_MODAL -->|useEditAccessGroup| PUT_EDIT["PUT /v1/access_group/:id"]
        DELETE_MODAL -->|useDeleteAccessGroup| DEL["DELETE /v1/access_group/:id"]
    end

    subgraph CacheInvalidation
        POST_CREATE -->|invalidate| CACHE["React Query Cache"]
        PUT_EDIT -->|invalidate| CACHE
        DEL -->|invalidate| CACHE
        CACHE -->|refetch| FETCH_LIST
    end
Loading

Last reviewed commit: ca2ce4a

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

19 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +226 to +234
<Descriptions.Item label="Created">
{new Date(accessGroup.created_at).toLocaleString()}
{accessGroup.created_by && (
<Text>
&nbsp;{"by"}&nbsp;
<DefaultProxyAdminTag userId={accessGroup.updated_by} />
</Text>
)}
</Descriptions.Item>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong user ID for "Created by"

The "Created" description item checks accessGroup.created_by on line 228 to decide whether to show the "by" label, but then passes accessGroup.updated_by to DefaultProxyAdminTag on line 231. This means the "Created by" field displays the updater's identity instead of the creator's.

Suggested change
<Descriptions.Item label="Created">
{new Date(accessGroup.created_at).toLocaleString()}
{accessGroup.created_by && (
<Text>
&nbsp;{"by"}&nbsp;
<DefaultProxyAdminTag userId={accessGroup.updated_by} />
</Text>
)}
</Descriptions.Item>
<Descriptions.Item label="Created">
{new Date(accessGroup.created_at).toLocaleString()}
{accessGroup.created_by && (
<Text>
&nbsp;{"by"}&nbsp;
<DefaultProxyAdminTag userId={accessGroup.created_by} />
</Text>
)}
</Descriptions.Item>

confirmLoading={editMutation.isPending}
destroyOnClose
>
<AccessGroupBaseForm form={form} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name field editable but backend ignores it

The edit modal renders AccessGroupBaseForm without passing isNameDisabled={true}. The base form has this prop specifically for this purpose, but it's not used here. The backend AccessGroupUpdateRequest does not include access_group_name — the field will be silently ignored on the server. This gives users the misleading impression they can rename access groups when the change won't actually persist.

Suggested change
<AccessGroupBaseForm form={form} />
<AccessGroupBaseForm form={form} isNameDisabled />

@yuneng-jiang yuneng-jiang merged commit 3ebafc4 into main Feb 14, 2026
11 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant