diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/EntityUsageExportModal.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/EntityUsageExportModal.tsx index 4c934bbf1d3..d3ec6a05e49 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/EntityUsageExportModal.tsx +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/EntityUsageExportModal.tsx @@ -1,12 +1,23 @@ import { useTeams } from "@/app/(dashboard)/hooks/teams/useTeams"; import { createTeamAliasMap } from "@/utils/teamUtils"; -import { Button, Modal, Skeleton } from "antd"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Skeleton } from "@/components/ui/skeleton"; import React, { useMemo, useState } from "react"; import NotificationsManager from "../molecules/notifications_manager"; import ExportFormatSelector from "./ExportFormatSelector"; import ExportSummary from "./ExportSummary"; import ExportTypeSelector from "./ExportTypeSelector"; -import type { EntityUsageExportModalProps, ExportFormat, ExportScope } from "./types"; +import type { + EntityUsageExportModalProps, + ExportFormat, + ExportScope, +} from "./types"; import { handleExportCSV, handleExportJSON } from "./utils"; const EntityUsageExportModal: React.FC = ({ @@ -26,18 +37,36 @@ const EntityUsageExportModal: React.FC = ({ const entityLabel = entityType.charAt(0).toUpperCase() + entityType.slice(1); const modalTitle = customTitle || `Export ${entityLabel} Usage`; - // Cache team alias map using useMemo const teamAliasMap = useMemo(() => createTeamAliasMap(teams), [teams]); + const handleExport = async (format?: ExportFormat) => { const formatToUse = format || exportFormat; setIsExporting(true); try { if (formatToUse === "csv") { - handleExportCSV(spendData, exportScope, entityLabel, entityType, teamAliasMap); - NotificationsManager.success(`${entityLabel} usage data exported successfully as CSV`); + handleExportCSV( + spendData, + exportScope, + entityLabel, + entityType, + teamAliasMap, + ); + NotificationsManager.success( + `${entityLabel} usage data exported successfully as CSV`, + ); } else { - handleExportJSON(spendData, exportScope, entityLabel, entityType, dateRange, selectedFilters, teamAliasMap); - NotificationsManager.success(`${entityLabel} usage data exported successfully as JSON`); + handleExportJSON( + spendData, + exportScope, + entityLabel, + entityType, + dateRange, + selectedFilters, + teamAliasMap, + ); + NotificationsManager.success( + `${entityLabel} usage data exported successfully as JSON`, + ); } onClose(); } catch (error) { @@ -49,45 +78,67 @@ const EntityUsageExportModal: React.FC = ({ }; return ( - {modalTitle}} + (!open ? onClose() : undefined)} > -
- {isLoadingTeams ? ( - - ) : ( - <> - - - - - )} - {isLoadingTeams ? ( -
- - -
- ) : ( -
- - -
- )} -
-
+ + + + {modalTitle} + + +
+ {isLoadingTeams ? ( +
+ + + +
+ ) : ( + <> + + + + + )} + {isLoadingTeams ? ( +
+ + +
+ ) : ( +
+ + +
+ )} +
+
+ ); }; diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.tsx index b27bbfd6762..d28b7581e29 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.tsx +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportFormatSelector.tsx @@ -1,5 +1,12 @@ import React from "react"; -import { Select } from "antd"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import type { ExportFormat } from "./types"; interface ExportFormatSelectorProps { @@ -7,28 +14,24 @@ interface ExportFormatSelectorProps { onChange: (value: ExportFormat) => void; } -const ExportFormatSelector: React.FC = ({ value, onChange }) => { +const ExportFormatSelector: React.FC = ({ + value, + onChange, +}) => { return (
- - onChange(v as ExportFormat)}> + + + + + CSV (Excel, Google Sheets) + JSON (includes metadata) + +
); }; export default ExportFormatSelector; - diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.tsx index 97068e0492c..08cc86da7fd 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.tsx +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportSummary.tsx @@ -1,4 +1,5 @@ import React from "react"; +// eslint-disable-next-line litellm-ui/no-banned-ui-imports import type { DateRangePickerValue } from "@tremor/react"; interface ExportSummaryProps { @@ -6,14 +7,18 @@ interface ExportSummaryProps { selectedFilters: string[]; } -const ExportSummary: React.FC = ({ dateRange, selectedFilters }) => { +const ExportSummary: React.FC = ({ + dateRange, + selectedFilters, +}) => { return ( -
- {dateRange.from?.toLocaleDateString()} - {dateRange.to?.toLocaleDateString()} - {selectedFilters.length > 0 && ` · ${selectedFilters.length} filter${selectedFilters.length > 1 ? "s" : ""}`} +
+ {dateRange.from?.toLocaleDateString()} -{" "} + {dateRange.to?.toLocaleDateString()} + {selectedFilters.length > 0 && + ` · ${selectedFilters.length} filter${selectedFilters.length > 1 ? "s" : ""}`}
); }; export default ExportSummary; - diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.tsx b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.tsx index 6bc85948608..177c7457ba5 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.tsx +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/ExportTypeSelector.tsx @@ -1,5 +1,6 @@ import React from "react"; -import { Radio } from "antd"; +import { Label } from "@/components/ui/label"; +import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import type { ExportScope, EntityType } from "./types"; interface ExportTypeSelectorProps { @@ -8,37 +9,58 @@ interface ExportTypeSelectorProps { entityType: EntityType; } -const ExportTypeSelector: React.FC = ({ value, onChange, entityType }) => { +const items: Array<{ + value: ExportScope; + title: (t: EntityType) => string; + description: (t: EntityType) => string; +}> = [ + { + value: "daily", + title: (t) => `Day-by-day breakdown by ${t}`, + description: (t) => `Daily metrics for each ${t}`, + }, + { + value: "daily_with_keys", + title: (t) => `Day-by-day breakdown by ${t} and key`, + description: (t) => `Daily metrics for each ${t}, split by API key`, + }, + { + value: "daily_with_models", + title: (t) => `Day-by-day by ${t} and model`, + description: () => `Daily metrics split by model`, + }, +]; + +const ExportTypeSelector: React.FC = ({ + value, + onChange, + entityType, +}) => { return (
- - onChange(e.target.value)} className="w-full"> -
-
-
+ ))} +
); };