From f6ba209e03e46c7896539d46c8fb81e01dc75290 Mon Sep 17 00:00:00 2001 From: mateo <277851410+mateo-berri@users.noreply.github.com> Date: Tue, 10 Nov 2026 02:59:56 +0000 Subject: [PATCH] fix(ui): preserve credential actions menu across panel refreshes Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../model_add/CredentialsPanel.test.tsx | 29 +++++++++++++++++++ .../components/model_add/CredentialsPanel.tsx | 10 +++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.test.tsx b/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.test.tsx index a9e98cc5430..9bc3e7c1146 100644 --- a/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.test.tsx +++ b/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.test.tsx @@ -111,6 +111,35 @@ const renderPanel = () => ); describe("CredentialsPanel", () => { + it("keeps an open credential menu usable when the panel refreshes", async () => { + const user = userEvent.setup(); + mockUseAuthorized.mockReturnValue({ accessToken: "test-token", userRole: "Admin" }); + mockUseCredentials.mockReturnValue({ data: { credentials }, isLoading: false, refetch: vi.fn() }); + const client = createQueryClient(); + const panel = ( + + + + ); + const { rerender } = render(panel); + + await user.click(screen.getByTestId("credential-actions-openai-key")); + expect(await screen.findByTestId("credential-action-edit")).toBeInTheDocument(); + mockUseCredentials.mockReturnValue({ + data: { credentials: credentials.map((credential) => ({ ...credential })) }, + isLoading: false, + refetch: vi.fn(), + }); + rerender( + + + , + ); + + await user.click(screen.getByTestId("credential-action-edit")); + expect(screen.getByTestId("credential-modal-edit-submit")).toBeInTheDocument(); + }); + beforeEach(() => { vi.clearAllMocks(); }); diff --git a/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.tsx b/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.tsx index e3738a12bd2..98a25caacff 100644 --- a/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.tsx +++ b/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.tsx @@ -2,7 +2,7 @@ import { useTerminology } from "@/contexts/TerminologyContext"; import { Plus } from "lucide-react"; -import { useState } from "react"; +import { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { useCredentials } from "@/app/(dashboard)/hooks/credentials/useCredentials"; @@ -91,15 +91,15 @@ export default function CredentialsPanel() { } }; - const openEditModal = (credential: CredentialItem) => { + const openEditModal = useCallback((credential: CredentialItem) => { setSelectedCredential(credential); setIsUpdateModalOpen(true); - }; + }, []); - const openDeleteModal = (credential: CredentialItem) => { + const openDeleteModal = useCallback((credential: CredentialItem) => { setCredentialToDelete(credential); setIsDeleteModalOpen(true); - }; + }, []); const closeDeleteModal = () => { setCredentialToDelete(null);