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..d686ed7c783 100644
--- a/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.test.tsx
+++ b/ui/litellm-dashboard/src/components/model_add/CredentialsPanel.test.tsx
@@ -115,6 +115,35 @@ describe("CredentialsPanel", () => {
vi.clearAllMocks();
});
+ it("keeps credential actions usable when the panel rerenders with refreshed data", 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")).toBeVisible();
+ 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();
+ });
+
it("renders the Add Credential button for an admin", () => {
mockUseAuthorized.mockReturnValue({ accessToken: "test-token", userRole: "Admin" });
mockUseCredentials.mockReturnValue({ data: { credentials: [] }, isLoading: false, refetch: vi.fn() });
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);