From fb9fb3467d7f076bc9b623fee255a376db7ba255 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Sat, 26 Oct 2024 11:41:37 +0400 Subject: [PATCH] (UI) Delete Internal Users on Admin UI (#6442) * add /user/delete call * ui show modal asking if you want to delete user * fix delete user modal --- .../src/components/networking.tsx | 33 +++++++ .../src/components/view_users.tsx | 87 +++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index fb959d380..874c522d3 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -521,6 +521,39 @@ export const keyDeleteCall = async (accessToken: String, user_key: String) => { } }; +export const userDeleteCall = async (accessToken: string, userIds: string[]) => { + try { + const url = proxyBaseUrl ? `${proxyBaseUrl}/user/delete` : `/user/delete`; + console.log("in userDeleteCall:", userIds); + + const response = await fetch(url, { + method: "POST", + headers: { + [globalLitellmHeaderName]: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + user_ids: userIds, + }), + }); + + if (!response.ok) { + const errorData = await response.text(); + handleError(errorData); + throw new Error("Network response was not ok"); + } + + const data = await response.json(); + console.log(data); + //message.success("User(s) Deleted"); + return data; + } catch (error) { + console.error("Failed to delete user(s):", error); + throw error; + } +}; + + export const teamDeleteCall = async (accessToken: String, teamID: String) => { try { const url = proxyBaseUrl ? `${proxyBaseUrl}/team/delete` : `/team/delete`; diff --git a/ui/litellm-dashboard/src/components/view_users.tsx b/ui/litellm-dashboard/src/components/view_users.tsx index e3be74706..58374a0c8 100644 --- a/ui/litellm-dashboard/src/components/view_users.tsx +++ b/ui/litellm-dashboard/src/components/view_users.tsx @@ -26,6 +26,7 @@ import { } from "@tremor/react"; import { message } from "antd"; +import { Modal } from "antd"; import { userInfoCall, @@ -43,6 +44,8 @@ import { TrashIcon, } from "@heroicons/react/outline"; +import { userDeleteCall } from "./networking"; + interface ViewUserDashboardProps { accessToken: string | null; token: string | null; @@ -84,11 +87,42 @@ const ViewUserDashboard: React.FC = ({ const [selectedItem, setSelectedItem] = useState(null); const [editModalVisible, setEditModalVisible] = useState(false); const [selectedUser, setSelectedUser] = useState(null); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [userToDelete, setUserToDelete] = useState(null); const [possibleUIRoles, setPossibleUIRoles] = useState< Record> >({}); const defaultPageSize = 25; + const handleDelete = (userId: string) => { + setUserToDelete(userId); + setIsDeleteModalOpen(true); + }; + + const confirmDelete = async () => { + if (userToDelete && accessToken) { + try { + await userDeleteCall(accessToken, [userToDelete]); + message.success("User deleted successfully"); + // Update the user list after deletion + if (userData) { + const updatedUserData = userData.filter(user => user.user_id !== userToDelete); + setUserData(updatedUserData); + } + } catch (error) { + console.error("Error deleting user:", error); + message.error("Failed to delete user"); + } + } + setIsDeleteModalOpen(false); + setUserToDelete(null); + }; + + const cancelDelete = () => { + setIsDeleteModalOpen(false); + setUserToDelete(null); + }; + const handleEditCancel = async () => { setSelectedUser(null); setEditModalVisible(false); @@ -272,6 +306,12 @@ const ViewUserDashboard: React.FC = ({ > View Keys + handleDelete(user.user_id)} + > + Delete + ))} @@ -293,6 +333,53 @@ const ViewUserDashboard: React.FC = ({ user={selectedUser} onSubmit={handleEditSubmit} /> + {isDeleteModalOpen && ( +
+
+ + + {/* Modal Panel */} + + + {/* Confirmation Modal Content */} +
+
+
+
+

+ Delete User +

+
+

+ Are you sure you want to delete this user? +

+

+ User ID: {userToDelete} +

+
+
+
+
+
+ + +
+
+
+
+ )} {renderPagination()}