diff --git a/litellm/proxy/management_endpoints/common_daily_activity.py b/litellm/proxy/management_endpoints/common_daily_activity.py index c1e21b70ad7..aab4d1b2a69 100644 --- a/litellm/proxy/management_endpoints/common_daily_activity.py +++ b/litellm/proxy/management_endpoints/common_daily_activity.py @@ -183,8 +183,8 @@ class _GroupingSetsRow(_RollupMetricsRow): endpoint: str | None group_level: int distinct_api_keys: int | None - key_spend: float | None - remaining_api_keys: int | None + key_spend: float | None = None + remaining_api_keys: int | None = None class _EntityRollupRow(_RollupMetricsRow): @@ -913,7 +913,7 @@ def _build_aggregated_sql_query( | GROUPING(model, {_MODEL_GROUP_EXPR}, custom_llm_provider, mcp_namespaced_tool_name, endpoint) AS group_level, - NULL::bigint AS distinct_api_keys, NULL::float AS key_spend, + NULL::bigint AS distinct_api_keys, NULL::float8 AS key_spend, NULL::bigint AS remaining_api_keys,{metric_select} FROM {_key_free_source(pg_table, where_clause, marker_param)} GROUP BY GROUPING SETS ( @@ -1530,18 +1530,14 @@ async def get_daily_activity_aggregated( records: Final = [_GroupingSetsRow(**row) for row in (raw_rows or ())] total_api_keys: Final = next((r.distinct_api_keys for r in records if r.distinct_api_keys is not None), 0) - remaining_api_keys: Final = next( - (r.remaining_api_keys or 0 for r in records if getattr(r, "remaining_api_keys", None) is not None), - 0, - ) - page_last: Final = max( - (r for r in records if r.api_key is not None and getattr(r, "key_spend", None) is not None), - key=lambda r: (-(r.key_spend or 0.0), r.api_key or ""), - default=None, + remaining_api_keys: Final = next((r.remaining_api_keys for r in records if r.remaining_api_keys is not None), 0) + page_keys: Final = tuple( + (spend, key) for r in records if (spend := r.key_spend) is not None and (key := r.api_key) is not None ) + page_last: Final = max(page_keys, key=lambda k: (-k[0], k[1]), default=None) next_cursor: Final = ( - KeyPageCursor(page_last.key_spend or 0.0, page_last.api_key or "").encode() - if remaining_api_keys > USAGE_TOP_API_KEYS_LIMIT and page_last is not None + KeyPageCursor(*page_last).encode() + if page_last is not None and remaining_api_keys > USAGE_TOP_API_KEYS_LIMIT else None ) diff --git a/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py b/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py index 544e0e6f8ad..17b02ec02f2 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py +++ b/tests/test_litellm/proxy/management_endpoints/test_common_daily_activity.py @@ -1877,6 +1877,7 @@ async def test_get_daily_activity_aggregated_reports_exact_limit_key_count_as_co assert result.metadata.total_api_keys == USAGE_TOP_API_KEYS_LIMIT assert result.metadata.api_key_limit == USAGE_TOP_API_KEYS_LIMIT + assert result.metadata.next_cursor is None assert len(result.results[0].breakdown.api_keys) == USAGE_TOP_API_KEYS_LIMIT diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 54398a04d6e..daf12d11743 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -1786,7 +1786,7 @@ "count": 1 }, "max-params": { - "count": 22 + "count": 21 }, "no-nested-ternary": { "count": 5 @@ -2432,4 +2432,4 @@ "count": 1 } } -} +} \ No newline at end of file diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 53abbac20f9..f2c4c0c3258 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -1445,9 +1445,9 @@ export const teamDailyActivityAggregatedCall = async ( accessToken: string, startTime: Date, endTime: Date, - teamIds: string[] | null = null, - cursor: string | null = null, + ...options: [teamIds?: string[] | null, cursor?: string | null] ) => { + const [teamIds = null, cursor = null] = options; /** * Get aggregated daily team activity with per-team breakdown (no pagination) */