diff --git a/ui/litellm-dashboard/src/components/policies/attachment_table.test.tsx b/ui/litellm-dashboard/src/components/policies/attachment_table.test.tsx index 4372983b71a..56a59553c09 100644 --- a/ui/litellm-dashboard/src/components/policies/attachment_table.test.tsx +++ b/ui/litellm-dashboard/src/components/policies/attachment_table.test.tsx @@ -111,14 +111,14 @@ describe("AttachmentTable", () => { const attachment = makeAttachment({ attachment_id: "att-del-me1" }); const user = userEvent.setup(); renderWithProviders(); - await user.click(screen.getByRole("button", { name: /TrashIcon/i })); + await user.click(screen.getByRole("button", { name: /delete attachment/i })); expect(defaultProps.onDeleteClick).toHaveBeenCalledWith("att-del-me1"); }); it("should not show the delete icon for non-admins", () => { const attachment = makeAttachment(); renderWithProviders(); - expect(screen.queryByRole("button", { name: /TrashIcon/i })).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /delete attachment/i })).not.toBeInTheDocument(); }); it("should show a truncated attachment ID in the table", () => { diff --git a/ui/litellm-dashboard/src/components/policies/attachment_table.tsx b/ui/litellm-dashboard/src/components/policies/attachment_table.tsx index d9de8378a8a..02a5d9fd992 100644 --- a/ui/litellm-dashboard/src/components/policies/attachment_table.tsx +++ b/ui/litellm-dashboard/src/components/policies/attachment_table.tsx @@ -202,12 +202,17 @@ const AttachmentTable: React.FC = ({ {isAdmin && ( - onDeleteClick(attachment.attachment_id)} - className="cursor-pointer hover:text-red-500" - /> + )} diff --git a/ui/litellm-dashboard/src/components/policies/index.tsx b/ui/litellm-dashboard/src/components/policies/index.tsx index f47b8d78b9d..6f624698dfb 100644 --- a/ui/litellm-dashboard/src/components/policies/index.tsx +++ b/ui/litellm-dashboard/src/components/policies/index.tsx @@ -1,8 +1,8 @@ import React, { useState, useEffect, useCallback } from "react"; import { Button, TabGroup, TabList, Tab, TabPanels, TabPanel } from "@tremor/react"; -import { Modal, Alert } from "antd"; +import { Alert } from "antd"; import MessageManager from "@/components/molecules/message_manager"; -import { ExclamationCircleOutlined, InfoCircleOutlined } from "@ant-design/icons"; +import { InfoCircleOutlined } from "@ant-design/icons"; import { isAdminRole } from "@/utils/roles"; import PolicyTable from "./policy_table"; import PolicyInfoView from "./policy_info"; @@ -57,6 +57,9 @@ const PoliciesPanel: React.FC = ({ const [isDeleting, setIsDeleting] = useState(false); const [policyToDelete, setPolicyToDelete] = useState(null); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [attachmentToDelete, setAttachmentToDelete] = useState(null); + const [isAttachmentDeleteModalOpen, setIsAttachmentDeleteModalOpen] = useState(false); + const [isDeletingAttachment, setIsDeletingAttachment] = useState(false); const [isGuardrailSelectionModalOpen, setIsGuardrailSelectionModalOpen] = useState(false); const [selectedTemplate, setSelectedTemplate] = useState(null); const [existingGuardrailNames, setExistingGuardrailNames] = useState>(new Set()); @@ -166,26 +169,34 @@ const PoliciesPanel: React.FC = ({ setPolicyToDelete(null); }; - const handleDeleteAttachment = (attachmentId: string) => { - Modal.confirm({ - title: "Delete Attachment", - icon: , - content: "Are you sure you want to delete this attachment? This action cannot be undone.", - okText: "Delete", - okType: "danger", - cancelText: "Cancel", - onOk: async () => { - if (!accessToken) return; - try { - await deletePolicyAttachmentCall(accessToken, attachmentId); - MessageManager.success("Attachment deleted successfully"); - fetchAttachments(); - } catch (error) { - console.error("Error deleting attachment:", error); - MessageManager.error("Failed to delete attachment"); - } - }, - }); + const handleDeleteAttachmentClick = (attachmentId: string) => { + const attachment = attachmentsList.find((a) => a.attachment_id === attachmentId) ?? null; + if (!attachment) return; + setAttachmentToDelete(attachment); + setIsAttachmentDeleteModalOpen(true); + }; + + const handleAttachmentDeleteConfirm = async () => { + if (!attachmentToDelete || !accessToken) return; + + setIsDeletingAttachment(true); + try { + await deletePolicyAttachmentCall(accessToken, attachmentToDelete.attachment_id); + MessageManager.success("Attachment deleted successfully"); + await fetchAttachments(); + } catch (error) { + console.error("Error deleting attachment:", error); + MessageManager.error("Failed to delete attachment"); + } finally { + setIsDeletingAttachment(false); + setIsAttachmentDeleteModalOpen(false); + setAttachmentToDelete(null); + } + }; + + const handleAttachmentDeleteCancel = () => { + setIsAttachmentDeleteModalOpen(false); + setAttachmentToDelete(null); }; const handleAttachmentSuccess = () => { @@ -579,11 +590,26 @@ const PoliciesPanel: React.FC = ({ + + setIsAddAttachmentModalVisible(false)}