Group F - Fix spending per tenant
All checks were successful
Build and Push / build (push) Successful in 1m22s

This commit is contained in:
2026-05-01 13:34:56 +02:00
parent 2cf5b56441
commit f308c84325
4 changed files with 169 additions and 92 deletions

View File

@@ -94,17 +94,27 @@ function UsageChart({ data }: { data: DailyUsage[] }) {
/**
* Usage display widget.
*
* - Customers: don't pass teamId or keyAlias — the backend resolves both
* from the session-bound tenant.
* - Admins inspecting a specific tenant: pass `teamId` (the org-level
* LiteLLM team id) AND `keyAlias` (the tenant's virtual-key alias).
* Without `keyAlias`, the response includes spend from sibling tenants
* in the same org, since teams are shared since Slice 2.
* Pass `tenant=<name>` for the canonical path — works for both
* customers and admins, the API resolves team+alias from the tenant
* CR's status. The visibility check on the API ensures users can't
* query tenants they shouldn't see.
*
* `teamId`/`keyAlias` remain available as a platform-admin escape
* hatch for cross-org debugging, but the tenant-detail and dashboard
* paths should always use `tenant`.
*
* Bug 19 fix: previous version omitted both props for customer
* sessions, expecting the API to "figure it out". The API's fallback
* was "first visible tenant", which meant siblings in the same org
* showed identical numbers regardless of which detail page was open.
* Now the page passes the tenant name explicitly; no fallback exists.
*/
export function UsageDisplay({
tenant,
teamId,
keyAlias,
}: {
tenant?: string | null;
teamId?: string | null;
keyAlias?: string | null;
}) {
@@ -121,11 +131,13 @@ export function UsageDisplay({
setError(null);
const params = new URLSearchParams({ month });
if (teamId) {
if (tenant) {
params.set("tenant", tenant);
} else if (teamId) {
// Admin escape hatch — only honoured by the API when the
// viewer is platform-role.
params.set("teamId", teamId);
}
if (keyAlias) {
params.set("keyAlias", keyAlias);
if (keyAlias) params.set("keyAlias", keyAlias);
}
fetch(`/api/usage?${params}`)
@@ -133,7 +145,7 @@ export function UsageDisplay({
.then(setData)
.catch((e) => setError(e.message))
.finally(() => setLoading(false));
}, [teamId, keyAlias, month]);
}, [tenant, teamId, keyAlias, month]);
useEffect(() => { fetchUsage(); }, [fetchUsage]);