diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopModelView.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopModelView.tsx
index c69ba42f182..14979936c29 100644
--- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopModelView.tsx
+++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopModelView.tsx
@@ -1,6 +1,11 @@
+// eslint-disable-next-line litellm-ui/no-banned-ui-imports
import { BarChart } from "@tremor/react";
-import { Segmented } from "antd";
+import {
+ ToggleGroup,
+ ToggleGroupItem,
+} from "@/components/ui/toggle-group";
import { useState } from "react";
+import { cn } from "@/lib/utils";
import { formatNumberWithCommas } from "../../../../utils/dataUtils";
import { DataTable } from "../../../view_logs/table";
@@ -18,18 +23,26 @@ interface TopModelViewProps {
setTopModelsLimit: (limit: number) => void;
}
-export default function TopModelView({ topModels, topModelsLimit, setTopModelsLimit }: TopModelViewProps) {
- const [modelViewMode, setModelViewMode] = useState<"chart" | "table">("table");
+export default function TopModelView({
+ topModels,
+ topModelsLimit,
+ setTopModelsLimit,
+}: TopModelViewProps) {
+ const [modelViewMode, setModelViewMode] = useState<"chart" | "table">(
+ "table",
+ );
const columns = [
{
header: "Model",
accessorKey: "key",
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
cell: (info: any) => info.getValue() || "-",
},
{
header: "Spend (USD)",
accessorKey: "spend",
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
cell: (info: any) => {
const value = info.getValue();
return `$${formatNumberWithCommas(value, 2)}`;
@@ -38,16 +51,27 @@ export default function TopModelView({ topModels, topModelsLimit, setTopModelsLi
{
header: "Successful",
accessorKey: "successful_requests",
- cell: (info: any) => {info.getValue()?.toLocaleString() || 0},
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ cell: (info: any) => (
+
+ {info.getValue()?.toLocaleString() || 0}
+
+ ),
},
{
header: "Failed",
accessorKey: "failed_requests",
- cell: (info: any) => {info.getValue()?.toLocaleString() || 0},
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ cell: (info: any) => (
+
+ {info.getValue()?.toLocaleString() || 0}
+
+ ),
},
{
header: "Tokens",
accessorKey: "tokens",
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
cell: (info: any) => info.getValue()?.toLocaleString() || 0,
},
];
@@ -56,26 +80,42 @@ export default function TopModelView({ topModels, topModelsLimit, setTopModelsLi
return (
<>
-
setTopModelsLimit(value as number)}
- />
+ {
+ if (!v) return;
+ setTopModelsLimit(parseInt(v));
+ }}
+ >
+ {[5, 10, 25, 50].map((n) => (
+
+ {n}
+
+ ))}
+
@@ -85,7 +125,10 @@ export default function TopModelView({ topModels, topModelsLimit, setTopModelsLi
void;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
onAddCredential: (values: any) => void;
uploadProps: UploadProps;
}
-const AddCredentialsModal: React.FC = ({ open, onCancel, onAddCredential, uploadProps }) => {
+const AddCredentialsModal: React.FC = ({
+ open,
+ onCancel,
+ onAddCredential,
+ uploadProps,
+}) => {
const [form] = Form.useForm();
- const [selectedProvider, setSelectedProvider] = useState(Providers.OpenAI);
+ const [selectedProvider, setSelectedProvider] = useState(
+ Providers.OpenAI,
+ );
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const handleSubmit = (values: any) => {
- const filteredValues = Object.entries(values).reduce((acc, [key, value]) => {
- if (value !== "" && value !== undefined && value !== null) {
- acc[key] = value;
- }
- return acc;
- }, {} as any);
+ const filteredValues = Object.entries(values).reduce(
+ (acc, [key, value]) => {
+ if (value !== "" && value !== undefined && value !== null) {
+ acc[key] = value;
+ }
+ return acc;
+ },
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ {} as any,
+ );
onAddCredential(filteredValues);
form.resetFields();
};
+ const handleCancel = () => {
+ onCancel();
+ form.resetFields();
+ };
+
return (
- {
- onCancel();
- form.resetFields();
- }}
- footer={null}
- width={600}
- >
-
-
-
-
- {/* Provider Selection */}
-
- {
- setSelectedProvider(value as Providers);
- form.setFieldValue("custom_llm_provider", value);
- }}
+
-
+
+
-
-
- {/* Modal Footer */}
-
-
- Need Help?
-
-
-
-
-
+ {Object.entries(Providers).map(
+ ([providerEnum, providerDisplayName]) => (
+
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+

{
+ const target = e.target as HTMLImageElement;
+ const parent = target.parentElement;
+ if (parent) {
+ const fallbackDiv = document.createElement("div");
+ fallbackDiv.className =
+ "w-5 h-5 rounded-full bg-muted flex items-center justify-center text-xs";
+ fallbackDiv.textContent =
+ providerDisplayName.charAt(0);
+ parent.replaceChild(fallbackDiv, target);
+ }
+ }}
+ />
+
{providerDisplayName}
+
+
+ ),
+ )}
+
+
+
+
+
+
+
+
+
+
+ Need Help?
+
+
+ Get help on our github
+
+
+
+
+
+
+
-
-
-
+
+
+
);
};
diff --git a/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx b/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx
index 106f82585dd..1aa11a00175 100644
--- a/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx
+++ b/ui/litellm-dashboard/src/components/model_dashboard/ModelSettingsModal/ModelSettingsModal.tsx
@@ -1,10 +1,25 @@
"use client";
-import { ConfigType, useProxyConfig } from "@/app/(dashboard)/hooks/proxyConfig/useProxyConfig";
-import { StoreModelInDBParams, useStoreModelInDB } from "@/app/(dashboard)/hooks/storeModelInDB/useStoreModelInDB";
+import {
+ ConfigType,
+ useProxyConfig,
+} from "@/app/(dashboard)/hooks/proxyConfig/useProxyConfig";
+import {
+ StoreModelInDBParams,
+ useStoreModelInDB,
+} from "@/app/(dashboard)/hooks/storeModelInDB/useStoreModelInDB";
import NotificationsManager from "@/components/molecules/notifications_manager";
import { parseErrorMessage } from "@/components/shared/errorUtils";
-import { Button, Form, Modal, Skeleton, Space, Switch, Typography } from "antd";
+import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { Skeleton } from "@/components/ui/skeleton";
+import { Form, Switch as AntdFormSwitch } from "antd";
import React, { useEffect, useMemo } from "react";
interface ModelSettingsModalProps {
@@ -13,19 +28,25 @@ interface ModelSettingsModalProps {
onSuccess?: () => void;
}
-const ModelSettingsModal: React.FC
= ({ isVisible, onCancel, onSuccess }) => {
+const ModelSettingsModal: React.FC = ({
+ isVisible,
+ onCancel,
+ onSuccess,
+}) => {
const [form] = Form.useForm();
const { mutateAsync, isPending } = useStoreModelInDB();
- const { data: proxyConfigData, isLoading: isLoadingConfig, refetch } = useProxyConfig(ConfigType.GENERAL_SETTINGS);
+ const {
+ data: proxyConfigData,
+ isLoading: isLoadingConfig,
+ refetch,
+ } = useProxyConfig(ConfigType.GENERAL_SETTINGS);
- // Refetch config when modal opens to ensure we have the latest values
useEffect(() => {
if (isVisible) {
refetch();
}
}, [isVisible, refetch]);
- // Compute initial values from fetched config data
const initialValues = useMemo(() => {
if (!proxyConfigData) {
return {
@@ -33,7 +54,9 @@ const ModelSettingsModal: React.FC = ({ isVisible, onCa
};
}
- const storeModelField = proxyConfigData.find(field => field.field_name === 'store_model_in_db');
+ const storeModelField = proxyConfigData.find(
+ (field) => field.field_name === "store_model_in_db",
+ );
return {
store_model_in_db: storeModelField?.field_value ?? false,
@@ -44,16 +67,22 @@ const ModelSettingsModal: React.FC = ({ isVisible, onCa
try {
await mutateAsync(formValues, {
onSuccess: () => {
- NotificationsManager.success("Model storage settings updated successfully");
+ NotificationsManager.success(
+ "Model storage settings updated successfully",
+ );
refetch();
onSuccess?.();
},
onError: (error) => {
- NotificationsManager.fromBackend("Failed to save model storage settings: " + parseErrorMessage(error));
+ NotificationsManager.fromBackend(
+ "Failed to save model storage settings: " + parseErrorMessage(error),
+ );
},
});
} catch (error) {
- NotificationsManager.fromBackend("Failed to save model storage settings: " + parseErrorMessage(error));
+ NotificationsManager.fromBackend(
+ "Failed to save model storage settings: " + parseErrorMessage(error),
+ );
}
};
@@ -62,42 +91,59 @@ const ModelSettingsModal: React.FC = ({ isVisible, onCa
onCancel();
};
+ const storeFieldDescription =
+ proxyConfigData?.find((f) => f.field_name === "store_model_in_db")
+ ?.field_description ||
+ "If enabled, models and config are stored in and loaded from the database.";
+
return (
- Model Settings}
+
+
+
+
);
};