From dd81a7ee9b10f5e5512a190f277cb35f98bd348f Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 29 May 2024 15:50:51 -0700 Subject: [PATCH 1/5] ui - edit user flow --- .../src/components/edit_user.tsx | 119 ++++++++++++++++++ .../src/components/leftnav.tsx | 2 +- .../src/components/view_users.tsx | 94 +++++++++----- 3 files changed, 185 insertions(+), 30 deletions(-) create mode 100644 ui/litellm-dashboard/src/components/edit_user.tsx 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..4ffc14f5b --- /dev/null +++ b/ui/litellm-dashboard/src/components/edit_user.tsx @@ -0,0 +1,119 @@ +import { useState } from 'react'; +import { + Dialog, + DialogPanel, + TextInput, + Button, + Select, + SelectItem, + Text, +} 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(); + + const handleChange = (e) => { + setEditedUser({ ...editedUser, [e.target.name]: e.target.value }); + }; + + const handleSubmit = () => { + onSubmit(editedUser); + onCancel(); + }; + + if (!user) { + return null; + } + + return ( + + + + + {JSON.stringify(user)} + + +
+ <> + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ ); +}; + +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 89a50ad93..a5b803822 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..c631ff510 100644 --- a/ui/litellm-dashboard/src/components/view_users.tsx +++ b/ui/litellm-dashboard/src/components/view_users.tsx @@ -28,8 +28,14 @@ import { userInfoCall } 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,32 @@ 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 handleEditClick = (user) => { + console.log("handleEditClick:", user); + setSelectedUser(user); + setEditModalVisible(true); + }; + + const handleEditCancel = () => { + setEditModalVisible(false); + setSelectedUser(null); + }; + + const handleEditSubmit = async (editedUser) => { + // Call your API to update the user with editedUser data + // ... + + // Update the userData state with the updated user data + const updatedUserData = userData.map((user) => + user.user_id === editedUser.user_id ? editedUser : user + ); + setUserData(updatedUserData); + }; + useEffect(() => { if (!accessToken || !token || !userRole || !userID) { return; @@ -146,7 +176,8 @@ const ViewUserDashboard: React.FC = ({ User Models User Spend ($ USD) User Max Budget ($ USD) - User API Key Aliases + API Keys + @@ -173,9 +204,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 +223,28 @@ const ViewUserDashboard: React.FC = ({ )} {/* {user.key_aliases.filter(key => key !== null).length} Keys */} - {/* { + + + + + { setOpenDialogId(user.user_id) setSelectedItem(user) - }}>View Keys */} - + }}>View Keys + + + { + handleEditClick(user) + }}>View Keys + + { + setOpenDialogId(user.user_id) + setSelectedItem(user) + }}>View Keys + + + ))} @@ -226,30 +277,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"} - -
-
-
*/} ); }; From 425a8fdb3ab8dccccc26cdab1e3de46d76215fe9 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 29 May 2024 16:45:30 -0700 Subject: [PATCH 2/5] feat - edit user --- .../src/components/edit_user.tsx | 51 +++++++++++-------- .../src/components/view_users.tsx | 38 +++++++------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/ui/litellm-dashboard/src/components/edit_user.tsx b/ui/litellm-dashboard/src/components/edit_user.tsx index 4ffc14f5b..d1364c9a4 100644 --- a/ui/litellm-dashboard/src/components/edit_user.tsx +++ b/ui/litellm-dashboard/src/components/edit_user.tsx @@ -34,6 +34,15 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, setEditedUser({ ...editedUser, [e.target.name]: e.target.value }); }; + const handleEditSubmit = async (formValues: Record) => { + // Call API to update team with teamId and values + + console.log("handleEditSubmit:", formValues); + onSubmit(formValues); + onCancel(); + }; + + const handleSubmit = () => { onSubmit(editedUser); onCancel(); @@ -45,15 +54,21 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, return ( - + - + {/* {JSON.stringify(user)} - + */}
= ({ visible, onCancel, user, <> @@ -70,43 +86,38 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, - - - - +
+ Save +
+ diff --git a/ui/litellm-dashboard/src/components/view_users.tsx b/ui/litellm-dashboard/src/components/view_users.tsx index c631ff510..9f955488c 100644 --- a/ui/litellm-dashboard/src/components/view_users.tsx +++ b/ui/litellm-dashboard/src/components/view_users.tsx @@ -24,7 +24,7 @@ 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"; @@ -65,26 +65,29 @@ const ViewUserDashboard: React.FC = ({ const [selectedUser, setSelectedUser] = useState(null); const defaultPageSize = 25; - const handleEditClick = (user) => { - console.log("handleEditClick:", user); - setSelectedUser(user); - setEditModalVisible(true); - }; - const handleEditCancel = () => { setEditModalVisible(false); setSelectedUser(null); }; - const handleEditSubmit = async (editedUser) => { - // Call your API to update the user with editedUser data - // ... - - // Update the userData state with the updated user data - const updatedUserData = userData.map((user) => - user.user_id === editedUser.user_id ? editedUser : user - ); - setUserData(updatedUserData); + 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(() => { @@ -234,7 +237,8 @@ const ViewUserDashboard: React.FC = ({ { - handleEditClick(user) + setSelectedUser(user) + setEditModalVisible(true) }}>View Keys { From 1dfc391a2bc5d5391765a2f71d007c93c38ae5eb Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 29 May 2024 17:28:29 -0700 Subject: [PATCH 3/5] ui - edit interal user flow --- .../src/components/edit_user.tsx | 26 +++++++++++++------ .../src/components/view_users.tsx | 4 +-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/ui/litellm-dashboard/src/components/edit_user.tsx b/ui/litellm-dashboard/src/components/edit_user.tsx index d1364c9a4..425ee0be0 100644 --- a/ui/litellm-dashboard/src/components/edit_user.tsx +++ b/ui/litellm-dashboard/src/components/edit_user.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { Dialog, DialogPanel, @@ -7,6 +7,8 @@ import { Select, SelectItem, Text, + Title, + Subtitle, } from '@tremor/react'; import { @@ -30,23 +32,28 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, 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(); - console.log("handleEditSubmit:", formValues); onSubmit(formValues); onCancel(); }; - const handleSubmit = () => { - onSubmit(editedUser); - onCancel(); - }; if (!user) { return null; @@ -56,16 +63,19 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, {/* {JSON.stringify(user)} */} + + + Edit User {user.user_id} +
= ({ const [selectedUser, setSelectedUser] = useState(null); const defaultPageSize = 25; - const handleEditCancel = () => { - setEditModalVisible(false); + const handleEditCancel = async () => { setSelectedUser(null); + setEditModalVisible(false); }; const handleEditSubmit = async (editedUser: any) => { From 07b1f1135daa34a97e4f95e4d41f0391bfcd6cd0 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Wed, 29 May 2024 17:34:37 -0700 Subject: [PATCH 4/5] fix edit user title --- ui/litellm-dashboard/src/components/edit_user.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ui/litellm-dashboard/src/components/edit_user.tsx b/ui/litellm-dashboard/src/components/edit_user.tsx index 425ee0be0..d7bad4acd 100644 --- a/ui/litellm-dashboard/src/components/edit_user.tsx +++ b/ui/litellm-dashboard/src/components/edit_user.tsx @@ -65,17 +65,11 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, visible={visible} onCancel={handleCancel} footer={null} + title={"Edit User " + user.user_id} width={1000} > - {/* - {JSON.stringify(user)} - - */} - - Edit User {user.user_id} - Date: Wed, 29 May 2024 17:46:30 -0700 Subject: [PATCH 5/5] ui - edit roles --- ui/litellm-dashboard/src/components/edit_user.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui/litellm-dashboard/src/components/edit_user.tsx b/ui/litellm-dashboard/src/components/edit_user.tsx index d7bad4acd..4a822c4d1 100644 --- a/ui/litellm-dashboard/src/components/edit_user.tsx +++ b/ui/litellm-dashboard/src/components/edit_user.tsx @@ -68,8 +68,6 @@ const EditUserModal: React.FC = ({ visible, onCancel, user, title={"Edit User " + user.user_id} width={1000} > - - = ({ visible, onCancel, user, label="User Role" name="user_role" > - + + Proxy Admin (Can create, edit, delete keys, teams) + Proxy Viewer (Can just view spend, cannot created keys, teams) + +