@acarmisc/backstage-plugin-litellm 0.44.0 → 0.46.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/components/GenerateKeyDialog.d.ts +21 -0
- package/dist/components/TeamUsage.d.ts +7 -3
- package/dist/index.cjs.js +80 -40
- package/dist/index.cjs.js.map +3 -3
- package/dist/index.esm.js +80 -40
- package/dist/index.esm.js.map +2 -2
- package/dist/permissions.d.ts +1 -0
- package/package.json +1 -1
|
@@ -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,10 +1,11 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
2
|
import { McpServerInfo, TeamInfo, TeamKeyUsage, TeamMemberUsage, UsageMetrics, VectorStoreInfo } from '../types';
|
|
3
3
|
/**
|
|
4
|
-
* Per-member usage for the period, sorted by spend
|
|
5
|
-
* the share of team spend when the
|
|
4
|
+
* Per-member usage for the period as mini-cards, sorted by spend (the order
|
|
5
|
+
* the backend sends). Dollars are replaced by the share of team spend when the
|
|
6
|
+
* backend hides them.
|
|
6
7
|
*/
|
|
7
|
-
export declare const
|
|
8
|
+
export declare const MemberUsageCards: FC<{
|
|
8
9
|
usage: TeamMemberUsage;
|
|
9
10
|
}>;
|
|
10
11
|
/**
|
|
@@ -25,6 +26,9 @@ interface TeamUsageProps {
|
|
|
25
26
|
/** Per-key usage for a team; null hides the section. */
|
|
26
27
|
getTeamKeyUsage?: (teamId: string) => TeamKeyUsage | null;
|
|
27
28
|
getTeamKeyUsageLoading?: (teamId: string) => boolean;
|
|
29
|
+
/** True when the breakdown failed for a reason other than refusal: shows a caption. */
|
|
30
|
+
getTeamMemberUsageFailed?: (teamId: string) => boolean;
|
|
31
|
+
getTeamKeyUsageFailed?: (teamId: string) => boolean;
|
|
28
32
|
canManage?: boolean;
|
|
29
33
|
onEditTeam?: (team: TeamInfo) => void;
|
|
30
34
|
/** When true (with `onCreateTeam`), a "Create Team" action renders in the section header. */
|
package/dist/index.cjs.js
CHANGED
|
@@ -5060,7 +5060,7 @@ function budgetStatValue(hidden, budget) {
|
|
|
5060
5060
|
if (budget > 0) return fmtUsd2(budget);
|
|
5061
5061
|
return "Unlimited";
|
|
5062
5062
|
}
|
|
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,
|
|
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, fmtShare, MemberUsageCards, TeamKeyUsageTable, TeamCard, TeamUsage;
|
|
5064
5064
|
var init_TeamUsage = __esm({
|
|
5065
5065
|
"src/components/TeamUsage.tsx"() {
|
|
5066
5066
|
"use strict";
|
|
@@ -5088,40 +5088,63 @@ var init_TeamUsage = __esm({
|
|
|
5088
5088
|
import_jsx_runtime15 = require("react/jsx-runtime");
|
|
5089
5089
|
fmtUsd2 = (n) => `$${(n ?? 0).toFixed(2)}`;
|
|
5090
5090
|
monoSx = { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 };
|
|
5091
|
-
|
|
5091
|
+
fmtShare = (pct) => `${pct.toFixed(pct > 0 && pct < 1 ? 1 : 0)}%`;
|
|
5092
|
+
MemberUsageCards = ({ usage }) => {
|
|
5092
5093
|
const hidden = usage.budget_hidden === true;
|
|
5093
5094
|
if (!usage.members.length) {
|
|
5094
5095
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "No members or activity in this period." });
|
|
5095
5096
|
}
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5097
|
+
const people = usage.members.filter((m) => m.user_id !== null).length;
|
|
5098
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
|
|
5099
|
+
!hidden && people > 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1 }, children: `Team spend ${fmtUsd2(usage.total_spend)} \xB7 avg ${fmtUsd2(usage.total_spend / people)} per member` }),
|
|
5100
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5101
|
+
import_Box14.default,
|
|
5102
|
+
{
|
|
5103
|
+
role: "list",
|
|
5104
|
+
"aria-label": "Usage by member",
|
|
5105
|
+
sx: { display: "grid", gap: 1.5, gridTemplateColumns: "repeat(auto-fill, minmax(230px, 1fr))" },
|
|
5106
|
+
children: usage.members.map((m) => {
|
|
5107
|
+
const name = m.display_name ?? m.user_email ?? m.user_id;
|
|
5108
|
+
let sub = null;
|
|
5109
|
+
if (m.display_name) sub = m.user_email ?? m.user_id;
|
|
5110
|
+
else if (m.user_email && m.user_id !== m.user_email) sub = m.user_id;
|
|
5111
|
+
const stats = [
|
|
5112
|
+
["Tokens", fmtCompact(m.total_tokens)],
|
|
5113
|
+
["Requests", m.api_requests.toLocaleString()],
|
|
5114
|
+
["Success", m.success_rate === null ? "\u2014" : `${m.success_rate.toFixed(0)}%`],
|
|
5115
|
+
["Keys", m.user_id === null ? "\u2014" : String(m.key_count)]
|
|
5116
|
+
];
|
|
5117
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
5118
|
+
import_Paper8.default,
|
|
5119
|
+
{
|
|
5120
|
+
role: "listitem",
|
|
5121
|
+
variant: "outlined",
|
|
5122
|
+
sx: { borderRadius: 1.5, p: 1.5, minWidth: 0 },
|
|
5123
|
+
children: [
|
|
5124
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 1, children: [
|
|
5125
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { minWidth: 0, children: m.user_id === null ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Tooltip5.default, { title: "Activity of keys that were deleted or have no owner", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", sx: { fontStyle: "italic" }, children: "Unattributed" }) }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
|
|
5126
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", fontWeight: 600, noWrap: true, children: name }),
|
|
5127
|
+
sub && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", noWrap: true, sx: { ...monoSx, display: "block" }, children: sub })
|
|
5128
|
+
] }) }),
|
|
5129
|
+
m.role && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false })
|
|
5130
|
+
] }),
|
|
5131
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mt: 1.5, display: "flex", alignItems: "baseline", justifyContent: "space-between", children: [
|
|
5132
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "h6", component: "span", sx: { lineHeight: 1.2 }, children: hidden ? fmtShare(m.spend_share_pct) : fmtUsd2(m.spend) }),
|
|
5133
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: hidden ? "of team usage" : `${fmtShare(m.spend_share_pct)} of team` })
|
|
5134
|
+
] }),
|
|
5135
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { mt: 0.75, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Meter, { value: m.spend_share_pct, ariaLabel: `${name ?? "Unattributed"} share of team spend` }) }),
|
|
5136
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { mt: 1.5, display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 0.5, children: stats.map(([label, value]) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
|
|
5137
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", display: "block", children: label }),
|
|
5138
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", children: value })
|
|
5139
|
+
] }, label)) })
|
|
5140
|
+
]
|
|
5141
|
+
},
|
|
5142
|
+
m.user_id ?? "__unattributed"
|
|
5143
|
+
);
|
|
5144
|
+
})
|
|
5145
|
+
}
|
|
5146
|
+
)
|
|
5147
|
+
] });
|
|
5125
5148
|
};
|
|
5126
5149
|
TeamKeyUsageTable = ({ usage }) => {
|
|
5127
5150
|
const hidden = usage.budget_hidden === true;
|
|
@@ -5163,7 +5186,7 @@ var init_TeamUsage = __esm({
|
|
|
5163
5186
|
}) })
|
|
5164
5187
|
] }) });
|
|
5165
5188
|
};
|
|
5166
|
-
TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, keyUsage, keyUsageLoading, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand, vectorStores, mcpServers }) => {
|
|
5189
|
+
TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, memberUsageFailed, keyUsage, keyUsageLoading, keyUsageFailed, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand, vectorStores, mcpServers }) => {
|
|
5167
5190
|
const [expanded, setExpanded] = (0, import_react10.useState)(false);
|
|
5168
5191
|
const chart = useChartTheme();
|
|
5169
5192
|
const handleExpandChange = (newExpanded) => {
|
|
@@ -5362,15 +5385,19 @@ var init_TeamUsage = __esm({
|
|
|
5362
5385
|
renderNamedTags("Knowledge bases", team.object_permission?.vector_stores, vectorStores),
|
|
5363
5386
|
renderNamedTags("MCP servers", team.object_permission?.mcp_servers, mcpServers),
|
|
5364
5387
|
renderDailySpendSection(),
|
|
5365
|
-
(memberUsageLoading || memberUsage) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5388
|
+
(memberUsageLoading || memberUsage || memberUsageFailed) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5366
5389
|
sectionLabel("Usage by member"),
|
|
5367
|
-
memberUsage
|
|
5390
|
+
memberUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MemberUsageCards, { usage: memberUsage }),
|
|
5391
|
+
!memberUsage && memberUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-member usage" }),
|
|
5392
|
+
!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 }) })
|
|
5368
5393
|
] }),
|
|
5369
|
-
(keyUsageLoading || keyUsage) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5394
|
+
(keyUsageLoading || keyUsage || keyUsageFailed) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5370
5395
|
sectionLabel("Keys by member"),
|
|
5371
|
-
keyUsage
|
|
5396
|
+
keyUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TeamKeyUsageTable, { usage: keyUsage }),
|
|
5397
|
+
!keyUsage && keyUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-key usage" }),
|
|
5398
|
+
!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 }) })
|
|
5372
5399
|
] }),
|
|
5373
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
|
|
5400
|
+
!memberUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
|
|
5374
5401
|
sectionLabel("Members"),
|
|
5375
5402
|
team.members_with_roles?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5376
5403
|
import_TableContainer4.default,
|
|
@@ -5428,6 +5455,8 @@ var init_TeamUsage = __esm({
|
|
|
5428
5455
|
getTeamMemberUsageLoading,
|
|
5429
5456
|
getTeamKeyUsage,
|
|
5430
5457
|
getTeamKeyUsageLoading,
|
|
5458
|
+
getTeamMemberUsageFailed,
|
|
5459
|
+
getTeamKeyUsageFailed,
|
|
5431
5460
|
canManage,
|
|
5432
5461
|
onEditTeam,
|
|
5433
5462
|
canCreate,
|
|
@@ -5493,6 +5522,8 @@ var init_TeamUsage = __esm({
|
|
|
5493
5522
|
memberUsageLoading: getTeamMemberUsageLoading?.(team.team_id) ?? false,
|
|
5494
5523
|
keyUsage: getTeamKeyUsage?.(team.team_id) ?? null,
|
|
5495
5524
|
keyUsageLoading: getTeamKeyUsageLoading?.(team.team_id) ?? false,
|
|
5525
|
+
memberUsageFailed: getTeamMemberUsageFailed?.(team.team_id) ?? false,
|
|
5526
|
+
keyUsageFailed: getTeamKeyUsageFailed?.(team.team_id) ?? false,
|
|
5496
5527
|
canManage,
|
|
5497
5528
|
onEditTeam,
|
|
5498
5529
|
canManageMembers: canManageMembers?.(team),
|
|
@@ -6316,7 +6347,7 @@ function initDateRange() {
|
|
|
6316
6347
|
else start.setDate(start.getDate() - 7);
|
|
6317
6348
|
return { start, end };
|
|
6318
6349
|
}
|
|
6319
|
-
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;
|
|
6350
|
+
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;
|
|
6320
6351
|
var init_LiteLLMPage = __esm({
|
|
6321
6352
|
"src/components/LiteLLMPage.tsx"() {
|
|
6322
6353
|
"use strict";
|
|
@@ -6356,6 +6387,7 @@ var init_LiteLLMPage = __esm({
|
|
|
6356
6387
|
PERIOD_LS_KEY2 = "litellm_usage_period";
|
|
6357
6388
|
PAGE_TABS = ["overview", "keys", "teams", "models", "insights"];
|
|
6358
6389
|
isPageTab = (v) => !!v && PAGE_TABS.includes(v);
|
|
6390
|
+
isRefusal = (err) => err instanceof ApiError && (err.status === 403 || err.status === 404);
|
|
6359
6391
|
LiteLLMPage = () => {
|
|
6360
6392
|
const api = (0, import_core_plugin_api5.useApi)(liteLlmApiRef);
|
|
6361
6393
|
const alertApi = (0, import_core_plugin_api5.useApi)(import_core_plugin_api5.alertApiRef);
|
|
@@ -6441,6 +6473,8 @@ var init_LiteLLMPage = __esm({
|
|
|
6441
6473
|
const [memberUsageLoading, setMemberUsageLoading] = (0, import_react13.useState)({});
|
|
6442
6474
|
const [keyUsageCache, setKeyUsageCache] = (0, import_react13.useState)({});
|
|
6443
6475
|
const [keyUsageLoading, setKeyUsageLoading] = (0, import_react13.useState)({});
|
|
6476
|
+
const [memberUsageFailed, setMemberUsageFailed] = (0, import_react13.useState)({});
|
|
6477
|
+
const [keyUsageFailed, setKeyUsageFailed] = (0, import_react13.useState)({});
|
|
6444
6478
|
const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use2.useAsync)(
|
|
6445
6479
|
() => api.getUserInfo(),
|
|
6446
6480
|
[api]
|
|
@@ -6509,6 +6543,8 @@ var init_LiteLLMPage = __esm({
|
|
|
6509
6543
|
setMemberUsageLoading({});
|
|
6510
6544
|
setKeyUsageCache({});
|
|
6511
6545
|
setKeyUsageLoading({});
|
|
6546
|
+
setMemberUsageFailed({});
|
|
6547
|
+
setKeyUsageFailed({});
|
|
6512
6548
|
}, [setDateRange, setCurrentPreset]);
|
|
6513
6549
|
const loadTeamUsage = (0, import_react13.useCallback)(async (teamId) => {
|
|
6514
6550
|
if (teamUsageCache[teamId] !== void 0 || teamUsageLoading[teamId]) return;
|
|
@@ -6532,8 +6568,9 @@ var init_LiteLLMPage = __esm({
|
|
|
6532
6568
|
const endDate = toLocalDay(dateRange.end);
|
|
6533
6569
|
const data = await api.getTeamMemberUsage(teamId, startDate, endDate);
|
|
6534
6570
|
setMemberUsageCache((prev) => ({ ...prev, [teamId]: data }));
|
|
6535
|
-
} catch {
|
|
6571
|
+
} catch (err) {
|
|
6536
6572
|
setMemberUsageCache((prev) => ({ ...prev, [teamId]: null }));
|
|
6573
|
+
setMemberUsageFailed((prev) => ({ ...prev, [teamId]: !isRefusal(err) }));
|
|
6537
6574
|
} finally {
|
|
6538
6575
|
setMemberUsageLoading((prev) => ({ ...prev, [teamId]: false }));
|
|
6539
6576
|
}
|
|
@@ -6546,8 +6583,9 @@ var init_LiteLLMPage = __esm({
|
|
|
6546
6583
|
const endDate = toLocalDay(dateRange.end);
|
|
6547
6584
|
const data = await api.getTeamKeyUsage(teamId, startDate, endDate);
|
|
6548
6585
|
setKeyUsageCache((prev) => ({ ...prev, [teamId]: data }));
|
|
6549
|
-
} catch {
|
|
6586
|
+
} catch (err) {
|
|
6550
6587
|
setKeyUsageCache((prev) => ({ ...prev, [teamId]: null }));
|
|
6588
|
+
setKeyUsageFailed((prev) => ({ ...prev, [teamId]: !isRefusal(err) }));
|
|
6551
6589
|
} finally {
|
|
6552
6590
|
setKeyUsageLoading((prev) => ({ ...prev, [teamId]: false }));
|
|
6553
6591
|
}
|
|
@@ -6851,6 +6889,8 @@ var init_LiteLLMPage = __esm({
|
|
|
6851
6889
|
getTeamMemberUsageLoading: (teamId) => memberUsageLoading[teamId] ?? false,
|
|
6852
6890
|
getTeamKeyUsage: (teamId) => keyUsageCache[teamId] ?? null,
|
|
6853
6891
|
getTeamKeyUsageLoading: (teamId) => keyUsageLoading[teamId] ?? false,
|
|
6892
|
+
getTeamMemberUsageFailed: (teamId) => memberUsageFailed[teamId] ?? false,
|
|
6893
|
+
getTeamKeyUsageFailed: (teamId) => keyUsageFailed[teamId] ?? false,
|
|
6854
6894
|
canManage: teamMgmtEnabled && canManageTeam && !readOnly,
|
|
6855
6895
|
onEditTeam: (t) => setManageTeam({ mode: "edit", team: t }),
|
|
6856
6896
|
canCreate: teamMgmtEnabled && canCreateTeam && !readOnly,
|