diff --git a/ui/litellm-dashboard/.eslintrc.json b/ui/litellm-dashboard/.eslintrc.json index a7f8aec6be7..a12b1aa7a88 100644 --- a/ui/litellm-dashboard/.eslintrc.json +++ b/ui/litellm-dashboard/.eslintrc.json @@ -77,6 +77,7 @@ "src/components/DeletedKeysPage/DeletedKeysTable/DeletedKeysTable.tsx", "src/components/AIHub/UsefulLinksManagement.tsx", "src/components/vector_store_management/VectorStoreTable.tsx", + "src/components/vector_store_management/vector_store_info.tsx", "src/components/permissions/VectorStorePermissions.tsx", "src/components/permissions/AgentPermissions.tsx", "src/components/permissions/MCPServerPermissions.tsx", diff --git a/ui/litellm-dashboard/src/components/vector_store_management/vector_store_info.tsx b/ui/litellm-dashboard/src/components/vector_store_management/vector_store_info.tsx index 92ed17715c6..18de286aa7b 100644 --- a/ui/litellm-dashboard/src/components/vector_store_management/vector_store_info.tsx +++ b/ui/litellm-dashboard/src/components/vector_store_management/vector_store_info.tsx @@ -1,11 +1,33 @@ -import React, { useState, useEffect } from "react"; -import { Card, Text, Title, Button, Badge, TabGroup, TabList, Tab, TabPanels, TabPanel } from "@tremor/react"; -import { Form, Input, Select as Select2, Tooltip, Button as AntButton } from "antd"; -import { InfoCircleOutlined } from "@ant-design/icons"; -import { ArrowLeftIcon } from "@heroicons/react/outline"; -import { vectorStoreInfoCall, vectorStoreUpdateCall, credentialListCall, CredentialItem } from "../networking"; +import React, { useCallback, useState, useEffect } from "react"; +// eslint-disable-next-line litellm-ui/no-banned-ui-imports +import { TabGroup, TabList, Tab, TabPanels, TabPanel } from "@tremor/react"; +import { + Form, + Input as AntInput, + Select as Select2, +} from "antd"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { ArrowLeft, Info } from "lucide-react"; +import { + vectorStoreInfoCall, + vectorStoreUpdateCall, + credentialListCall, + CredentialItem, +} from "../networking"; import { VectorStore } from "./types"; -import { Providers, providerLogoMap, provider_map } from "../provider_info_helpers"; +import { + Providers, + providerLogoMap, + provider_map, +} from "../provider_info_helpers"; import VectorStoreTester from "./VectorStoreTester"; import NotificationsManager from "../molecules/notifications_manager"; @@ -29,9 +51,8 @@ const VectorStoreInfoView: React.FC = ({ const [isEditing, setIsEditing] = useState(editVectorStore); const [metadataString, setMetadataString] = useState("{}"); const [credentials, setCredentials] = useState([]); - const [activeTab, setActiveTab] = useState(editVectorStore ? "details" : "details"); - const fetchVectorStoreDetails = async () => { + const fetchVectorStoreDetails = useCallback(async () => { if (!accessToken) return; try { const response = await vectorStoreInfoCall(accessToken, vectorStoreId); @@ -58,26 +79,28 @@ const VectorStoreInfoView: React.FC = ({ } } catch (error) { console.error("Error fetching vector store details:", error); - NotificationsManager.fromBackend("Error fetching vector store details: " + error); + NotificationsManager.fromBackend( + "Error fetching vector store details: " + error, + ); } - }; + }, [accessToken, editVectorStore, form, vectorStoreId]); - const fetchCredentials = async () => { + const fetchCredentials = useCallback(async () => { if (!accessToken) return; try { const response = await credentialListCall(accessToken); - console.log("List credentials response:", response); setCredentials(response.credentials || []); } catch (error) { console.error("Error fetching credentials:", error); } - }; + }, [accessToken]); useEffect(() => { fetchVectorStoreDetails(); fetchCredentials(); - }, [vectorStoreId, accessToken]); + }, [fetchVectorStoreDetails, fetchCredentials]); + // eslint-disable-next-line @typescript-eslint/no-explicit-any const handleSave = async (values: any) => { if (!accessToken) return; try { @@ -85,7 +108,8 @@ const VectorStoreInfoView: React.FC = ({ let metadata = {}; try { metadata = metadataString ? JSON.parse(metadataString) : {}; - } catch (e) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (_e) { NotificationsManager.fromBackend("Invalid JSON in metadata field"); return; } @@ -116,13 +140,20 @@ const VectorStoreInfoView: React.FC = ({
- - Vector Store ID: {vectorStoreDetails.vector_store_id} - {vectorStoreDetails.vector_store_description || "No description"} +

+ Vector Store ID: {vectorStoreDetails.vector_store_id} +

+

+ {vectorStoreDetails.vector_store_description || "No description"} +

