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);