diff --git a/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx b/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx
index e9c4500205b..a850fa8d2df 100644
--- a/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx
@@ -1,68 +1,193 @@
-import { describe, it, expect, vi } from "vitest";
+import { describe, it, expect, vi, beforeEach } from "vitest";
import userEvent from "@testing-library/user-event";
-import { renderWithProviders } from "../../../tests/test-utils";
+import { renderWithProviders, screen } from "../../../tests/test-utils";
import DeleteResourceModal from "./DeleteResourceModal";
describe("DeleteResourceModal", () => {
+ const mockOnCancel = vi.fn();
+ const mockOnOk = vi.fn();
+
const defaultProps = {
isOpen: true,
title: "Delete Resource",
message: "Are you sure you want to delete this resource?",
- onCancel: vi.fn(),
- onOk: vi.fn(),
+ onCancel: mockOnCancel,
+ onOk: mockOnOk,
confirmLoading: false,
};
- it("renders", () => {
- const { getByText } = renderWithProviders();
- expect(getByText("Delete Resource")).toBeInTheDocument();
+ beforeEach(() => {
+ vi.clearAllMocks();
});
- it("renders the title correctly", () => {
- const { getByText } = renderWithProviders();
- expect(getByText("Custom Delete Title")).toBeInTheDocument();
+ it("should render", () => {
+ renderWithProviders();
+ expect(screen.getByText("Delete Resource")).toBeInTheDocument();
});
- it("renders the message correctly", () => {
- const { getByText } = renderWithProviders(
- ,
- );
- expect(getByText("This is a custom message")).toBeInTheDocument();
+ it("should render the title correctly", () => {
+ renderWithProviders();
+ expect(screen.getByText("Custom Delete Title")).toBeInTheDocument();
});
- it("renders the resourceInformation and resourceInformationTitle correctly", () => {
+ it("should render the message correctly", () => {
+ renderWithProviders();
+ expect(screen.getByText("This is a custom message")).toBeInTheDocument();
+ });
+
+ it("should render alert message when provided", () => {
+ renderWithProviders();
+ expect(screen.getByText("Warning: This action cannot be undone")).toBeInTheDocument();
+ });
+
+ it("should not render alert message when not provided", () => {
+ renderWithProviders();
+ expect(screen.queryByRole("alert")).not.toBeInTheDocument();
+ });
+
+ it("should render resourceInformation and resourceInformationTitle correctly", () => {
const resourceInformation = [
{ label: "Name", value: "Test Resource" },
{ label: "ID", value: "123" },
];
- const { getByText } = renderWithProviders(
+ renderWithProviders(
,
);
- expect(getByText("Resource Details")).toBeInTheDocument();
- expect(getByText("Name")).toBeInTheDocument();
- expect(getByText("Test Resource")).toBeInTheDocument();
- expect(getByText("ID")).toBeInTheDocument();
- expect(getByText("123")).toBeInTheDocument();
+ expect(screen.getByText("Resource Details")).toBeInTheDocument();
+ expect(screen.getByText("Name")).toBeInTheDocument();
+ expect(screen.getByText("Test Resource")).toBeInTheDocument();
+ expect(screen.getByText("ID")).toBeInTheDocument();
+ expect(screen.getByText("123")).toBeInTheDocument();
});
- it("disables the delete button when requiredConfirmation is not in the input (empty state)", async () => {
- const { getByRole } = renderWithProviders();
- const deleteButton = getByRole("button", { name: /delete/i });
+ it("should render dash for null or undefined resource information values", () => {
+ const resourceInformation = [
+ { label: "Name", value: null },
+ { label: "ID", value: undefined },
+ { label: "Status", value: "Active" },
+ ];
+ renderWithProviders(
+ ,
+ );
+ expect(screen.getAllByText("-")).toHaveLength(2);
+ expect(screen.getByText("Active")).toBeInTheDocument();
+ });
+
+ it("should render resource information with number values", () => {
+ const resourceInformation = [{ label: "Count", value: 42 }];
+ renderWithProviders();
+ expect(screen.getByText("42")).toBeInTheDocument();
+ });
+
+ it("should call onCancel when cancel button is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+ const cancelButton = screen.getByRole("button", { name: "Cancel" });
+ await user.click(cancelButton);
+ expect(mockOnCancel).toHaveBeenCalledTimes(1);
+ });
+
+ it("should call onOk when delete button is clicked", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+ const deleteButton = screen.getByRole("button", { name: /delete/i });
+ await user.click(deleteButton);
+ expect(mockOnOk).toHaveBeenCalledTimes(1);
+ });
+
+ it("should disable delete button when requiredConfirmation is not entered", () => {
+ renderWithProviders();
+ const deleteButton = screen.getByRole("button", { name: /delete/i });
expect(deleteButton).toBeDisabled();
});
- it("enables the delete button when the input equals requiredConfirmation", async () => {
+ it("should disable delete button when requiredConfirmation input does not match exactly", async () => {
const user = userEvent.setup();
- const { getByRole, getByPlaceholderText } = renderWithProviders(
- ,
- );
- const input = getByPlaceholderText("DELETE");
+ renderWithProviders();
+ const input = screen.getByPlaceholderText("DELETE");
+ await user.type(input, "DELET");
+ const deleteButton = screen.getByRole("button", { name: /delete/i });
+ expect(deleteButton).toBeDisabled();
+ });
+
+ it("should enable delete button when requiredConfirmation input matches exactly", async () => {
+ const user = userEvent.setup();
+ renderWithProviders();
+ const input = screen.getByPlaceholderText("DELETE");
await user.type(input, "DELETE");
- const deleteButton = getByRole("button", { name: /delete/i });
+ const deleteButton = screen.getByRole("button", { name: /delete/i });
expect(deleteButton).not.toBeDisabled();
});
+
+ it("should reset requiredConfirmation input when modal opens", async () => {
+ const user = userEvent.setup();
+ const { rerender } = renderWithProviders(
+ ,
+ );
+ const input = screen.getByPlaceholderText("DELETE");
+ await user.type(input, "DELETE");
+ expect(input).toHaveValue("DELETE");
+
+ rerender();
+ rerender();
+
+ const newInput = screen.getByPlaceholderText("DELETE");
+ expect(newInput).toHaveValue("");
+ });
+
+ it("should display deleting text on delete button when confirmLoading is true", () => {
+ renderWithProviders();
+ expect(screen.getByText("Deleting...")).toBeInTheDocument();
+ });
+
+ it("should display delete text on delete button when confirmLoading is false", () => {
+ renderWithProviders();
+ const deleteButton = screen.getByRole("button", { name: /delete/i });
+ expect(deleteButton).toBeInTheDocument();
+ expect(screen.queryByText("Deleting...")).not.toBeInTheDocument();
+ });
+
+ it("should disable delete button when confirmLoading is true", () => {
+ renderWithProviders();
+ const deleteButton = screen.getByText("Deleting...").closest("button");
+ expect(deleteButton).toBeDisabled();
+ });
+
+ it("should disable cancel button when confirmLoading is true", () => {
+ renderWithProviders();
+ const cancelButton = screen.getByRole("button", { name: "Cancel" });
+ expect(cancelButton).toBeDisabled();
+ });
+
+ it("should disable delete button when confirmLoading is true even if requiredConfirmation matches", async () => {
+ const user = userEvent.setup();
+ renderWithProviders(
+ ,
+ );
+ const input = screen.getByPlaceholderText("DELETE");
+ await user.type(input, "DELETE");
+ const deleteButton = screen.getByText("Deleting...").closest("button");
+ expect(deleteButton).toBeDisabled();
+ });
+
+ it("should render required confirmation prompt with correct text", () => {
+ renderWithProviders();
+ expect(screen.getByText(/Type/i)).toBeInTheDocument();
+ expect(screen.getByText("DELETE")).toBeInTheDocument();
+ expect(screen.getByText(/to confirm deletion/i)).toBeInTheDocument();
+ });
+
+ it("should not render required confirmation section when not provided", () => {
+ renderWithProviders();
+ expect(screen.queryByPlaceholderText("DELETE")).not.toBeInTheDocument();
+ });
+
+ it("should not render modal when isOpen is false", () => {
+ renderWithProviders();
+ expect(screen.queryByText("Delete Resource")).not.toBeInTheDocument();
+ });
});
diff --git a/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.tsx b/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.tsx
index 93de859dd7d..26419585a4c 100644
--- a/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.tsx
+++ b/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.tsx
@@ -1,4 +1,5 @@
-import { Alert, Descriptions, Input, Modal, Typography } from "antd";
+import { Alert, Card, Descriptions, Input, Modal, Typography, theme } from "antd";
+import { ExclamationCircleOutlined } from "@ant-design/icons";
import React, { useState, useEffect } from "react";
interface DeleteResourceModalProps {
@@ -32,6 +33,7 @@ export default function DeleteResourceModal({
requiredConfirmation,
}: DeleteResourceModalProps) {
const { Title, Text } = Typography;
+ const { token } = theme.useToken();
const [requiredConfirmationInput, setRequiredConfirmationInput] = useState("");
useEffect(() => {
@@ -57,25 +59,36 @@ export default function DeleteResourceModal({
>
{alertMessage &&
}
-
-
- {resourceInformationTitle}
-
+
{resourceInformation &&
resourceInformation.map(({ label, value, ...textProps }) => (
- {label}}>
+ {label}}>
{value ?? "-"}
))}
-
+
{message}
{requiredConfirmation && (
-
-
+
+
Type
{requiredConfirmation}
@@ -86,7 +99,8 @@ export default function DeleteResourceModal({
value={requiredConfirmationInput}
onChange={(e) => setRequiredConfirmationInput(e.target.value)}
placeholder={requiredConfirmation}
- className="rounded-md text-base border-gray-200"
+ className="rounded-md"
+ prefix={}
autoFocus
/>