- {is_admin && !isEditing && } + {is_admin && !isEditing && ( + + )}
@@ -137,33 +168,56 @@ const VectorStoreInfoView: React.FC = ({ {isEditing ? (
- Edit Vector Store +

Edit Vector Store

- -
+ + - + - - + + - - + + Provider{" "} - - - + + + + + + + Select the provider for this vector store + + + } name="custom_llm_provider" @@ -174,22 +228,31 @@ const VectorStoreInfoView: React.FC = ({ // Currently only showing Bedrock since it's the only supported provider if (providerEnum === "Bedrock") { return ( - +
+ {/* eslint-disable-next-line @next/next/no-img-element */} {`${providerEnum} { - // Create a div with provider initial as fallback - const target = e.target as HTMLImageElement; + const target = + e.target as HTMLImageElement; const parent = target.parentElement; if (parent) { - const fallbackDiv = document.createElement("div"); + const fallbackDiv = + document.createElement("div"); fallbackDiv.className = - "w-5 h-5 rounded-full bg-gray-200 flex items-center justify-center text-xs"; - fallbackDiv.textContent = providerDisplayName.charAt(0); - parent.replaceChild(fallbackDiv, target); + "w-5 h-5 rounded-full bg-muted flex items-center justify-center text-xs"; + fallbackDiv.textContent = + providerDisplayName.charAt(0); + parent.replaceChild( + fallbackDiv, + target, + ); } }} /> @@ -203,20 +266,25 @@ const VectorStoreInfoView: React.FC = ({ - {/* Credentials */}
- - Either select existing credentials OR enter provider credentials below - +

+ Either select existing credentials OR enter provider + credentials below +

- + - (option?.label ?? "").toLowerCase().includes(input.toLowerCase()) + (option?.label ?? "") + .toLowerCase() + .includes(input.toLowerCase()) } options={[ { value: null, label: "None" }, @@ -230,22 +298,31 @@ const VectorStoreInfoView: React.FC = ({
-
- OR -
+
+ + OR + +
Metadata{" "} - - - + + + + + + + JSON metadata for the vector store + + + } > - setMetadataString(e.target.value)} @@ -254,10 +331,14 @@ const VectorStoreInfoView: React.FC = ({
- setIsEditing(false)}>Cancel - - Save Changes - + +
@@ -265,40 +346,50 @@ const VectorStoreInfoView: React.FC = ({ ) : (
- Vector Store Details - {is_admin && } +

+ Vector Store Details +

+ {is_admin && ( + + )}
- +
- ID - {vectorStoreDetails.vector_store_id} +

ID

+

{vectorStoreDetails.vector_store_id}

- Name - {vectorStoreDetails.vector_store_name || "-"} +

Name

+

{vectorStoreDetails.vector_store_name || "-"}

- Description - {vectorStoreDetails.vector_store_description || "-"} +

Description

+

+ {vectorStoreDetails.vector_store_description || "-"} +

- Provider +

Provider

{(() => { - const provider = vectorStoreDetails.custom_llm_provider || "bedrock"; + const provider = + vectorStoreDetails.custom_llm_provider || "bedrock"; const { displayName, logo } = (() => { - // Find the enum key by matching provider_map values const enumKey = Object.keys(provider_map).find( - (key) => provider_map[key].toLowerCase() === provider.toLowerCase(), + (key) => + provider_map[key].toLowerCase() === + provider.toLowerCase(), ); if (!enumKey) { return { displayName: provider, logo: "" }; } - // Get the display name from Providers enum and logo from map - const displayName = Providers[enumKey as keyof typeof Providers]; + const displayName = + Providers[enumKey as keyof typeof Providers]; const logo = providerLogoMap[displayName]; return { displayName, logo }; @@ -307,46 +398,60 @@ const VectorStoreInfoView: React.FC = ({ return ( <> {logo && ( + // eslint-disable-next-line @next/next/no-img-element {`${displayName} { - const target = e.target as HTMLImageElement; + const target = + e.target as HTMLImageElement; const parent = target.parentElement; if (parent) { - const fallbackDiv = document.createElement("div"); + const fallbackDiv = + document.createElement("div"); fallbackDiv.className = - "w-5 h-5 rounded-full bg-gray-200 flex items-center justify-center text-xs"; - fallbackDiv.textContent = displayName.charAt(0); + "w-5 h-5 rounded-full bg-muted flex items-center justify-center text-xs"; + fallbackDiv.textContent = + displayName.charAt(0); parent.replaceChild(fallbackDiv, target); } }} /> )} - {displayName} + + {displayName} + ); })()}
- Metadata -
+

Metadata

+
{metadataString}
- Created - - {vectorStoreDetails.created_at ? new Date(vectorStoreDetails.created_at).toLocaleString() : "-"} - +

Created

+

+ {vectorStoreDetails.created_at + ? new Date( + vectorStoreDetails.created_at, + ).toLocaleString() + : "-"} +

- Last Updated - - {vectorStoreDetails.updated_at ? new Date(vectorStoreDetails.updated_at).toLocaleString() : "-"} - +

Last Updated

+

+ {vectorStoreDetails.updated_at + ? new Date( + vectorStoreDetails.updated_at, + ).toLocaleString() + : "-"} +