diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx index 068c78032a..a106910cff 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx @@ -85,10 +85,9 @@ interface EntityUsageProps { entityList: EntityList[] | null; premiumUser: boolean; dateValue: DateRangePickerValue; - timezoneOffset?: number; } -const EntityUsage: React.FC = ({ accessToken, entityType, entityId, entityList, dateValue, timezoneOffset }) => { +const EntityUsage: React.FC = ({ accessToken, entityType, entityId, entityList, dateValue }) => { const [spendData, setSpendData] = useState({ results: [], metadata: { @@ -120,7 +119,6 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti endTime, 1, selectedTags.length > 0 ? selectedTags : null, - timezoneOffset, ); setSpendData(data); } else if (entityType === "team") { @@ -130,7 +128,6 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti endTime, 1, selectedTags.length > 0 ? selectedTags : null, - timezoneOffset, ); setSpendData(data); } else if (entityType === "organization") { @@ -140,7 +137,6 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti endTime, 1, selectedTags.length > 0 ? selectedTags : null, - timezoneOffset, ); setSpendData(data); } else if (entityType === "customer") { @@ -150,7 +146,6 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti endTime, 1, selectedTags.length > 0 ? selectedTags : null, - timezoneOffset, ); setSpendData(data); } else if (entityType === "agent") { @@ -160,7 +155,6 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti endTime, 1, selectedTags.length > 0 ? selectedTags : null, - timezoneOffset, ); setSpendData(data); } else if (entityType === "user") { @@ -170,7 +164,6 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti endTime, 1, selectedTags.length > 0 ? selectedTags[0] : null, - timezoneOffset, ); setSpendData(data); } else { @@ -180,7 +173,7 @@ const EntityUsage: React.FC = ({ accessToken, entityType, enti useEffect(() => { fetchSpendData(); - }, [accessToken, dateValue, entityId, selectedTags, timezoneOffset]); + }, [accessToken, dateValue, entityId, selectedTags]); const getTopModels = () => { const modelSpend: { [key: string]: any } = {}; diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx index 1a89311c35..f32026dcaf 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx @@ -78,8 +78,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { to: initialToDate, }); - const [timezoneOffset, setTimezoneOffset] = useState(() => new Date().getTimezoneOffset()); - const [allTags, setAllTags] = useState([]); const { data: customers = [] } = useCustomers(); const { data: agentsResponse } = useAgents(); @@ -378,14 +376,14 @@ const UsagePage: React.FC = ({ teams, organizations }) => { try { // Prefer aggregated endpoint to avoid many page requests try { - const aggregated = await userDailyActivityAggregatedCall(accessToken, startTime, endTime, effectiveUserId, timezoneOffset); + const aggregated = await userDailyActivityAggregatedCall(accessToken, startTime, endTime, effectiveUserId); setUserSpendData(aggregated); return; } catch (e) { // Fallback to paginated calls if aggregated endpoint is unavailable } - const firstPageData = await userDailyActivityCall(accessToken, startTime, endTime, 1, effectiveUserId, timezoneOffset); + const firstPageData = await userDailyActivityCall(accessToken, startTime, endTime, 1, effectiveUserId); if (firstPageData.metadata.total_pages <= 1) { setUserSpendData(firstPageData); @@ -396,7 +394,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { const aggregatedMetadata = { ...firstPageData.metadata }; for (let page = 2; page <= firstPageData.metadata.total_pages; page++) { - const pageData = await userDailyActivityCall(accessToken, startTime, endTime, page, effectiveUserId, timezoneOffset); + const pageData = await userDailyActivityCall(accessToken, startTime, endTime, page, effectiveUserId); allResults.push(...pageData.results); if (pageData.metadata) { aggregatedMetadata.total_spend += pageData.metadata.total_spend || 0; @@ -417,7 +415,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { setLoading(false); setIsDateChanging(false); } - }, [accessToken, dateValue.from, dateValue.to, selectedUserId, isAdmin, userID, timezoneOffset]); + }, [accessToken, dateValue.from, dateValue.to, selectedUserId, isAdmin, userID]); // Super responsive date change handler const handleDateChange = useCallback((newValue: DateRangePickerValue) => { @@ -497,7 +495,7 @@ const UsagePage: React.FC = ({ teams, organizations }) => { onChange={(value) => setUsageView(value)} isAdmin={isAdmin} /> - + {/* Your Usage Panel */} {usageView === "global" && ( @@ -827,7 +825,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { })) || null } premiumUser={premiumUser} - timezoneOffset={timezoneOffset} /> )} @@ -846,7 +843,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { } premiumUser={premiumUser} dateValue={dateValue} - timezoneOffset={timezoneOffset} /> )} @@ -865,7 +861,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { } premiumUser={premiumUser} dateValue={dateValue} - timezoneOffset={timezoneOffset} /> )} {/* Tag Usage Panel */} @@ -896,7 +891,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { entityList={allTags} premiumUser={premiumUser} dateValue={dateValue} - timezoneOffset={timezoneOffset} /> )} @@ -911,7 +905,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { } premiumUser={premiumUser} dateValue={dateValue} - timezoneOffset={timezoneOffset} /> )} {/* User Usage Panel */} @@ -924,7 +917,6 @@ const UsagePage: React.FC = ({ teams, organizations }) => { entityList={userOptions.length > 0 ? userOptions : null} premiumUser={premiumUser} dateValue={dateValue} - timezoneOffset={timezoneOffset} /> )} {/* User Agent Activity Panel */} diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 762fed91d1..70156a7d2b 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -1698,7 +1698,6 @@ const buildDailyActivityUrl = ( endTime: Date, page: number, extraQueryParams?: Record, - timezoneOffset?: number, ) => { const resolvedEndpoint = endpoint.startsWith("/") ? endpoint : `/${endpoint}`; const baseUrl = proxyBaseUrl ? `${proxyBaseUrl}${resolvedEndpoint}` : resolvedEndpoint; @@ -1709,8 +1708,7 @@ const buildDailyActivityUrl = ( params.append("page_size", DEFAULT_DAILY_ACTIVITY_PAGE_SIZE); params.append("page", page.toString()); // Send timezone offset so backend can adjust date range for UTC storage - const tz = timezoneOffset !== undefined ? timezoneOffset : new Date().getTimezoneOffset(); - params.append("timezone", tz.toString()); + params.append("timezone", new Date().getTimezoneOffset().toString()); if (extraQueryParams) { Object.entries(extraQueryParams).forEach(([key, value]) => { @@ -1729,7 +1727,6 @@ type DailyActivityCallOptions = { endTime: Date; page?: number; extraQueryParams?: Record; - timezoneOffset?: number; }; const fetchDailyActivity = async ({ @@ -1739,10 +1736,9 @@ const fetchDailyActivity = async ({ endTime, page = 1, extraQueryParams, - timezoneOffset, }: DailyActivityCallOptions) => { try { - const url = buildDailyActivityUrl(endpoint, startTime, endTime, page, extraQueryParams, timezoneOffset); + const url = buildDailyActivityUrl(endpoint, startTime, endTime, page, extraQueryParams); const response = await fetch(url, { method: "GET", @@ -1767,7 +1763,7 @@ const fetchDailyActivity = async ({ } }; -export const userDailyActivityCall = async (accessToken: string, startTime: Date, endTime: Date, page: number = 1, userId: string | null = null, timezoneOffset?: number) => { +export const userDailyActivityCall = async (accessToken: string, startTime: Date, endTime: Date, page: number = 1, userId: string | null = null) => { /** * Get daily user activity on proxy */ @@ -1780,7 +1776,6 @@ export const userDailyActivityCall = async (accessToken: string, startTime: Date extraQueryParams: { user_id: userId, }, - timezoneOffset, }); }; @@ -1790,7 +1785,6 @@ export const tagDailyActivityCall = async ( endTime: Date, page: number = 1, tags: string[] | null = null, - timezoneOffset?: number, ) => { /** * Get daily user activity on proxy @@ -1804,7 +1798,6 @@ export const tagDailyActivityCall = async ( extraQueryParams: { tags, }, - timezoneOffset, }); }; @@ -1814,7 +1807,6 @@ export const teamDailyActivityCall = async ( endTime: Date, page: number = 1, teamIds: string[] | null = null, - timezoneOffset?: number, ) => { /** * Get daily user activity on proxy @@ -1829,7 +1821,6 @@ export const teamDailyActivityCall = async ( team_ids: teamIds, exclude_team_ids: "litellm-dashboard", }, - timezoneOffset, }); }; @@ -1839,7 +1830,6 @@ export const organizationDailyActivityCall = async ( endTime: Date, page: number = 1, organizationIds: string[] | null = null, - timezoneOffset?: number, ) => { return fetchDailyActivity({ accessToken, @@ -1850,7 +1840,6 @@ export const organizationDailyActivityCall = async ( extraQueryParams: { organization_ids: organizationIds, }, - timezoneOffset, }); }; @@ -1860,7 +1849,6 @@ export const customerDailyActivityCall = async ( endTime: Date, page: number = 1, customerIds: string[] | null = null, - timezoneOffset?: number, ) => { return fetchDailyActivity({ accessToken, @@ -1871,7 +1859,6 @@ export const customerDailyActivityCall = async ( extraQueryParams: { end_user_ids: customerIds, }, - timezoneOffset, }); }; @@ -1881,7 +1868,6 @@ export const agentDailyActivityCall = async ( endTime: Date, page: number = 1, agentIds: string[] | null = null, - timezoneOffset?: number, ) => { return fetchDailyActivity({ accessToken, @@ -1892,7 +1878,6 @@ export const agentDailyActivityCall = async ( extraQueryParams: { agent_ids: agentIds, }, - timezoneOffset, }); }; @@ -3196,7 +3181,7 @@ export const keyAliasesCall = async ( } }; -export const userDailyActivityAggregatedCall = async (accessToken: string, startTime: Date, endTime: Date, userId: string | null = null, timezoneOffset?: number) => { +export const userDailyActivityAggregatedCall = async (accessToken: string, startTime: Date, endTime: Date, userId: string | null = null) => { /** * Get aggregated daily user activity (no pagination) */ @@ -3213,8 +3198,7 @@ export const userDailyActivityAggregatedCall = async (accessToken: string, start queryParams.append("start_date", formatDate(startTime)); queryParams.append("end_date", formatDate(endTime)); // Send timezone offset so backend can adjust date range for UTC storage - const tz = timezoneOffset !== undefined ? timezoneOffset : new Date().getTimezoneOffset(); - queryParams.append("timezone", tz.toString()); + queryParams.append("timezone", new Date().getTimezoneOffset().toString()); if (userId) { queryParams.append("user_id", userId); } diff --git a/ui/litellm-dashboard/src/components/shared/advanced_date_picker.tsx b/ui/litellm-dashboard/src/components/shared/advanced_date_picker.tsx index 636782df73..4293657b71 100644 --- a/ui/litellm-dashboard/src/components/shared/advanced_date_picker.tsx +++ b/ui/litellm-dashboard/src/components/shared/advanced_date_picker.tsx @@ -1,8 +1,7 @@ -import { CalendarOutlined, ClockCircleOutlined, SearchOutlined } from "@ant-design/icons"; -import { Select } from "antd"; +import { CalendarOutlined, ClockCircleOutlined } from "@ant-design/icons"; import { Button, DateRangePickerValue, Text } from "@tremor/react"; import moment from "moment"; -import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; interface AdvancedDatePickerProps { value: DateRangePickerValue; @@ -10,48 +9,8 @@ interface AdvancedDatePickerProps { label?: string; className?: string; showTimeRange?: boolean; - timezoneOffset?: number; - onTimezoneChange?: (offset: number) => void; } -const getLocalTimezoneOffset = (): number => new Date().getTimezoneOffset(); - -const formatTimezoneLabel = (offsetMinutes: number): string => { - if (offsetMinutes === 0) return "UTC"; - const sign = offsetMinutes > 0 ? "-" : "+"; - const absMinutes = Math.abs(offsetMinutes); - const hours = Math.floor(absMinutes / 60); - const minutes = absMinutes % 60; - const formatted = minutes > 0 ? `${hours}:${String(minutes).padStart(2, "0")}` : `${hours}`; - return `UTC${sign}${formatted}`; -}; - -// Common timezone options: offset in minutes (JS getTimezoneOffset convention: positive = west of UTC) -const TIMEZONE_OPTIONS: { label: string; offset: number }[] = [ - { label: "UTC-10 (Hawaii)", offset: 600 }, - { label: "UTC-9 (Alaska)", offset: 540 }, - { label: "UTC-8 (Pacific)", offset: 480 }, - { label: "UTC-7 (Mountain)", offset: 420 }, - { label: "UTC-6 (Central)", offset: 360 }, - { label: "UTC-5 (Eastern)", offset: 300 }, - { label: "UTC-4 (Atlantic)", offset: 240 }, - { label: "UTC-3 (Buenos Aires)", offset: 180 }, - { label: "UTC (London/UTC)", offset: 0 }, - { label: "UTC+1 (Central Europe)", offset: -60 }, - { label: "UTC+2 (Eastern Europe)", offset: -120 }, - { label: "UTC+3 (Moscow)", offset: -180 }, - { label: "UTC+4 (Dubai)", offset: -240 }, - { label: "UTC+5 (Pakistan)", offset: -300 }, - { label: "UTC+5:30 (India)", offset: -330 }, - { label: "UTC+5:45 (Nepal)", offset: -345 }, - { label: "UTC+6 (Bangladesh)", offset: -360 }, - { label: "UTC+7 (Bangkok)", offset: -420 }, - { label: "UTC+8 (Singapore)", offset: -480 }, - { label: "UTC+9 (Japan/Korea)", offset: -540 }, - { label: "UTC+10 (Sydney)", offset: -600 }, - { label: "UTC+12 (Auckland)", offset: -720 }, -]; - interface RelativeTimeOption { label: string; shortLabel: string; @@ -109,22 +68,7 @@ const AdvancedDatePicker: React.FC = ({ onValueChange, label = "Select Time Range", showTimeRange = true, - timezoneOffset, - onTimezoneChange, }) => { - const timezoneOptions = useMemo(() => { - const localOffset = getLocalTimezoneOffset(); - const hasLocalInList = TIMEZONE_OPTIONS.some((tz) => tz.offset === localOffset); - const opts = TIMEZONE_OPTIONS.map((tz) => ({ - value: tz.offset, - label: tz.label + (tz.offset === localOffset ? " (Local)" : ""), - })); - if (!hasLocalInList) { - opts.unshift({ value: localOffset, label: `Local (${formatTimezoneLabel(localOffset)})` }); - } - return opts; - }, []); - const [isOpen, setIsOpen] = useState(false); const [tempValue, setTempValue] = useState(value); const [selectedOption, setSelectedOption] = useState(null); @@ -134,7 +78,6 @@ const AdvancedDatePicker: React.FC = ({ const [endDate, setEndDate] = useState(""); const dropdownRef = useRef(null); - const settingsPanelRef = useRef(null); // Function to check if current value matches a relative time option const getMatchingOption = useCallback((currentValue: DateRangePickerValue): string | null => { @@ -400,29 +343,6 @@ const AdvancedDatePicker: React.FC = ({
- {/* Timezone selector */} - {onTimezoneChange && ( -
- -