diff --git a/ui/litellm-dashboard/src/components/create_key_button.tsx b/ui/litellm-dashboard/src/components/create_key_button.tsx index b274437145..113952ea82 100644 --- a/ui/litellm-dashboard/src/components/create_key_button.tsx +++ b/ui/litellm-dashboard/src/components/create_key_button.tsx @@ -78,15 +78,13 @@ const CreateKey: React.FC = ({ label="Key Name" name="key_alias" > - -

Optional

+ -

Optional

= ({ ))} -

Optional, defaults to all models

- - -

Optional, defaults Unlimited Budget

-

Optional, defaults to Unlimited TPM

-

Optional, defaults to Unlimited RPM

-

Optional, defaults to never expiring key

-

Optional, defaults to null

) : ( diff --git a/ui/litellm-dashboard/src/components/create_user_button.tsx b/ui/litellm-dashboard/src/components/create_user_button.tsx new file mode 100644 index 0000000000..0e2c564d2d --- /dev/null +++ b/ui/litellm-dashboard/src/components/create_user_button.tsx @@ -0,0 +1,148 @@ +import React, { useState } from "react"; +import { Button, Modal, Form, Input, message, Select, InputNumber } from "antd"; +import { Button as Button2 } from "@tremor/react"; +import { userCreateCall } from "./networking"; + +interface CreateuserProps { + userID: string; + accessToken: string; +} + +const Createuser: React.FC = ({ userID, accessToken }) => { + const [form] = Form.useForm(); + const [isModalVisible, setIsModalVisible] = useState(false); + const [apiuser, setApiuser] = useState(null); + + const handleOk = () => { + setIsModalVisible(false); + form.resetFields(); + }; + + const handleCancel = () => { + setIsModalVisible(false); + setApiuser(null); + form.resetFields(); + }; + + const handleCreate = async (formValues: { user_id: string }) => { + try { + message.info("Making API Call"); + setIsModalVisible(true); + console.log("formValues in create user:", formValues); + const response = await userCreateCall(accessToken, userID, formValues); + console.log("user create Response:", response); + setApiuser(response["key"]); + message.success("API user Created"); + form.resetFields(); + localStorage.removeItem("userData" + userID); + } catch (error) { + console.error("Error creating the user:", error); + } + }; + + return ( +
+ setIsModalVisible(true)}> + + Create New User + + +
+ + + + + + + + {/* */} + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ {apiuser && ( + +

+ Please save this secret user somewhere safe and accessible. For + security reasons, you will not be able to view it again through + your LiteLLM account. If you lose this secret user, you will need to + generate a new one. +

+

{apiuser != null ? `API user: ${apiuser}` : "User being created, this might take 30s"}

+
+ )} +
+ ); +}; + +export default Createuser; diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 4c4fb72d93..250515eeb8 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -69,6 +69,71 @@ export const keyCreateCall = async ( } }; + +export const userCreateCall = async ( + accessToken: string, + userID: string, + formValues: Record // Assuming formValues is an object +) => { + try { + console.log("Form Values in keyCreateCall:", formValues); // Log the form values before making the API call + + // check if formValues.description is not undefined, make it a string and add it to formValues.metadata + if (formValues.description) { + // add to formValues.metadata + if (!formValues.metadata) { + formValues.metadata = {}; + } + // value needs to be in "", valid JSON + formValues.metadata.description = formValues.description; + // remove descrption from formValues + delete formValues.description; + formValues.metadata = JSON.stringify(formValues.metadata); + } + // if formValues.metadata is not undefined, make it a valid dict + if (formValues.metadata) { + console.log("formValues.metadata:", formValues.metadata); + // if there's an exception JSON.parse, show it in the message + try { + formValues.metadata = JSON.parse(formValues.metadata); + } catch (error) { + message.error("Failed to parse metadata: " + error); + throw new Error("Failed to parse metadata: " + error); + } + } + + console.log("Form Values after check:", formValues); + const url = proxyBaseUrl ? `${proxyBaseUrl}/user/new` : `/user/new`; + const response = await fetch(url, { + method: "POST", + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + user_id: userID, + ...formValues, // Include formValues in the request body + }), + }); + + if (!response.ok) { + const errorData = await response.text(); + message.error("Failed to create key: " + errorData); + console.error("Error response from the server:", errorData); + throw new Error("Network response was not ok"); + } + + const data = await response.json(); + console.log("API Response:", data); + return data; + // Handle success - you might want to update some state or UI based on the created key + } catch (error) { + console.error("Failed to create key:", error); + throw error; + } +}; + + export const keyDeleteCall = async (accessToken: String, user_key: String) => { try { const url = proxyBaseUrl ? `${proxyBaseUrl}/key/delete` : `/key/delete`; diff --git a/ui/litellm-dashboard/src/components/view_users.tsx b/ui/litellm-dashboard/src/components/view_users.tsx index 9db7b878e4..0cacb908ae 100644 --- a/ui/litellm-dashboard/src/components/view_users.tsx +++ b/ui/litellm-dashboard/src/components/view_users.tsx @@ -3,6 +3,7 @@ import { Card, Title, Subtitle, Table, TableHead, TableRow, TableCell, TableBody import { userInfoCall } from "./networking"; import { Badge, BadgeDelta, Button } from '@tremor/react'; import RequestAccess from "./request_model_access"; +import CreateUser from "./create_user_button"; interface ViewUserDashboardProps { accessToken: string | null; @@ -55,6 +56,12 @@ const ViewUserDashboard: React.FC = ({ return (
+