@acarmisc/backstage-plugin-litellm 0.43.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.ts +4 -1
- package/dist/components/GenerateKeyDialog.d.ts +21 -0
- package/dist/components/TeamUsage.d.ts +14 -1
- package/dist/index.cjs.js +101 -7
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.esm.js +101 -7
- package/dist/index.esm.js.map +2 -2
- package/dist/permissions.d.ts +1 -0
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
package/dist/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type FetchApi, type DiscoveryApi } from '@backstage/frontend-plugin-api';
|
|
2
|
-
import { UserInfo, VirtualKey, ModelInfo, UsageMetrics, TeamMemberUsage, TeamInfo, GenerateKeyRequest, GenerateKeyResponse, UpdateKeyRequest, AuditLogsParams, PaginatedAuditLogs, SpendLogsParams, PaginatedSpendLogs, LiteLlmConfig, QualityResponse, VectorStoreInfo, McpServerInfo, CreateTeamRequest, CreateTeamResponse, UpdateTeamRequest } from './types';
|
|
2
|
+
import { UserInfo, VirtualKey, ModelInfo, UsageMetrics, TeamMemberUsage, TeamKeyUsage, TeamInfo, GenerateKeyRequest, GenerateKeyResponse, UpdateKeyRequest, AuditLogsParams, PaginatedAuditLogs, SpendLogsParams, PaginatedSpendLogs, LiteLlmConfig, QualityResponse, VectorStoreInfo, McpServerInfo, CreateTeamRequest, CreateTeamResponse, UpdateTeamRequest } from './types';
|
|
3
3
|
export declare class ApiError extends Error {
|
|
4
4
|
body: unknown;
|
|
5
5
|
status: number;
|
|
@@ -49,6 +49,8 @@ export interface LiteLlmApiInterface {
|
|
|
49
49
|
getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics>;
|
|
50
50
|
/** Per-member breakdown; rejects (403/404) when the caller may not see it. */
|
|
51
51
|
getTeamMemberUsage(teamId: string, startDate: string, endDate: string): Promise<TeamMemberUsage>;
|
|
52
|
+
/** A team's keys with per-key usage; same access rules as the per-member breakdown. */
|
|
53
|
+
getTeamKeyUsage(teamId: string, startDate: string, endDate: string): Promise<TeamKeyUsage>;
|
|
52
54
|
getAuditLogs(params: AuditLogsParams): Promise<PaginatedAuditLogs>;
|
|
53
55
|
getSpendLogs(params: SpendLogsParams): Promise<PaginatedSpendLogs>;
|
|
54
56
|
/** Langfuse quality summary; `{configured:false}` when Langfuse is off. */
|
|
@@ -120,6 +122,7 @@ export declare class LiteLlmApi implements LiteLlmApiInterface {
|
|
|
120
122
|
getUsage(startDate: string, endDate: string): Promise<UsageMetrics>;
|
|
121
123
|
getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics>;
|
|
122
124
|
getTeamMemberUsage(teamId: string, startDate: string, endDate: string): Promise<TeamMemberUsage>;
|
|
125
|
+
getTeamKeyUsage(teamId: string, startDate: string, endDate: string): Promise<TeamKeyUsage>;
|
|
123
126
|
getSpendLogs(params: SpendLogsParams): Promise<PaginatedSpendLogs>;
|
|
124
127
|
getQuality(params: SpendLogsParams): Promise<QualityResponse>;
|
|
125
128
|
getConfig(): Promise<LiteLlmConfig>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { GenerateKeyRequest, GenerateKeyResponse, LiteLlmConfig, ModelInfo, TeamInfo, VirtualKey } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use {@link KeyFormDialog} with `mode="create"` instead — this
|
|
5
|
+
* wrapper only forwards props for backwards compatibility with the public
|
|
6
|
+
* entrypoint and will be removed in a future release.
|
|
7
|
+
*/
|
|
8
|
+
export declare const GenerateKeyDialog: FC<{
|
|
9
|
+
open: boolean;
|
|
10
|
+
onClose: () => void;
|
|
11
|
+
keys: VirtualKey[];
|
|
12
|
+
models: ModelInfo[];
|
|
13
|
+
teams: TeamInfo[];
|
|
14
|
+
username?: string;
|
|
15
|
+
keyGenerationSettings?: {
|
|
16
|
+
allowUnlimitedBudget: boolean;
|
|
17
|
+
teamRequired: boolean;
|
|
18
|
+
};
|
|
19
|
+
onGenerateKey: (request: GenerateKeyRequest) => Promise<GenerateKeyResponse>;
|
|
20
|
+
onGetConfig: () => Promise<LiteLlmConfig>;
|
|
21
|
+
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
-
import { McpServerInfo, TeamInfo, TeamMemberUsage, UsageMetrics, VectorStoreInfo } from '../types';
|
|
2
|
+
import { McpServerInfo, TeamInfo, TeamKeyUsage, TeamMemberUsage, UsageMetrics, VectorStoreInfo } from '../types';
|
|
3
3
|
/**
|
|
4
4
|
* Per-member usage for the period, sorted by spend. Dollars are replaced by
|
|
5
5
|
* the share of team spend when the backend hides them.
|
|
@@ -7,6 +7,13 @@ import { McpServerInfo, TeamInfo, TeamMemberUsage, UsageMetrics, VectorStoreInfo
|
|
|
7
7
|
export declare const MemberUsageTable: FC<{
|
|
8
8
|
usage: TeamMemberUsage;
|
|
9
9
|
}>;
|
|
10
|
+
/**
|
|
11
|
+
* A team's keys with the period's usage, for team leads. The backend never
|
|
12
|
+
* sends secrets; dollars are dropped when it hides them.
|
|
13
|
+
*/
|
|
14
|
+
export declare const TeamKeyUsageTable: FC<{
|
|
15
|
+
usage: TeamKeyUsage;
|
|
16
|
+
}>;
|
|
10
17
|
interface TeamUsageProps {
|
|
11
18
|
teams: TeamInfo[];
|
|
12
19
|
loading: boolean;
|
|
@@ -15,6 +22,12 @@ interface TeamUsageProps {
|
|
|
15
22
|
/** Per-member breakdown for a team; null hides the section. */
|
|
16
23
|
getTeamMemberUsage?: (teamId: string) => TeamMemberUsage | null;
|
|
17
24
|
getTeamMemberUsageLoading?: (teamId: string) => boolean;
|
|
25
|
+
/** Per-key usage for a team; null hides the section. */
|
|
26
|
+
getTeamKeyUsage?: (teamId: string) => TeamKeyUsage | null;
|
|
27
|
+
getTeamKeyUsageLoading?: (teamId: string) => boolean;
|
|
28
|
+
/** True when the breakdown failed for a reason other than refusal: shows a caption. */
|
|
29
|
+
getTeamMemberUsageFailed?: (teamId: string) => boolean;
|
|
30
|
+
getTeamKeyUsageFailed?: (teamId: string) => boolean;
|
|
18
31
|
canManage?: boolean;
|
|
19
32
|
onEditTeam?: (team: TeamInfo) => void;
|
|
20
33
|
/** When true (with `onCreateTeam`), a "Create Team" action renders in the section header. */
|
package/dist/index.cjs.js
CHANGED
|
@@ -321,6 +321,12 @@ var init_api = __esm({
|
|
|
321
321
|
end_date: endDate
|
|
322
322
|
});
|
|
323
323
|
}
|
|
324
|
+
async getTeamKeyUsage(teamId, startDate, endDate) {
|
|
325
|
+
return this.get(`/teams/${encodeURIComponent(teamId)}/usage/keys`, {
|
|
326
|
+
start_date: startDate,
|
|
327
|
+
end_date: endDate
|
|
328
|
+
});
|
|
329
|
+
}
|
|
324
330
|
async getSpendLogs(params) {
|
|
325
331
|
const strParams = {
|
|
326
332
|
start_date: params.startDate,
|
|
@@ -5054,7 +5060,7 @@ function budgetStatValue(hidden, budget) {
|
|
|
5054
5060
|
if (budget > 0) return fmtUsd2(budget);
|
|
5055
5061
|
return "Unlimited";
|
|
5056
5062
|
}
|
|
5057
|
-
var import_react10, import_Paper8, import_Box14, import_Typography12, import_Skeleton5, import_Divider3, import_Table4, import_TableBody4, import_TableCell4, import_TableHead4, import_TableRow4, import_TableContainer4, import_Collapse2, import_IconButton6, import_Button6, import_CircularProgress4, import_styles10, import_Tooltip5, import_icons_material7, import_recharts2, import_jsx_runtime15, fmtUsd2, monoSx, MemberUsageTable, TeamCard, TeamUsage;
|
|
5063
|
+
var import_react10, import_Paper8, import_Box14, import_Typography12, import_Skeleton5, import_Divider3, import_Table4, import_TableBody4, import_TableCell4, import_TableHead4, import_TableRow4, import_TableContainer4, import_Collapse2, import_IconButton6, import_Button6, import_CircularProgress4, import_styles10, import_Tooltip5, import_icons_material7, import_recharts2, import_jsx_runtime15, fmtUsd2, monoSx, MemberUsageTable, TeamKeyUsageTable, TeamCard, TeamUsage;
|
|
5058
5064
|
var init_TeamUsage = __esm({
|
|
5059
5065
|
"src/components/TeamUsage.tsx"() {
|
|
5060
5066
|
"use strict";
|
|
@@ -5117,7 +5123,47 @@ var init_TeamUsage = __esm({
|
|
|
5117
5123
|
}) })
|
|
5118
5124
|
] }) });
|
|
5119
5125
|
};
|
|
5120
|
-
|
|
5126
|
+
TeamKeyUsageTable = ({ usage }) => {
|
|
5127
|
+
const hidden = usage.budget_hidden === true;
|
|
5128
|
+
if (!usage.keys.length) {
|
|
5129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "This team has no keys." });
|
|
5130
|
+
}
|
|
5131
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableContainer4.default, { component: import_Paper8.default, variant: "outlined", sx: { borderRadius: 1.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Table4.default, { size: "small", sx: dataTableSx, "aria-label": "Keys by member", children: [
|
|
5132
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableHead4.default, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableRow4.default, { children: [
|
|
5133
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: "Key" }),
|
|
5134
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: "Owner" }),
|
|
5135
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: "Created" }),
|
|
5136
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: "Status" }),
|
|
5137
|
+
!hidden && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Spend" }),
|
|
5138
|
+
!hidden && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Budget" }),
|
|
5139
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Tokens" }),
|
|
5140
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Requests" })
|
|
5141
|
+
] }) }),
|
|
5142
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableBody4.default, { children: usage.keys.map((k) => {
|
|
5143
|
+
const owner = k.display_name ?? k.user_email ?? k.user_id;
|
|
5144
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableRow4.default, { children: [
|
|
5145
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableCell4.default, { children: [
|
|
5146
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", children: k.key_alias ?? k.key }),
|
|
5147
|
+
k.key_alias && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", sx: monoSx, children: k.key })
|
|
5148
|
+
] }),
|
|
5149
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: owner ?? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "\u2014" }) }),
|
|
5150
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: fmtDateShort(k.created_at) }),
|
|
5151
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5152
|
+
StatusPill,
|
|
5153
|
+
{
|
|
5154
|
+
label: k.blocked ? "Blocked" : "Active",
|
|
5155
|
+
tone: k.blocked ? "danger" : "success"
|
|
5156
|
+
}
|
|
5157
|
+
) }),
|
|
5158
|
+
!hidden && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: fmtUsd2(k.spend) }),
|
|
5159
|
+
!hidden && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: k.max_budget === void 0 ? "Unlimited" : fmtUsd2(k.max_budget) }),
|
|
5160
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: fmtCompact(k.total_tokens) }),
|
|
5161
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: k.api_requests.toLocaleString() })
|
|
5162
|
+
] }, k.key);
|
|
5163
|
+
}) })
|
|
5164
|
+
] }) });
|
|
5165
|
+
};
|
|
5166
|
+
TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, memberUsageFailed, keyUsage, keyUsageLoading, keyUsageFailed, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand, vectorStores, mcpServers }) => {
|
|
5121
5167
|
const [expanded, setExpanded] = (0, import_react10.useState)(false);
|
|
5122
5168
|
const chart = useChartTheme();
|
|
5123
5169
|
const handleExpandChange = (newExpanded) => {
|
|
@@ -5316,9 +5362,17 @@ var init_TeamUsage = __esm({
|
|
|
5316
5362
|
renderNamedTags("Knowledge bases", team.object_permission?.vector_stores, vectorStores),
|
|
5317
5363
|
renderNamedTags("MCP servers", team.object_permission?.mcp_servers, mcpServers),
|
|
5318
5364
|
renderDailySpendSection(),
|
|
5319
|
-
(memberUsageLoading || memberUsage) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5365
|
+
(memberUsageLoading || memberUsage || memberUsageFailed) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5320
5366
|
sectionLabel("Usage by member"),
|
|
5321
|
-
memberUsage
|
|
5367
|
+
memberUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MemberUsageTable, { usage: memberUsage }),
|
|
5368
|
+
!memberUsage && memberUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-member usage" }),
|
|
5369
|
+
!memberUsage && !memberUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { display: "flex", justifyContent: "center", py: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_CircularProgress4.default, { size: 22 }) })
|
|
5370
|
+
] }),
|
|
5371
|
+
(keyUsageLoading || keyUsage || keyUsageFailed) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5372
|
+
sectionLabel("Keys by member"),
|
|
5373
|
+
keyUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TeamKeyUsageTable, { usage: keyUsage }),
|
|
5374
|
+
!keyUsage && keyUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-key usage" }),
|
|
5375
|
+
!keyUsage && !keyUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { display: "flex", justifyContent: "center", py: 2, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_CircularProgress4.default, { size: 22 }) })
|
|
5322
5376
|
] }),
|
|
5323
5377
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
|
|
5324
5378
|
sectionLabel("Members"),
|
|
@@ -5376,6 +5430,10 @@ var init_TeamUsage = __esm({
|
|
|
5376
5430
|
getTeamUsageLoading,
|
|
5377
5431
|
getTeamMemberUsage,
|
|
5378
5432
|
getTeamMemberUsageLoading,
|
|
5433
|
+
getTeamKeyUsage,
|
|
5434
|
+
getTeamKeyUsageLoading,
|
|
5435
|
+
getTeamMemberUsageFailed,
|
|
5436
|
+
getTeamKeyUsageFailed,
|
|
5379
5437
|
canManage,
|
|
5380
5438
|
onEditTeam,
|
|
5381
5439
|
canCreate,
|
|
@@ -5439,6 +5497,10 @@ var init_TeamUsage = __esm({
|
|
|
5439
5497
|
usageLoading: getTeamUsageLoading(team.team_id),
|
|
5440
5498
|
memberUsage: getTeamMemberUsage?.(team.team_id) ?? null,
|
|
5441
5499
|
memberUsageLoading: getTeamMemberUsageLoading?.(team.team_id) ?? false,
|
|
5500
|
+
keyUsage: getTeamKeyUsage?.(team.team_id) ?? null,
|
|
5501
|
+
keyUsageLoading: getTeamKeyUsageLoading?.(team.team_id) ?? false,
|
|
5502
|
+
memberUsageFailed: getTeamMemberUsageFailed?.(team.team_id) ?? false,
|
|
5503
|
+
keyUsageFailed: getTeamKeyUsageFailed?.(team.team_id) ?? false,
|
|
5442
5504
|
canManage,
|
|
5443
5505
|
onEditTeam,
|
|
5444
5506
|
canManageMembers: canManageMembers?.(team),
|
|
@@ -6262,7 +6324,7 @@ function initDateRange() {
|
|
|
6262
6324
|
else start.setDate(start.getDate() - 7);
|
|
6263
6325
|
return { start, end };
|
|
6264
6326
|
}
|
|
6265
|
-
var import_react13, import_Box17, import_Alert6, import_Button8, import_Typography15, import_Tabs2, import_Tab2, import_Grid3, import_Accordion2, import_AccordionSummary2, import_AccordionDetails2, import_ExpandMore, import_react_router_dom, import_react_use2, import_core_plugin_api5, import_core_components3, import_plugin_permission_react3, import_backstage_plugin_litellm_common5, import_jsx_runtime18, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
|
|
6327
|
+
var import_react13, import_Box17, import_Alert6, import_Button8, import_Typography15, import_Tabs2, import_Tab2, import_Grid3, import_Accordion2, import_AccordionSummary2, import_AccordionDetails2, import_ExpandMore, import_react_router_dom, import_react_use2, import_core_plugin_api5, import_core_components3, import_plugin_permission_react3, import_backstage_plugin_litellm_common5, import_jsx_runtime18, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, isRefusal, LiteLLMPage;
|
|
6266
6328
|
var init_LiteLLMPage = __esm({
|
|
6267
6329
|
"src/components/LiteLLMPage.tsx"() {
|
|
6268
6330
|
"use strict";
|
|
@@ -6302,6 +6364,7 @@ var init_LiteLLMPage = __esm({
|
|
|
6302
6364
|
PERIOD_LS_KEY2 = "litellm_usage_period";
|
|
6303
6365
|
PAGE_TABS = ["overview", "keys", "teams", "models", "insights"];
|
|
6304
6366
|
isPageTab = (v) => !!v && PAGE_TABS.includes(v);
|
|
6367
|
+
isRefusal = (err) => err instanceof ApiError && (err.status === 403 || err.status === 404);
|
|
6305
6368
|
LiteLLMPage = () => {
|
|
6306
6369
|
const api = (0, import_core_plugin_api5.useApi)(liteLlmApiRef);
|
|
6307
6370
|
const alertApi = (0, import_core_plugin_api5.useApi)(import_core_plugin_api5.alertApiRef);
|
|
@@ -6385,6 +6448,10 @@ var init_LiteLLMPage = __esm({
|
|
|
6385
6448
|
const [teamUsageLoading, setTeamUsageLoading] = (0, import_react13.useState)({});
|
|
6386
6449
|
const [memberUsageCache, setMemberUsageCache] = (0, import_react13.useState)({});
|
|
6387
6450
|
const [memberUsageLoading, setMemberUsageLoading] = (0, import_react13.useState)({});
|
|
6451
|
+
const [keyUsageCache, setKeyUsageCache] = (0, import_react13.useState)({});
|
|
6452
|
+
const [keyUsageLoading, setKeyUsageLoading] = (0, import_react13.useState)({});
|
|
6453
|
+
const [memberUsageFailed, setMemberUsageFailed] = (0, import_react13.useState)({});
|
|
6454
|
+
const [keyUsageFailed, setKeyUsageFailed] = (0, import_react13.useState)({});
|
|
6388
6455
|
const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use2.useAsync)(
|
|
6389
6456
|
() => api.getUserInfo(),
|
|
6390
6457
|
[api]
|
|
@@ -6451,6 +6518,10 @@ var init_LiteLLMPage = __esm({
|
|
|
6451
6518
|
setTeamUsageLoading({});
|
|
6452
6519
|
setMemberUsageCache({});
|
|
6453
6520
|
setMemberUsageLoading({});
|
|
6521
|
+
setKeyUsageCache({});
|
|
6522
|
+
setKeyUsageLoading({});
|
|
6523
|
+
setMemberUsageFailed({});
|
|
6524
|
+
setKeyUsageFailed({});
|
|
6454
6525
|
}, [setDateRange, setCurrentPreset]);
|
|
6455
6526
|
const loadTeamUsage = (0, import_react13.useCallback)(async (teamId) => {
|
|
6456
6527
|
if (teamUsageCache[teamId] !== void 0 || teamUsageLoading[teamId]) return;
|
|
@@ -6474,12 +6545,28 @@ var init_LiteLLMPage = __esm({
|
|
|
6474
6545
|
const endDate = toLocalDay(dateRange.end);
|
|
6475
6546
|
const data = await api.getTeamMemberUsage(teamId, startDate, endDate);
|
|
6476
6547
|
setMemberUsageCache((prev) => ({ ...prev, [teamId]: data }));
|
|
6477
|
-
} catch {
|
|
6548
|
+
} catch (err) {
|
|
6478
6549
|
setMemberUsageCache((prev) => ({ ...prev, [teamId]: null }));
|
|
6550
|
+
setMemberUsageFailed((prev) => ({ ...prev, [teamId]: !isRefusal(err) }));
|
|
6479
6551
|
} finally {
|
|
6480
6552
|
setMemberUsageLoading((prev) => ({ ...prev, [teamId]: false }));
|
|
6481
6553
|
}
|
|
6482
6554
|
}, [api, dateRange, memberUsageCache, memberUsageLoading]);
|
|
6555
|
+
const loadKeyUsage = (0, import_react13.useCallback)(async (teamId) => {
|
|
6556
|
+
if (keyUsageCache[teamId] !== void 0 || keyUsageLoading[teamId]) return;
|
|
6557
|
+
setKeyUsageLoading((prev) => ({ ...prev, [teamId]: true }));
|
|
6558
|
+
try {
|
|
6559
|
+
const startDate = toLocalDay(dateRange.start);
|
|
6560
|
+
const endDate = toLocalDay(dateRange.end);
|
|
6561
|
+
const data = await api.getTeamKeyUsage(teamId, startDate, endDate);
|
|
6562
|
+
setKeyUsageCache((prev) => ({ ...prev, [teamId]: data }));
|
|
6563
|
+
} catch (err) {
|
|
6564
|
+
setKeyUsageCache((prev) => ({ ...prev, [teamId]: null }));
|
|
6565
|
+
setKeyUsageFailed((prev) => ({ ...prev, [teamId]: !isRefusal(err) }));
|
|
6566
|
+
} finally {
|
|
6567
|
+
setKeyUsageLoading((prev) => ({ ...prev, [teamId]: false }));
|
|
6568
|
+
}
|
|
6569
|
+
}, [api, dateRange, keyUsageCache, keyUsageLoading]);
|
|
6483
6570
|
const allowedModels = (0, import_react13.useMemo)(() => {
|
|
6484
6571
|
if (!allModels?.length) return [];
|
|
6485
6572
|
const userModels = userInfo?.models;
|
|
@@ -6777,6 +6864,10 @@ var init_LiteLLMPage = __esm({
|
|
|
6777
6864
|
getTeamUsageLoading: (teamId) => teamUsageLoading[teamId] ?? false,
|
|
6778
6865
|
getTeamMemberUsage: (teamId) => memberUsageCache[teamId] ?? null,
|
|
6779
6866
|
getTeamMemberUsageLoading: (teamId) => memberUsageLoading[teamId] ?? false,
|
|
6867
|
+
getTeamKeyUsage: (teamId) => keyUsageCache[teamId] ?? null,
|
|
6868
|
+
getTeamKeyUsageLoading: (teamId) => keyUsageLoading[teamId] ?? false,
|
|
6869
|
+
getTeamMemberUsageFailed: (teamId) => memberUsageFailed[teamId] ?? false,
|
|
6870
|
+
getTeamKeyUsageFailed: (teamId) => keyUsageFailed[teamId] ?? false,
|
|
6780
6871
|
canManage: teamMgmtEnabled && canManageTeam && !readOnly,
|
|
6781
6872
|
onEditTeam: (t) => setManageTeam({ mode: "edit", team: t }),
|
|
6782
6873
|
canCreate: teamMgmtEnabled && canCreateTeam && !readOnly,
|
|
@@ -6788,7 +6879,10 @@ var init_LiteLLMPage = __esm({
|
|
|
6788
6879
|
readOnly,
|
|
6789
6880
|
onTeamExpand: (team) => {
|
|
6790
6881
|
loadTeamUsage(team.team_id);
|
|
6791
|
-
if (liteLlmConfig?.teamUsage?.memberBreakdown)
|
|
6882
|
+
if (liteLlmConfig?.teamUsage?.memberBreakdown) {
|
|
6883
|
+
loadMemberUsage(team.team_id);
|
|
6884
|
+
loadKeyUsage(team.team_id);
|
|
6885
|
+
}
|
|
6792
6886
|
}
|
|
6793
6887
|
}
|
|
6794
6888
|
);
|