diff --git a/ui/litellm-dashboard/src/components/organization/organization_view.tsx b/ui/litellm-dashboard/src/components/organization/organization_view.tsx index a3ee0004fa6..8ec1738346d 100644 --- a/ui/litellm-dashboard/src/components/organization/organization_view.tsx +++ b/ui/litellm-dashboard/src/components/organization/organization_view.tsx @@ -9,6 +9,7 @@ import { Button, Form, Input, Select, Tabs, Typography } from "antd"; import type { ColumnsType } from "antd/es/table"; import { CheckIcon, CopyIcon } from "lucide-react"; import React, { useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; import MemberTable from "../common_components/MemberTable"; import UserSearchModal from "../common_components/user_search_modal"; import MCPServerSelector from "../mcp_server_management/MCPServerSelector"; @@ -46,6 +47,7 @@ const OrganizationInfoView: React.FC = ({ userModels, editOrg, }) => { + const { t } = useTranslation(); const queryClient = useQueryClient(); const { data: orgData, isLoading: loading } = useOrganization(organizationId); const [form] = Form.useForm(); @@ -73,12 +75,12 @@ const OrganizationInfoView: React.FC = ({ }; const response = await organizationMemberAddCall(accessToken, organizationId, member); - NotificationsManager.success("Organization member added successfully"); + NotificationsManager.success(t("organization.organizationView.memberAddedSuccess")); setIsAddMemberModalVisible(false); form.resetFields(); queryClient.invalidateQueries({ queryKey: organizationKeys.all }); } catch (error) { - NotificationsManager.fromBackend("Failed to add organization member"); + NotificationsManager.fromBackend(t("organization.organizationView.memberAddFailed")); console.error("Error adding organization member:", error); } }; @@ -94,12 +96,12 @@ const OrganizationInfoView: React.FC = ({ }; const response = await organizationMemberUpdateCall(accessToken, organizationId, member); - NotificationsManager.success("Organization member updated successfully"); + NotificationsManager.success(t("organization.organizationView.memberUpdatedSuccess")); setIsEditMemberModalVisible(false); form.resetFields(); queryClient.invalidateQueries({ queryKey: organizationKeys.all }); } catch (error) { - NotificationsManager.fromBackend("Failed to update organization member"); + NotificationsManager.fromBackend(t("organization.organizationView.memberUpdateFailed")); console.error("Error updating organization member:", error); } }; @@ -109,12 +111,12 @@ const OrganizationInfoView: React.FC = ({ if (!accessToken) return; await organizationMemberDeleteCall(accessToken, organizationId, values.user_id); - NotificationsManager.success("Organization member deleted successfully"); + NotificationsManager.success(t("organization.organizationView.memberDeletedSuccess")); setIsEditMemberModalVisible(false); form.resetFields(); queryClient.invalidateQueries({ queryKey: organizationKeys.all }); } catch (error) { - NotificationsManager.fromBackend("Failed to delete organization member"); + NotificationsManager.fromBackend(t("organization.organizationView.memberDeleteFailed")); console.error("Error deleting organization member:", error); } }; @@ -160,11 +162,11 @@ const OrganizationInfoView: React.FC = ({ const response = await organizationUpdateCall(accessToken, updateData); - NotificationsManager.success("Organization settings updated successfully"); + NotificationsManager.success(t("organization.organizationView.settingsUpdatedSuccess")); setIsEditing(false); queryClient.invalidateQueries({ queryKey: organizationKeys.all }); } catch (error) { - NotificationsManager.fromBackend("Failed to update organization settings"); + NotificationsManager.fromBackend(t("organization.organizationView.settingsUpdateFailed")); console.error("Error updating organization:", error); } finally { setIsOrgSaving(false); @@ -172,11 +174,11 @@ const OrganizationInfoView: React.FC = ({ }; if (loading) { - return
Loading...
; + return
{t("common.loading")}
; } if (!orgData) { - return
Organization not found
; + return
{t("organization.organizationView.notFound")}
; } const copyToClipboard = async (text: string | null | undefined, key: string) => { @@ -191,7 +193,7 @@ const OrganizationInfoView: React.FC = ({ const orgExtraColumns: ColumnsType = [ { - title: "Spend (USD)", + title: t("organization.organizationView.spendColumnTitle"), key: "spend", render: (_: unknown, record: Member) => { const orgMember = @@ -200,7 +202,7 @@ const OrganizationInfoView: React.FC = ({ }, }, { - title: "Created At", + title: t("common.createdAt"), key: "created_at", render: (_: unknown, record: Member) => { const orgMember = @@ -219,7 +221,7 @@ const OrganizationInfoView: React.FC = ({
- Back to Organizations + {t("organization.organizationView.backToOrganizations")} {orgData.organization_alias}
@@ -245,50 +247,74 @@ const OrganizationInfoView: React.FC = ({ items={[ { key: "overview", - label: "Overview", + label: t("organization.organizationView.tabOverview"), children: ( - Organization Details + {t("organization.organizationView.orgDetails")}
- Created: {new Date(orgData.created_at).toLocaleDateString()} - Updated: {new Date(orgData.updated_at).toLocaleDateString()} - Created By: {orgData.created_by} + + {t("organization.organizationView.createdLabel", { + date: new Date(orgData.created_at).toLocaleDateString(), + })} + + + {t("organization.organizationView.updatedLabel", { + date: new Date(orgData.updated_at).toLocaleDateString(), + })} + + {t("organization.organizationView.createdByLabel", { name: orgData.created_by })}
- Budget Status + {t("organization.organizationView.budgetStatus")}
${formatNumberWithCommas(orgData.spend, 4)} - of{" "} + {t("organization.organizationView.budgetOf")}{" "} {orgData.litellm_budget_table.max_budget === null - ? "Unlimited" + ? t("organization.organizationView.unlimited") : `$${formatNumberWithCommas(orgData.litellm_budget_table.max_budget, 4)}`} {orgData.litellm_budget_table.budget_duration && ( - Reset: {orgData.litellm_budget_table.budget_duration} + + {t("organization.organizationView.budgetReset", { + duration: orgData.litellm_budget_table.budget_duration, + })} + )}
- Rate Limits + {t("organization.organizationView.rateLimits")}
- TPM: {orgData.litellm_budget_table.tpm_limit || "Unlimited"} - RPM: {orgData.litellm_budget_table.rpm_limit || "Unlimited"} + + {t("organization.organizationView.tpmLabel", { + value: orgData.litellm_budget_table.tpm_limit || t("organization.organizationView.unlimited"), + })} + + + {t("organization.organizationView.rpmLabel", { + value: orgData.litellm_budget_table.rpm_limit || t("organization.organizationView.unlimited"), + })} + {orgData.litellm_budget_table.max_parallel_requests && ( - Max Parallel Requests: {orgData.litellm_budget_table.max_parallel_requests} + + {t("organization.organizationView.maxParallelRequests", { + value: orgData.litellm_budget_table.max_parallel_requests, + })} + )}
- Models + {t("organization.organizationView.modelsCard")}
{orgData.models.length === 0 ? ( - All proxy models + {t("organization.organizationView.allProxyModels")} ) : ( orgData.models.map((model, index) => ( @@ -299,7 +325,7 @@ const OrganizationInfoView: React.FC = ({
- Teams + {t("organization.organizationView.teamsCard")}
{orgData.teams?.map((team, index) => ( @@ -319,7 +345,7 @@ const OrganizationInfoView: React.FC = ({ }, { key: "members", - label: "Members", + label: t("organization.organizationView.tabMembers"), children: (
= ({ }} onDelete={(member) => handleMemberDelete(member)} onAddMember={() => setIsAddMemberModalVisible(true)} - roleColumnTitle="Organization Role" + roleColumnTitle={t("organization.organizationView.orgRoleColumnTitle")} extraColumns={orgExtraColumns} - emptyText="No members found" + emptyText={t("organization.organizationView.noMembersFound")} />
), }, { key: "settings", - label: "Settings", + label: t("common.settings"), children: (
- Organization Settings + {t("organization.organizationView.orgSettings")} {canEditOrg && !isEditing && ( - setIsEditing(true)}>Edit Settings + setIsEditing(true)}> + {t("organization.organizationView.editSettings")} + )}
@@ -375,19 +403,19 @@ const OrganizationInfoView: React.FC = ({ layout="vertical" > - + form.setFieldValue("models", values)} @@ -399,55 +427,61 @@ const OrganizationInfoView: React.FC = ({ /> - + - + - + - + - + form.setFieldValue("vector_stores", values)} value={form.getFieldValue("vector_stores")} accessToken={accessToken || ""} - placeholder="Select vector stores" + placeholder={t("organization.organizationView.vectorStoresPlaceholder")} /> - + form.setFieldValue("mcp_servers_and_groups", values)} value={form.getFieldValue("mcp_servers_and_groups")} accessToken={accessToken || ""} - placeholder="Select MCP servers and access groups" + placeholder={t("organization.organizationView.mcpServersPlaceholder")} /> - +
setIsEditing(false)} disabled={isOrgSaving}> - Cancel + {t("common.cancel")} - Save Changes + {t("organization.organizationView.saveChanges")}
@@ -455,19 +489,19 @@ const OrganizationInfoView: React.FC = ({ ) : (
- Organization Name + {t("organization.organizationView.displayOrgName")}
{orgData.organization_alias}
- Organization ID + {t("organization.organizationView.displayOrgId")}
{orgData.organization_id}
- Created At + {t("common.createdAt")}
{new Date(orgData.created_at).toLocaleString()}
- Models + {t("organization.organizationView.displayModels")}
{orgData.models.map((model, index) => ( @@ -477,19 +511,32 @@ const OrganizationInfoView: React.FC = ({
- Rate Limits -
TPM: {orgData.litellm_budget_table.tpm_limit || "Unlimited"}
-
RPM: {orgData.litellm_budget_table.rpm_limit || "Unlimited"}
+ {t("organization.organizationView.displayRateLimits")} +
+ {t("organization.organizationView.displayTpm", { + value: orgData.litellm_budget_table.tpm_limit || t("organization.organizationView.unlimited"), + })} +
+
+ {t("organization.organizationView.displayRpm", { + value: orgData.litellm_budget_table.rpm_limit || t("organization.organizationView.unlimited"), + })} +
- Budget + {t("organization.organizationView.displayBudget")}
- Max:{" "} {orgData.litellm_budget_table.max_budget !== null - ? `$${formatNumberWithCommas(orgData.litellm_budget_table.max_budget, 4)}` - : "No Limit"} + ? t("organization.organizationView.displayMax", { + value: `$${formatNumberWithCommas(orgData.litellm_budget_table.max_budget, 4)}`, + }) + : t("organization.organizationView.noLimit")} +
+
+ {t("organization.organizationView.displayReset", { + duration: orgData.litellm_budget_table.budget_duration || t("common.never"), + })}
-
Reset: {orgData.litellm_budget_table.budget_duration || "Never"}
= ({ onCancel={() => setIsAddMemberModalVisible(false)} onSubmit={handleMemberAdd} accessToken={accessToken} - title="Add Organization Member" + title={t("organization.organizationView.addMemberTitle")} roles={[ { label: "org_admin", value: "org_admin", - description: "Can add and remove members, and change their roles.", + description: t("organization.organizationView.roleOrgAdminDesc"), }, { label: "internal_user", value: "internal_user", - description: "Can view/create keys for themselves within organization.", + description: t("organization.organizationView.roleInternalUserDesc"), }, { label: "internal_user_viewer", value: "internal_user_viewer", - description: "Can only view their keys within organization.", + description: t("organization.organizationView.roleInternalUserViewerDesc"), }, ]} defaultRole="internal_user" @@ -537,13 +584,13 @@ const OrganizationInfoView: React.FC = ({ initialData={selectedEditMember} mode="edit" config={{ - title: "Edit Member", + title: t("organization.organizationView.editMemberTitle"), showEmail: true, showUserId: true, roleOptions: [ - { label: "Org Admin", value: "org_admin" }, - { label: "Internal User", value: "internal_user" }, - { label: "Internal User Viewer", value: "internal_user_viewer" }, + { label: t("organization.organizationView.roleOrgAdmin"), value: "org_admin" }, + { label: t("organization.organizationView.roleInternalUser"), value: "internal_user" }, + { label: t("organization.organizationView.roleInternalUserViewer"), value: "internal_user_viewer" }, ], }} /> diff --git a/ui/litellm-dashboard/src/locales/en.json b/ui/litellm-dashboard/src/locales/en.json index 9e5ebd52038..daff683d88e 100644 --- a/ui/litellm-dashboard/src/locales/en.json +++ b/ui/litellm-dashboard/src/locales/en.json @@ -8422,5 +8422,75 @@ "noDescription": "No description", "noToolsAvailable": "No tools available" } + }, + "organization": { + "organizationView": { + "memberAddedSuccess": "Organization member added successfully", + "memberAddFailed": "Failed to add organization member", + "memberUpdatedSuccess": "Organization member updated successfully", + "memberUpdateFailed": "Failed to update organization member", + "memberDeletedSuccess": "Organization member deleted successfully", + "memberDeleteFailed": "Failed to delete organization member", + "settingsUpdatedSuccess": "Organization settings updated successfully", + "settingsUpdateFailed": "Failed to update organization settings", + "notFound": "Organization not found", + "backToOrganizations": "Back to Organizations", + "spendColumnTitle": "Spend (USD)", + "tabOverview": "Overview", + "orgDetails": "Organization Details", + "createdLabel": "Created: {{date}}", + "updatedLabel": "Updated: {{date}}", + "createdByLabel": "Created By: {{name}}", + "budgetStatus": "Budget Status", + "unlimited": "Unlimited", + "budgetOf": "of", + "budgetReset": "Reset: {{duration}}", + "rateLimits": "Rate Limits", + "tpmLabel": "TPM: {{value}}", + "rpmLabel": "RPM: {{value}}", + "maxParallelRequests": "Max Parallel Requests: {{value}}", + "modelsCard": "Models", + "allProxyModels": "All proxy models", + "teamsCard": "Teams", + "tabMembers": "Members", + "orgRoleColumnTitle": "Organization Role", + "noMembersFound": "No members found", + "orgSettings": "Organization Settings", + "editSettings": "Edit Settings", + "formOrgName": "Organization Name", + "formOrgNameRequired": "Please input an organization name", + "formModels": "Models", + "formMaxBudget": "Max Budget (USD)", + "formResetBudget": "Reset Budget", + "budgetDurationDaily": "daily", + "budgetDurationWeekly": "weekly", + "budgetDurationMonthly": "monthly", + "formTpmLimit": "Tokens per minute Limit (TPM)", + "formRpmLimit": "Requests per minute Limit (RPM)", + "formVectorStores": "Vector Stores", + "vectorStoresPlaceholder": "Select vector stores", + "formMcpServers": "MCP Servers & Access Groups", + "mcpServersPlaceholder": "Select MCP servers and access groups", + "formMetadata": "Metadata", + "saveChanges": "Save Changes", + "displayOrgName": "Organization Name", + "displayOrgId": "Organization ID", + "displayModels": "Models", + "displayRateLimits": "Rate Limits", + "displayTpm": "TPM: {{value}}", + "displayRpm": "RPM: {{value}}", + "displayBudget": "Budget", + "displayMax": "Max: {{value}}", + "noLimit": "No Limit", + "displayReset": "Reset: {{duration}}", + "addMemberTitle": "Add Organization Member", + "roleOrgAdminDesc": "Can add and remove members, and change their roles.", + "roleInternalUserDesc": "Can view/create keys for themselves within organization.", + "roleInternalUserViewerDesc": "Can only view their keys within organization.", + "editMemberTitle": "Edit Member", + "roleOrgAdmin": "Org Admin", + "roleInternalUser": "Internal User", + "roleInternalUserViewer": "Internal User Viewer" + } } } diff --git a/ui/litellm-dashboard/src/locales/zh-CN.json b/ui/litellm-dashboard/src/locales/zh-CN.json index 591f4a0b8f6..b851f2c3aee 100644 --- a/ui/litellm-dashboard/src/locales/zh-CN.json +++ b/ui/litellm-dashboard/src/locales/zh-CN.json @@ -8422,5 +8422,75 @@ "noDescription": "无描述", "noToolsAvailable": "暂无可用工具" } + }, + "organization": { + "organizationView": { + "memberAddedSuccess": "组织成员添加成功", + "memberAddFailed": "添加组织成员失败", + "memberUpdatedSuccess": "组织成员更新成功", + "memberUpdateFailed": "更新组织成员失败", + "memberDeletedSuccess": "组织成员删除成功", + "memberDeleteFailed": "删除组织成员失败", + "settingsUpdatedSuccess": "组织设置更新成功", + "settingsUpdateFailed": "更新组织设置失败", + "notFound": "未找到组织", + "backToOrganizations": "返回组织列表", + "spendColumnTitle": "花费(USD)", + "tabOverview": "概览", + "orgDetails": "组织详情", + "createdLabel": "创建时间:{{date}}", + "updatedLabel": "更新时间:{{date}}", + "createdByLabel": "创建人:{{name}}", + "budgetStatus": "预算状态", + "unlimited": "无限制", + "budgetOf": "共", + "budgetReset": "重置:{{duration}}", + "rateLimits": "速率限制", + "tpmLabel": "TPM:{{value}}", + "rpmLabel": "RPM:{{value}}", + "maxParallelRequests": "最大并行请求数:{{value}}", + "modelsCard": "模型", + "allProxyModels": "所有代理模型", + "teamsCard": "团队", + "tabMembers": "成员", + "orgRoleColumnTitle": "组织角色", + "noMembersFound": "未找到成员", + "orgSettings": "组织设置", + "editSettings": "编辑设置", + "formOrgName": "组织名称", + "formOrgNameRequired": "请输入组织名称", + "formModels": "模型", + "formMaxBudget": "最大预算(USD)", + "formResetBudget": "重置预算", + "budgetDurationDaily": "每日", + "budgetDurationWeekly": "每周", + "budgetDurationMonthly": "每月", + "formTpmLimit": "每分钟 Token 限制(TPM)", + "formRpmLimit": "每分钟请求限制(RPM)", + "formVectorStores": "向量存储", + "vectorStoresPlaceholder": "选择向量存储", + "formMcpServers": "MCP 服务器与访问组", + "mcpServersPlaceholder": "选择 MCP 服务器和访问组", + "formMetadata": "元数据", + "saveChanges": "保存更改", + "displayOrgName": "组织名称", + "displayOrgId": "组织 ID", + "displayModels": "模型", + "displayRateLimits": "速率限制", + "displayTpm": "TPM:{{value}}", + "displayRpm": "RPM:{{value}}", + "displayBudget": "预算", + "displayMax": "最大值:{{value}}", + "noLimit": "无限制", + "displayReset": "重置:{{duration}}", + "addMemberTitle": "添加组织成员", + "roleOrgAdminDesc": "可添加和移除成员,并更改其角色。", + "roleInternalUserDesc": "可在组织内查看/创建自己的密钥。", + "roleInternalUserViewerDesc": "只能查看组织内自己的密钥。", + "editMemberTitle": "编辑成员", + "roleOrgAdmin": "组织管理员", + "roleInternalUser": "内部用户", + "roleInternalUserViewer": "内部用户(只读)" + } } }