mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-11 22:51:28 +00:00
fix(dashboard): policy attachment delete button and confirm modal
Use a native button for the trash action so clicks work with Tooltip. Replace Modal.confirm with DeleteResourceModal for a consistent confirm step. Update attachment table tests for the new accessible control. Made-with: Cursor
This commit is contained in:
parent
4e12d3c562
commit
8eb5f4eea5
3 changed files with 62 additions and 31 deletions
|
|
@ -111,14 +111,14 @@ describe("AttachmentTable", () => {
|
|||
const attachment = makeAttachment({ attachment_id: "att-del-me1" });
|
||||
const user = userEvent.setup();
|
||||
renderWithProviders(<AttachmentTable {...defaultProps} attachments={[attachment]} />);
|
||||
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(<AttachmentTable {...defaultProps} attachments={[attachment]} isAdmin={false} />);
|
||||
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", () => {
|
||||
|
|
|
|||
|
|
@ -202,12 +202,17 @@ const AttachmentTable: React.FC<AttachmentTableProps> = ({
|
|||
<ImpactPopover attachment={attachment} accessToken={accessToken} />
|
||||
{isAdmin && (
|
||||
<Tooltip title="Delete attachment">
|
||||
<Icon
|
||||
icon={TrashIcon}
|
||||
size="sm"
|
||||
onClick={() => onDeleteClick(attachment.attachment_id)}
|
||||
className="cursor-pointer hover:text-red-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
aria-label="Delete attachment"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDeleteClick(attachment.attachment_id);
|
||||
}}
|
||||
className="inline-flex items-center justify-center p-0 border-0 bg-transparent text-inherit cursor-pointer hover:text-red-500"
|
||||
>
|
||||
<Icon icon={TrashIcon} size="sm" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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<PoliciesPanelProps> = ({
|
|||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [policyToDelete, setPolicyToDelete] = useState<Policy | null>(null);
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [attachmentToDelete, setAttachmentToDelete] = useState<PolicyAttachment | null>(null);
|
||||
const [isAttachmentDeleteModalOpen, setIsAttachmentDeleteModalOpen] = useState(false);
|
||||
const [isDeletingAttachment, setIsDeletingAttachment] = useState(false);
|
||||
const [isGuardrailSelectionModalOpen, setIsGuardrailSelectionModalOpen] = useState(false);
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<any>(null);
|
||||
const [existingGuardrailNames, setExistingGuardrailNames] = useState<Set<string>>(new Set());
|
||||
|
|
@ -166,26 +169,34 @@ const PoliciesPanel: React.FC<PoliciesPanelProps> = ({
|
|||
setPolicyToDelete(null);
|
||||
};
|
||||
|
||||
const handleDeleteAttachment = (attachmentId: string) => {
|
||||
Modal.confirm({
|
||||
title: "Delete Attachment",
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
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<PoliciesPanelProps> = ({
|
|||
<AttachmentTable
|
||||
attachments={attachmentsList}
|
||||
isLoading={isAttachmentsLoading}
|
||||
onDeleteClick={handleDeleteAttachment}
|
||||
onDeleteClick={handleDeleteAttachmentClick}
|
||||
isAdmin={isAdmin}
|
||||
accessToken={accessToken}
|
||||
/>
|
||||
|
||||
<DeleteResourceModal
|
||||
isOpen={isAttachmentDeleteModalOpen}
|
||||
title="Delete Attachment"
|
||||
message="Are you sure you want to delete this policy attachment? This action cannot be undone."
|
||||
resourceInformationTitle="Attachment Information"
|
||||
resourceInformation={[
|
||||
{ label: "Policy", value: attachmentToDelete?.policy_name },
|
||||
{ label: "Attachment ID", value: attachmentToDelete?.attachment_id, code: true },
|
||||
{ label: "Scope", value: attachmentToDelete?.scope || "-" },
|
||||
]}
|
||||
onCancel={handleAttachmentDeleteCancel}
|
||||
onOk={handleAttachmentDeleteConfirm}
|
||||
confirmLoading={isDeletingAttachment}
|
||||
/>
|
||||
|
||||
<AddAttachmentForm
|
||||
visible={isAddAttachmentModalVisible}
|
||||
onClose={() => setIsAddAttachmentModalVisible(false)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue