@acarmisc/backstage-plugin-litellm 0.45.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.
@@ -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. Dollars are replaced by
5
- * the share of team spend when the backend hides them.
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 MemberUsageTable: FC<{
8
+ export declare const MemberUsageCards: FC<{
8
9
  usage: TeamMemberUsage;
9
10
  }>;
10
11
  /**
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, MemberUsageTable, 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_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
- MemberUsageTable = ({ usage }) => {
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
- 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": "Usage by member", children: [
5097
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableHead4.default, { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableRow4.default, { children: [
5098
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { children: "Member" }),
5099
- !hidden && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Spend" }),
5100
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Share" }),
5101
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Tokens" }),
5102
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Requests" }),
5103
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Success" }),
5104
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: "Keys" })
5105
- ] }) }),
5106
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableBody4.default, { 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
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_TableRow4.default, { children: [
5112
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { 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: [
5113
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", children: name }),
5114
- sub && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", sx: monoSx, children: sub })
5115
- ] }) }),
5116
- !hidden && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: fmtUsd2(m.spend) }),
5117
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: `${m.spend_share_pct.toFixed(m.spend_share_pct > 0 && m.spend_share_pct < 1 ? 1 : 0)}%` }),
5118
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: fmtCompact(m.total_tokens) }),
5119
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: m.api_requests.toLocaleString() }),
5120
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: m.success_rate === null ? "\u2014" : `${m.success_rate.toFixed(0)}%` }),
5121
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_TableCell4.default, { align: "right", children: m.user_id === null ? "\u2014" : m.key_count })
5122
- ] }, m.user_id ?? "__unattributed");
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;
@@ -5364,7 +5387,7 @@ var init_TeamUsage = __esm({
5364
5387
  renderDailySpendSection(),
5365
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 && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MemberUsageTable, { usage: memberUsage }),
5390
+ memberUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(MemberUsageCards, { usage: memberUsage }),
5368
5391
  !memberUsage && memberUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-member usage" }),
5369
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 }) })
5370
5393
  ] }),
@@ -5374,7 +5397,7 @@ var init_TeamUsage = __esm({
5374
5397
  !keyUsage && keyUsageFailed && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "caption", color: "text.secondary", children: "Could not load per-key usage" }),
5375
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 }) })
5376
5399
  ] }),
5377
- /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
5400
+ !memberUsage && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { children: [
5378
5401
  sectionLabel("Members"),
5379
5402
  team.members_with_roles?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
5380
5403
  import_TableContainer4.default,