diff --git a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx index 21d82a41fcf..872ea8c1df0 100644 --- a/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx +++ b/ui/litellm-dashboard/src/components/CostTrackingSettings/pricing_calculator/multi_cost_results.tsx @@ -51,7 +51,9 @@ const SingleModelBreakdown: React.FC<{
- {t("costTracking.multiCostResults.totalPerRequest")} + + {t("costTracking.multiCostResults.breakdownTotalPerRequest")} + {formatCost(result.cost_per_request)}
diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.tsx index 6908b8a6b79..bc39b01ae49 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.tsx @@ -111,7 +111,7 @@ const EditSSOSettingsModal: React.FC = ({ isVisible, }, onError: (error) => { NotificationsManager.fromBackend( - t("settingsPages.editSSOSettingsModal.saveFailed", { error: parseErrorMessage(error) }), + t("settingsPages.editSSOSettingsModal.saveFailed", { error: String(parseErrorMessage(error)) }), ); }, }); diff --git a/ui/litellm-dashboard/src/components/policies/impact_preview_alert.test.tsx b/ui/litellm-dashboard/src/components/policies/impact_preview_alert.test.tsx index b79ca7b5681..4332a13752b 100644 --- a/ui/litellm-dashboard/src/components/policies/impact_preview_alert.test.tsx +++ b/ui/litellm-dashboard/src/components/policies/impact_preview_alert.test.tsx @@ -33,12 +33,12 @@ describe("ImpactPreviewAlert", () => { describe("when scope is specific", () => { it("should show the number of affected keys", () => { renderWithProviders(); - expect(screen.getByText(/3 keys/i)).toBeInTheDocument(); + expect(screen.queryAllByText((_, node) => !!node?.textContent?.match(/3 keys/i)).length).toBeGreaterThan(0); }); it("should show the number of affected teams", () => { renderWithProviders(); - expect(screen.getByText(/1 team\b/i)).toBeInTheDocument(); + expect(screen.queryAllByText((_, node) => !!node?.textContent?.match(/1 team\b/i)).length).toBeGreaterThan(0); }); it("should render sample key tags", () => { @@ -66,7 +66,7 @@ describe("ImpactPreviewAlert", () => { it("should use singular 'key' when exactly one key is affected", () => { const oneKey = { affected_keys_count: 1, affected_teams_count: 0, sample_keys: ["sk-1"], sample_teams: [] }; renderWithProviders(); - expect(screen.getByText(/1 key\b/i)).toBeInTheDocument(); + expect(screen.queryAllByText((_, node) => !!node?.textContent?.match(/1 key\b/i)).length).toBeGreaterThan(0); }); it("should not show a key section when there are no sample keys", () => { diff --git a/ui/litellm-dashboard/src/components/policies/policy_templates.tsx b/ui/litellm-dashboard/src/components/policies/policy_templates.tsx index 8ec97774754..93d104d6045 100644 --- a/ui/litellm-dashboard/src/components/policies/policy_templates.tsx +++ b/ui/litellm-dashboard/src/components/policies/policy_templates.tsx @@ -226,7 +226,7 @@ const PolicyTemplates: React.FC = ({ {t("policies.policyTemplates.categories")} {selectedTags.size > 0 && ( )}
diff --git a/ui/litellm-dashboard/src/components/vector_store_management/CreateVectorStore.tsx b/ui/litellm-dashboard/src/components/vector_store_management/CreateVectorStore.tsx index c62ade3d2f2..33341ff05c4 100644 --- a/ui/litellm-dashboard/src/components/vector_store_management/CreateVectorStore.tsx +++ b/ui/litellm-dashboard/src/components/vector_store_management/CreateVectorStore.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; import { Card, Title, Text } from "@tremor/react"; import { Upload, Button, Select, Form, Alert, Tooltip, Input } from "antd"; import MessageManager from "@/components/molecules/message_manager"; @@ -25,6 +26,7 @@ interface CreateVectorStoreProps { } const CreateVectorStore: React.FC = ({ accessToken, onSuccess }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); const [documents, setDocuments] = useState([]); const [isCreating, setIsCreating] = useState(false); @@ -48,13 +50,13 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu ].includes(file.type); if (!isValidType) { - MessageManager.error(`${file.name} is not a supported file type. Please upload PDF, TXT, DOCX, or MD files.`); + MessageManager.error(t("vectorStoreManagement.createVectorStore.unsupportedFileType", { name: file.name })); return Upload.LIST_IGNORE; } const isLt50M = file.size / 1024 / 1024 < 50; if (!isLt50M) { - MessageManager.error(`${file.name} must be smaller than 50MB!`); + MessageManager.error(t("vectorStoreManagement.createVectorStore.fileTooLarge", { name: file.name })); return Upload.LIST_IGNORE; } @@ -88,20 +90,20 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu const handleCreateVectorStore = async () => { if (documents.length === 0) { - MessageManager.warning("Please upload at least one document"); + MessageManager.warning(t("vectorStoreManagement.createVectorStore.uploadAtLeastOne")); return; } if (!selectedProvider) { - MessageManager.warning("Please select a provider"); + MessageManager.warning(t("vectorStoreManagement.createVectorStore.selectProvider")); return; } // Validate provider-specific required fields - const requiredFields = getProviderSpecificFields(selectedProvider).filter((field) => field.required); + const requiredFields = getProviderSpecificFields(selectedProvider, t).filter((field) => field.required); for (const field of requiredFields) { if (!providerParams[field.name]) { - MessageManager.warning(`Please provide ${field.label}`); + MessageManager.warning(t("vectorStoreManagement.createVectorStore.provideField", { label: field.label })); return; } } @@ -109,17 +111,17 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu // S3 Vectors specific validation if (selectedProvider === "s3_vectors") { if (providerParams.vector_bucket_name && providerParams.vector_bucket_name.length < 3) { - MessageManager.warning("Vector bucket name must be at least 3 characters"); + MessageManager.warning(t("vectorStoreManagement.createVectorStore.bucketNameMinLength")); return; } if (providerParams.index_name && providerParams.index_name.length > 0 && providerParams.index_name.length < 3) { - MessageManager.warning("Index name must be at least 3 characters if provided"); + MessageManager.warning(t("vectorStoreManagement.createVectorStore.indexNameMinLength")); return; } } if (!accessToken) { - MessageManager.error("No access token available"); + MessageManager.error(t("common.error")); return; } @@ -165,7 +167,7 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu setIngestResults(results); NotificationsManager.success( - `Successfully created vector store with ${results.length} document(s). Vector Store ID: ${vectorStoreId}`, + t("vectorStoreManagement.createVectorStore.createSuccess", { count: results.length, vectorStoreId }), ); if (onSuccess && vectorStoreId) { @@ -179,7 +181,7 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu }, 3000); } catch (error) { console.error("Error creating vector store:", error); - NotificationsManager.fromBackend(`Failed to create vector store: ${error}`); + NotificationsManager.fromBackend(t("vectorStoreManagement.createVectorStore.createFailed", { error })); } finally { setIsCreating(false); } @@ -188,26 +190,24 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu return (
- Create Vector Store - - Upload documents and select a provider to create a new vector store with embedded content. - + {t("vectorStoreManagement.createVectorStore.pageTitle")} + {t("vectorStoreManagement.createVectorStore.pageSubtitle")}
{/* Upload Area */}
- Step 1: Upload Documents + {t("vectorStoreManagement.createVectorStore.step1Title")} - Upload one or more documents (PDF, TXT, DOCX, MD). Maximum file size: 50MB per file. + {t("vectorStoreManagement.createVectorStore.step1Subtitle")}

-

Click or drag files to this area to upload

-

Support for single or bulk upload. Supported formats: PDF, TXT, DOCX, MD

+

{t("vectorStoreManagement.createVectorStore.draggerText")}

+

{t("vectorStoreManagement.createVectorStore.draggerHint")}

@@ -215,7 +215,9 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu {documents.length > 0 && (
- Uploaded Documents ({documents.length}) + + {t("vectorStoreManagement.createVectorStore.uploadedDocuments", { count: documents.length })} +
@@ -225,9 +227,9 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu
- Step 2: Configure Vector Store + {t("vectorStoreManagement.createVectorStore.step2Title")} - Choose the provider and optionally provide a name and description for your vector store. + {t("vectorStoreManagement.createVectorStore.step2Subtitle")}
@@ -235,8 +237,8 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu - Vector Store Name{" "} - + {t("vectorStoreManagement.createVectorStore.vectorStoreNameLabel")}{" "} + @@ -245,7 +247,7 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu setVectorStoreName(e.target.value)} - placeholder="e.g., Product Documentation, Customer Support KB" + placeholder={t("vectorStoreManagement.createVectorStore.vectorStoreNamePlaceholder")} size="large" className="rounded-md" /> @@ -254,8 +256,8 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu - Description{" "} - + {t("common.description")}{" "} + @@ -264,7 +266,7 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu setVectorStoreDescription(e.target.value)} - placeholder="e.g., Contains all product documentation and user guides" + placeholder={t("vectorStoreManagement.createVectorStore.descriptionPlaceholder")} rows={2} size="large" className="rounded-md" @@ -274,8 +276,8 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu - Provider{" "} - + {t("vectorStoreManagement.createVectorStore.providerLabel")}{" "} + @@ -285,7 +287,7 @@ const CreateVectorStore: React.FC = ({ accessToken, onSu handleFieldChange("vector_bucket_name", e.target.value)} - placeholder="my-vector-bucket (min 3 chars)" + placeholder={t("vectorStoreManagement.s3VectorsConfig.vectorBucketNamePlaceholder")} size="large" className="rounded-md" /> @@ -103,8 +105,8 @@ const S3VectorsConfig: React.FC = ({ accessToken, provider - Index Name{" "} - + {t("vectorStoreManagement.s3VectorsConfig.indexNameLabel")}{" "} + @@ -116,14 +118,14 @@ const S3VectorsConfig: React.FC = ({ accessToken, provider } help={ providerParams.index_name && providerParams.index_name.length > 0 && providerParams.index_name.length < 3 - ? "Index name must be at least 3 characters if provided" + ? t("vectorStoreManagement.s3VectorsConfig.indexNameHelp") : undefined } > handleFieldChange("index_name", e.target.value)} - placeholder="my-vector-index (optional, min 3 chars)" + placeholder={t("vectorStoreManagement.s3VectorsConfig.indexNamePlaceholder")} size="large" className="rounded-md" /> @@ -133,8 +135,8 @@ const S3VectorsConfig: React.FC = ({ accessToken, provider - AWS Region{" "} - + {t("vectorStoreManagement.s3VectorsConfig.awsRegionLabel")}{" "} + @@ -154,8 +156,8 @@ const S3VectorsConfig: React.FC = ({ accessToken, provider - Embedding Model{" "} - + {t("vectorStoreManagement.s3VectorsConfig.embeddingModelLabel")}{" "} + @@ -165,7 +167,7 @@ const S3VectorsConfig: React.FC = ({ accessToken, provider = ({ accessToken, credentials, }) => { + const { t } = useTranslation(); const [form] = Form.useForm(); const [metadataJson, setMetadataJson] = useState("{}"); const [selectedProvider, setSelectedProvider] = useState("bedrock"); @@ -59,7 +61,7 @@ const VectorStoreForm: React.FC = ({ try { metadata = metadataJson.trim() ? JSON.parse(metadataJson) : {}; } catch (e) { - NotificationsManager.fromBackend("Invalid JSON in metadata field"); + NotificationsManager.fromBackend(t("vectorStoreManagement.vectorStoreForm.invalidMetadataJson")); return; } @@ -74,7 +76,7 @@ const VectorStoreForm: React.FC = ({ }; // pass all provider fields as litellm params dict - const providerFields = getProviderSpecificFields(formValues.custom_llm_provider); + const providerFields = getProviderSpecificFields(formValues.custom_llm_provider, t); const litellmParams = providerFields.reduce( (acc, field) => { // Special handling for Milvus: rename embedding_model to litellm_embedding_model @@ -91,13 +93,13 @@ const VectorStoreForm: React.FC = ({ payload["litellm_params"] = litellmParams; await vectorStoreCreateCall(accessToken, payload); - NotificationsManager.success("Vector store created successfully"); + NotificationsManager.success(t("vectorStoreManagement.vectorStoreForm.createSuccess")); form.resetFields(); setMetadataJson("{}"); onSuccess(); } catch (error) { console.error("Error creating vector store:", error); - NotificationsManager.fromBackend("Error creating vector store: " + error); + NotificationsManager.fromBackend(t("vectorStoreManagement.vectorStoreForm.createFailed", { error })); } }; @@ -109,19 +111,25 @@ const VectorStoreForm: React.FC = ({ }; return ( - +
- Provider{" "} - + {t("vectorStoreManagement.vectorStoreForm.providerLabel")}{" "} + } name="custom_llm_provider" - rules={[{ required: true, message: "Please select a provider" }]} + rules={[{ required: true, message: t("vectorStoreManagement.vectorStoreForm.providerRequired") }]} initialValue="bedrock" > = ({ } name={field.name} rules={ - field.required ? [{ required: true, message: `Please input the ${field.label.toLowerCase()}` }] : [] + field.required + ? [ + { + required: true, + message: t("vectorStoreManagement.vectorStoreForm.fieldInputRequired", { + label: field.label.toLowerCase(), + }), + }, + ] + : [] } > @@ -339,8 +356,8 @@ const VectorStoreForm: React.FC = ({ - Vector Store Name{" "} - + {t("vectorStoreManagement.vectorStoreForm.vectorStoreNameLabel")}{" "} + @@ -350,15 +367,15 @@ const VectorStoreForm: React.FC = ({ - + - Existing Credentials{" "} - + {t("vectorStoreManagement.vectorStoreForm.existingCredentialsLabel")}{" "} + @@ -367,11 +384,11 @@ const VectorStoreForm: React.FC = ({ >