@acarmisc/backstage-plugin-litellm 0.46.0 → 0.47.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/TeamUsage.d.ts +2 -0
- package/dist/index.cjs.js +54 -15
- package/dist/index.cjs.js.map +3 -3
- package/dist/index.esm.js +53 -14
- package/dist/index.esm.js.map +3 -3
- package/package.json +1 -1
|
@@ -7,6 +7,7 @@ import { McpServerInfo, TeamInfo, TeamKeyUsage, TeamMemberUsage, UsageMetrics, V
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const MemberUsageCards: FC<{
|
|
9
9
|
usage: TeamMemberUsage;
|
|
10
|
+
filterText?: string;
|
|
10
11
|
}>;
|
|
11
12
|
/**
|
|
12
13
|
* A team's keys with the period's usage, for team leads. The backend never
|
|
@@ -14,6 +15,7 @@ export declare const MemberUsageCards: FC<{
|
|
|
14
15
|
*/
|
|
15
16
|
export declare const TeamKeyUsageTable: FC<{
|
|
16
17
|
usage: TeamKeyUsage;
|
|
18
|
+
filterText?: string;
|
|
17
19
|
}>;
|
|
18
20
|
interface TeamUsageProps {
|
|
19
21
|
teams: TeamInfo[];
|
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, fmtShare, MemberUsageCards, TeamKeyUsageTable, 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_TextField5, import_InputAdornment3, 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";
|
|
@@ -5079,6 +5079,8 @@ var init_TeamUsage = __esm({
|
|
|
5079
5079
|
import_Collapse2 = __toESM(require("@mui/material/Collapse"));
|
|
5080
5080
|
import_IconButton6 = __toESM(require("@mui/material/IconButton"));
|
|
5081
5081
|
import_Button6 = __toESM(require("@mui/material/Button"));
|
|
5082
|
+
import_TextField5 = __toESM(require("@mui/material/TextField"));
|
|
5083
|
+
import_InputAdornment3 = __toESM(require("@mui/material/InputAdornment"));
|
|
5082
5084
|
import_CircularProgress4 = __toESM(require("@mui/material/CircularProgress"));
|
|
5083
5085
|
import_styles10 = require("@mui/material/styles");
|
|
5084
5086
|
import_Tooltip5 = __toESM(require("@mui/material/Tooltip"));
|
|
@@ -5089,21 +5091,28 @@ var init_TeamUsage = __esm({
|
|
|
5089
5091
|
fmtUsd2 = (n) => `$${(n ?? 0).toFixed(2)}`;
|
|
5090
5092
|
monoSx = { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 };
|
|
5091
5093
|
fmtShare = (pct) => `${pct.toFixed(pct > 0 && pct < 1 ? 1 : 0)}%`;
|
|
5092
|
-
MemberUsageCards = ({ usage }) => {
|
|
5094
|
+
MemberUsageCards = ({ usage, filterText }) => {
|
|
5093
5095
|
const hidden = usage.budget_hidden === true;
|
|
5094
5096
|
if (!usage.members.length) {
|
|
5095
5097
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "No members or activity in this period." });
|
|
5096
5098
|
}
|
|
5099
|
+
const query = (filterText ?? "").trim().toLowerCase();
|
|
5100
|
+
const matches = (m) => {
|
|
5101
|
+
if (!query) return true;
|
|
5102
|
+
const haystacks = m.user_id === null ? ["Unattributed"] : [m.display_name, m.user_email, m.user_id];
|
|
5103
|
+
return haystacks.some((h) => h && h.toLowerCase().includes(query));
|
|
5104
|
+
};
|
|
5105
|
+
const visible = usage.members.filter(matches);
|
|
5097
5106
|
const people = usage.members.filter((m) => m.user_id !== null).length;
|
|
5098
5107
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
|
|
5099
5108
|
!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)(
|
|
5109
|
+
visible.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", sx: { display: "block", py: 1 }, children: "No members match that filter." }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5101
5110
|
import_Box14.default,
|
|
5102
5111
|
{
|
|
5103
5112
|
role: "list",
|
|
5104
5113
|
"aria-label": "Usage by member",
|
|
5105
5114
|
sx: { display: "grid", gap: 1.5, gridTemplateColumns: "repeat(auto-fill, minmax(230px, 1fr))" },
|
|
5106
|
-
children:
|
|
5115
|
+
children: visible.map((m) => {
|
|
5107
5116
|
const name = m.display_name ?? m.user_email ?? m.user_id;
|
|
5108
5117
|
let sub = null;
|
|
5109
5118
|
if (m.display_name) sub = m.user_email ?? m.user_id;
|
|
@@ -5146,11 +5155,20 @@ var init_TeamUsage = __esm({
|
|
|
5146
5155
|
)
|
|
5147
5156
|
] });
|
|
5148
5157
|
};
|
|
5149
|
-
TeamKeyUsageTable = ({ usage }) => {
|
|
5158
|
+
TeamKeyUsageTable = ({ usage, filterText }) => {
|
|
5150
5159
|
const hidden = usage.budget_hidden === true;
|
|
5151
5160
|
if (!usage.keys.length) {
|
|
5152
5161
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "This team has no keys." });
|
|
5153
5162
|
}
|
|
5163
|
+
const query = (filterText ?? "").trim().toLowerCase();
|
|
5164
|
+
const visible = usage.keys.filter((k) => {
|
|
5165
|
+
if (!query) return true;
|
|
5166
|
+
const haystacks = [k.key_alias, k.key, k.user_email, k.user_id, k.display_name];
|
|
5167
|
+
return haystacks.some((h) => h && h.toLowerCase().includes(query));
|
|
5168
|
+
});
|
|
5169
|
+
if (visible.length === 0) {
|
|
5170
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", sx: { display: "block", py: 1 }, children: "No keys match that filter." });
|
|
5171
|
+
}
|
|
5154
5172
|
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: [
|
|
5155
5173
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableHead4.default, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableRow4.default, { children: [
|
|
5156
5174
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: "Key" }),
|
|
@@ -5162,7 +5180,7 @@ var init_TeamUsage = __esm({
|
|
|
5162
5180
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Tokens" }),
|
|
5163
5181
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Requests" })
|
|
5164
5182
|
] }) }),
|
|
5165
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableBody4.default, { children:
|
|
5183
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableBody4.default, { children: visible.map((k) => {
|
|
5166
5184
|
const owner = k.display_name ?? k.user_email ?? k.user_id;
|
|
5167
5185
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableRow4.default, { children: [
|
|
5168
5186
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableCell4.default, { children: [
|
|
@@ -5188,7 +5206,9 @@ var init_TeamUsage = __esm({
|
|
|
5188
5206
|
};
|
|
5189
5207
|
TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, memberUsageFailed, keyUsage, keyUsageLoading, keyUsageFailed, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand, vectorStores, mcpServers }) => {
|
|
5190
5208
|
const [expanded, setExpanded] = (0, import_react10.useState)(false);
|
|
5209
|
+
const [teamSearch, setTeamSearch] = (0, import_react10.useState)("");
|
|
5191
5210
|
const chart = useChartTheme();
|
|
5211
|
+
const searchValue = teamSearch.trim() ? teamSearch : "";
|
|
5192
5212
|
const handleExpandChange = (newExpanded) => {
|
|
5193
5213
|
setExpanded(newExpanded);
|
|
5194
5214
|
if (newExpanded && onExpand) {
|
|
@@ -5386,14 +5406,33 @@ var init_TeamUsage = __esm({
|
|
|
5386
5406
|
renderNamedTags("MCP servers", team.object_permission?.mcp_servers, mcpServers),
|
|
5387
5407
|
renderDailySpendSection(),
|
|
5388
5408
|
(memberUsageLoading || memberUsage || memberUsageFailed) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5389
|
-
|
|
5390
|
-
|
|
5409
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1, mb: 1, children: [
|
|
5410
|
+
sectionLabel("Usage by member"),
|
|
5411
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
5412
|
+
import_TextField5.default,
|
|
5413
|
+
{
|
|
5414
|
+
size: "small",
|
|
5415
|
+
placeholder: "Filter members by name or email\u2026",
|
|
5416
|
+
value: teamSearch,
|
|
5417
|
+
onChange: (e) => setTeamSearch(e.target.value),
|
|
5418
|
+
sx: { width: { xs: "100%", sm: 260 } },
|
|
5419
|
+
InputProps: {
|
|
5420
|
+
startAdornment: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_InputAdornment3.default, { position: "start", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_material7.Search, { fontSize: "small", color: "disabled" }) }),
|
|
5421
|
+
endAdornment: searchValue ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_InputAdornment3.default, { position: "end", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_IconButton6.default, { size: "small", onClick: () => setTeamSearch(""), "aria-label": "Clear member filter", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_icons_material7.Close, { fontSize: "small" }) }) }) : void 0
|
|
5422
|
+
}
|
|
5423
|
+
}
|
|
5424
|
+
)
|
|
5425
|
+
] }),
|
|
5426
|
+
memberUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MemberUsageCards, { usage: memberUsage, filterText: searchValue }),
|
|
5391
5427
|
!memberUsage && memberUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-member usage" }),
|
|
5392
5428
|
!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 }) })
|
|
5393
5429
|
] }),
|
|
5394
5430
|
(keyUsageLoading || keyUsage || keyUsageFailed) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
|
|
5395
|
-
|
|
5396
|
-
|
|
5431
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1, mb: 1, children: [
|
|
5432
|
+
sectionLabel("Keys by member"),
|
|
5433
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", noWrap: true, children: "Filter member keys, owner or alias" })
|
|
5434
|
+
] }),
|
|
5435
|
+
keyUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TeamKeyUsageTable, { usage: keyUsage, filterText: searchValue }),
|
|
5397
5436
|
!keyUsage && keyUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-key usage" }),
|
|
5398
5437
|
!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 }) })
|
|
5399
5438
|
] }),
|
|
@@ -5558,7 +5597,7 @@ function fmtTokens(n) {
|
|
|
5558
5597
|
if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
|
|
5559
5598
|
return String(n);
|
|
5560
5599
|
}
|
|
5561
|
-
var import_react11, import_Box15, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TableSortLabel2, import_Typography13, import_MenuItem5, import_Select, import_FormControl, import_InputLabel,
|
|
5600
|
+
var import_react11, import_Box15, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TableSortLabel2, import_Typography13, import_MenuItem5, import_Select, import_FormControl, import_InputLabel, import_TextField6, import_InputAdornment4, import_icons_material8, import_ContentCopy, import_Tooltip6, import_Snackbar, import_Alert4, import_styles11, import_jsx_runtime16, ALL_PROXY_MODELS, ModelsTable;
|
|
5562
5601
|
var init_ModelsTable = __esm({
|
|
5563
5602
|
"src/components/ModelsTable.tsx"() {
|
|
5564
5603
|
"use strict";
|
|
@@ -5576,8 +5615,8 @@ var init_ModelsTable = __esm({
|
|
|
5576
5615
|
import_Select = __toESM(require("@mui/material/Select"));
|
|
5577
5616
|
import_FormControl = __toESM(require("@mui/material/FormControl"));
|
|
5578
5617
|
import_InputLabel = __toESM(require("@mui/material/InputLabel"));
|
|
5579
|
-
|
|
5580
|
-
|
|
5618
|
+
import_TextField6 = __toESM(require("@mui/material/TextField"));
|
|
5619
|
+
import_InputAdornment4 = __toESM(require("@mui/material/InputAdornment"));
|
|
5581
5620
|
import_icons_material8 = require("@mui/icons-material");
|
|
5582
5621
|
import_ContentCopy = __toESM(require("@mui/icons-material/ContentCopy"));
|
|
5583
5622
|
import_Tooltip6 = __toESM(require("@mui/material/Tooltip"));
|
|
@@ -5695,7 +5734,7 @@ var init_ModelsTable = __esm({
|
|
|
5695
5734
|
)
|
|
5696
5735
|
] }),
|
|
5697
5736
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5698
|
-
|
|
5737
|
+
import_TextField6.default,
|
|
5699
5738
|
{
|
|
5700
5739
|
label: "Filter Models",
|
|
5701
5740
|
size: "small",
|
|
@@ -5704,7 +5743,7 @@ var init_ModelsTable = __esm({
|
|
|
5704
5743
|
disabled: !selectedTeamId,
|
|
5705
5744
|
sx: { minWidth: 240, mb: 2 },
|
|
5706
5745
|
InputProps: {
|
|
5707
|
-
startAdornment: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
5746
|
+
startAdornment: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_InputAdornment4.default, { position: "start", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_icons_material8.Search, { fontSize: "small" }) })
|
|
5708
5747
|
}
|
|
5709
5748
|
}
|
|
5710
5749
|
)
|