diff --git a/ui/litellm-dashboard/src/components/edit_user.tsx b/ui/litellm-dashboard/src/components/edit_user.tsx new file mode 100644 index 000000000..4a822c4d1 --- /dev/null +++ b/ui/litellm-dashboard/src/components/edit_user.tsx @@ -0,0 +1,136 @@ +import { useEffect, useState } from 'react'; +import { + Dialog, + DialogPanel, + TextInput, + Button, + Select, + SelectItem, + Text, + Title, + Subtitle, +} from '@tremor/react'; + +import { + Button as Button2, + Modal, + Form, + Input, + Select as Select2, + InputNumber, + message, + } from "antd"; + +interface EditUserModalProps { + visible: boolean; + onCancel: () => void; + user: any; + onSubmit: (data: any) => void; +} + +const EditUserModal: React.FC = ({ visible, onCancel, user, onSubmit }) => { + const [editedUser, setEditedUser] = useState(user); + const [form] = Form.useForm(); + + useEffect(() => { + form.resetFields(); + }, [user]); + + const handleChange = (e) => { + setEditedUser({ ...editedUser, [e.target.name]: e.target.value }); + }; + + const handleCancel = async () => { + form.resetFields(); + onCancel(); + }; + + const handleEditSubmit = async (formValues: Record) => { + // Call API to update team with teamId and values + form.resetFields(); + + onSubmit(formValues); + onCancel(); + }; + + + + if (!user) { + return null; + } + + return ( + + +
+ <> + + + + + + + + + Proxy Admin (Can create, edit, delete keys, teams) + Proxy Viewer (Can just view spend, cannot created keys, teams) + + + + + + + + + + + + +
+ Save +
+ + + +
+ + +
+ ); +}; + +export default EditUserModal; \ No newline at end of file diff --git a/ui/litellm-dashboard/src/components/leftnav.tsx b/ui/litellm-dashboard/src/components/leftnav.tsx index 3ba468c7f..a23ebc72c 100644 --- a/ui/litellm-dashboard/src/components/leftnav.tsx +++ b/ui/litellm-dashboard/src/components/leftnav.tsx @@ -79,7 +79,7 @@ const Sidebar: React.FC = ({ {userRole == "Admin" ? ( setPage("users")}> - Users + Internal Users ) : null} diff --git a/ui/litellm-dashboard/src/components/view_users.tsx b/ui/litellm-dashboard/src/components/view_users.tsx index 3faf4c026..b87524bc6 100644 --- a/ui/litellm-dashboard/src/components/view_users.tsx +++ b/ui/litellm-dashboard/src/components/view_users.tsx @@ -24,12 +24,18 @@ import { Icon, TextInput, } from "@tremor/react"; -import { userInfoCall } from "./networking"; +import { userInfoCall, userUpdateUserCall } from "./networking"; import { Badge, BadgeDelta, Button } from "@tremor/react"; import RequestAccess from "./request_model_access"; import CreateUser from "./create_user_button"; +import EditUserModal from "./edit_user"; import Paragraph from "antd/es/skeleton/Paragraph"; -import InformationCircleIcon from "@heroicons/react/outline/InformationCircleIcon"; +import { + PencilAltIcon, + InformationCircleIcon, + TrashIcon, +} from "@heroicons/react/outline"; + interface ViewUserDashboardProps { accessToken: string | null; @@ -55,8 +61,35 @@ const ViewUserDashboard: React.FC = ({ const [currentPage, setCurrentPage] = useState(0); const [openDialogId, setOpenDialogId] = React.useState(null); const [selectedItem, setSelectedItem] = useState(null); + const [editModalVisible, setEditModalVisible] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); const defaultPageSize = 25; + const handleEditCancel = async () => { + setSelectedUser(null); + setEditModalVisible(false); + }; + + const handleEditSubmit = async (editedUser: any) => { + console.log("inside handleEditSubmit:", editedUser); + + if (!accessToken || !token || !userRole || !userID) { + return; + } + + userUpdateUserCall(accessToken, editedUser, userRole); + + if (userData) { + const updatedUserData = userData.map((user) => + user.user_id === editedUser.user_id ? editedUser : user + ); + setUserData(updatedUserData); + } + setSelectedUser(null); + setEditModalVisible(false); + // Close the modal + }; + useEffect(() => { if (!accessToken || !token || !userRole || !userID) { return; @@ -146,7 +179,8 @@ const ViewUserDashboard: React.FC = ({ User Models User Spend ($ USD) User Max Budget ($ USD) - User API Key Aliases + API Keys + @@ -173,9 +207,13 @@ const ViewUserDashboard: React.FC = ({ (key: any) => key !== null ).length > 0 ? ( - {user.key_aliases - .filter((key: any) => key !== null) - .join(", ")} + { + user.key_aliases.filter( + (key: any) => key !== null + ).length + + } +  Keys ) : ( @@ -188,12 +226,29 @@ const ViewUserDashboard: React.FC = ({ )} {/* {user.key_aliases.filter(key => key !== null).length} Keys */} - {/* { + + + + + { setOpenDialogId(user.user_id) setSelectedItem(user) - }}>View Keys */} - + }}>View Keys + + + { + setSelectedUser(user) + setEditModalVisible(true) + }}>View Keys + + { + setOpenDialogId(user.user_id) + setSelectedItem(user) + }}>View Keys + + + ))} @@ -226,30 +281,15 @@ const ViewUserDashboard: React.FC = ({ + {renderPagination()} - {/* { - setOpenDialogId(null); - }} - -> - -
- Key Aliases - - - {selectedItem && selectedItem.key_aliases - ? selectedItem.key_aliases.filter(key => key !== null).length > 0 - ? selectedItem.key_aliases.filter(key => key !== null).join(', ') - : 'No Keys' - : "No Keys"} - -
-
-
*/} ); };