@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/index.esm.js CHANGED
@@ -5056,10 +5056,12 @@ import TableContainer4 from "@mui/material/TableContainer";
5056
5056
  import Collapse2 from "@mui/material/Collapse";
5057
5057
  import IconButton6 from "@mui/material/IconButton";
5058
5058
  import Button6 from "@mui/material/Button";
5059
+ import TextField5 from "@mui/material/TextField";
5060
+ import InputAdornment3 from "@mui/material/InputAdornment";
5059
5061
  import CircularProgress4 from "@mui/material/CircularProgress";
5060
5062
  import { alpha as alpha10 } from "@mui/material/styles";
5061
5063
  import MuiTooltip from "@mui/material/Tooltip";
5062
- import { ExpandMore as ExpandMore3, Group, Add as Add2, LockOutlined, GroupAddOutlined } from "@mui/icons-material";
5064
+ import { ExpandMore as ExpandMore3, Group, Add as Add2, LockOutlined, GroupAddOutlined, Search as SearchIcon, Close as CloseIcon } from "@mui/icons-material";
5063
5065
  import {
5064
5066
  AreaChart as AreaChart2,
5065
5067
  Area as Area2,
@@ -5092,21 +5094,28 @@ var init_TeamUsage = __esm({
5092
5094
  fmtUsd2 = (n) => `$${(n ?? 0).toFixed(2)}`;
5093
5095
  monoSx = { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 };
5094
5096
  fmtShare = (pct) => `${pct.toFixed(pct > 0 && pct < 1 ? 1 : 0)}%`;
5095
- MemberUsageCards = ({ usage }) => {
5097
+ MemberUsageCards = ({ usage, filterText }) => {
5096
5098
  const hidden = usage.budget_hidden === true;
5097
5099
  if (!usage.members.length) {
5098
5100
  return /* @__PURE__ */ jsx15(Typography12, { variant: "body2", color: "text.secondary", children: "No members or activity in this period." });
5099
5101
  }
5102
+ const query = (filterText ?? "").trim().toLowerCase();
5103
+ const matches = (m) => {
5104
+ if (!query) return true;
5105
+ const haystacks = m.user_id === null ? ["Unattributed"] : [m.display_name, m.user_email, m.user_id];
5106
+ return haystacks.some((h) => h && h.toLowerCase().includes(query));
5107
+ };
5108
+ const visible = usage.members.filter(matches);
5100
5109
  const people = usage.members.filter((m) => m.user_id !== null).length;
5101
5110
  return /* @__PURE__ */ jsxs14(Box14, { children: [
5102
5111
  !hidden && people > 0 && /* @__PURE__ */ jsx15(Typography12, { 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` }),
5103
- /* @__PURE__ */ jsx15(
5112
+ visible.length === 0 ? /* @__PURE__ */ jsx15(Typography12, { variant: "body2", color: "text.secondary", sx: { display: "block", py: 1 }, children: "No members match that filter." }) : /* @__PURE__ */ jsx15(
5104
5113
  Box14,
5105
5114
  {
5106
5115
  role: "list",
5107
5116
  "aria-label": "Usage by member",
5108
5117
  sx: { display: "grid", gap: 1.5, gridTemplateColumns: "repeat(auto-fill, minmax(230px, 1fr))" },
5109
- children: usage.members.map((m) => {
5118
+ children: visible.map((m) => {
5110
5119
  const name = m.display_name ?? m.user_email ?? m.user_id;
5111
5120
  let sub = null;
5112
5121
  if (m.display_name) sub = m.user_email ?? m.user_id;
@@ -5149,11 +5158,20 @@ var init_TeamUsage = __esm({
5149
5158
  )
5150
5159
  ] });
5151
5160
  };
5152
- TeamKeyUsageTable = ({ usage }) => {
5161
+ TeamKeyUsageTable = ({ usage, filterText }) => {
5153
5162
  const hidden = usage.budget_hidden === true;
5154
5163
  if (!usage.keys.length) {
5155
5164
  return /* @__PURE__ */ jsx15(Typography12, { variant: "body2", color: "text.secondary", children: "This team has no keys." });
5156
5165
  }
5166
+ const query = (filterText ?? "").trim().toLowerCase();
5167
+ const visible = usage.keys.filter((k) => {
5168
+ if (!query) return true;
5169
+ const haystacks = [k.key_alias, k.key, k.user_email, k.user_id, k.display_name];
5170
+ return haystacks.some((h) => h && h.toLowerCase().includes(query));
5171
+ });
5172
+ if (visible.length === 0) {
5173
+ return /* @__PURE__ */ jsx15(Typography12, { variant: "body2", color: "text.secondary", sx: { display: "block", py: 1 }, children: "No keys match that filter." });
5174
+ }
5157
5175
  return /* @__PURE__ */ jsx15(TableContainer4, { component: Paper8, variant: "outlined", sx: { borderRadius: 1.5 }, children: /* @__PURE__ */ jsxs14(Table4, { size: "small", sx: dataTableSx, "aria-label": "Keys by member", children: [
5158
5176
  /* @__PURE__ */ jsx15(TableHead4, { children: /* @__PURE__ */ jsxs14(TableRow4, { children: [
5159
5177
  /* @__PURE__ */ jsx15(TableCell4, { children: "Key" }),
@@ -5165,7 +5183,7 @@ var init_TeamUsage = __esm({
5165
5183
  /* @__PURE__ */ jsx15(TableCell4, { align: "right", children: "Tokens" }),
5166
5184
  /* @__PURE__ */ jsx15(TableCell4, { align: "right", children: "Requests" })
5167
5185
  ] }) }),
5168
- /* @__PURE__ */ jsx15(TableBody4, { children: usage.keys.map((k) => {
5186
+ /* @__PURE__ */ jsx15(TableBody4, { children: visible.map((k) => {
5169
5187
  const owner = k.display_name ?? k.user_email ?? k.user_id;
5170
5188
  return /* @__PURE__ */ jsxs14(TableRow4, { children: [
5171
5189
  /* @__PURE__ */ jsxs14(TableCell4, { children: [
@@ -5191,7 +5209,9 @@ var init_TeamUsage = __esm({
5191
5209
  };
5192
5210
  TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, memberUsageFailed, keyUsage, keyUsageLoading, keyUsageFailed, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand, vectorStores, mcpServers }) => {
5193
5211
  const [expanded, setExpanded] = useState9(false);
5212
+ const [teamSearch, setTeamSearch] = useState9("");
5194
5213
  const chart = useChartTheme();
5214
+ const searchValue = teamSearch.trim() ? teamSearch : "";
5195
5215
  const handleExpandChange = (newExpanded) => {
5196
5216
  setExpanded(newExpanded);
5197
5217
  if (newExpanded && onExpand) {
@@ -5389,14 +5409,33 @@ var init_TeamUsage = __esm({
5389
5409
  renderNamedTags("MCP servers", team.object_permission?.mcp_servers, mcpServers),
5390
5410
  renderDailySpendSection(),
5391
5411
  (memberUsageLoading || memberUsage || memberUsageFailed) && /* @__PURE__ */ jsxs14(Box14, { mb: 2.5, children: [
5392
- sectionLabel("Usage by member"),
5393
- memberUsage && /* @__PURE__ */ jsx15(MemberUsageCards, { usage: memberUsage }),
5412
+ /* @__PURE__ */ jsxs14(Box14, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1, mb: 1, children: [
5413
+ sectionLabel("Usage by member"),
5414
+ /* @__PURE__ */ jsx15(
5415
+ TextField5,
5416
+ {
5417
+ size: "small",
5418
+ placeholder: "Filter members by name or email\u2026",
5419
+ value: teamSearch,
5420
+ onChange: (e) => setTeamSearch(e.target.value),
5421
+ sx: { width: { xs: "100%", sm: 260 } },
5422
+ InputProps: {
5423
+ startAdornment: /* @__PURE__ */ jsx15(InputAdornment3, { position: "start", children: /* @__PURE__ */ jsx15(SearchIcon, { fontSize: "small", color: "disabled" }) }),
5424
+ endAdornment: searchValue ? /* @__PURE__ */ jsx15(InputAdornment3, { position: "end", children: /* @__PURE__ */ jsx15(IconButton6, { size: "small", onClick: () => setTeamSearch(""), "aria-label": "Clear member filter", children: /* @__PURE__ */ jsx15(CloseIcon, { fontSize: "small" }) }) }) : void 0
5425
+ }
5426
+ }
5427
+ )
5428
+ ] }),
5429
+ memberUsage && /* @__PURE__ */ jsx15(MemberUsageCards, { usage: memberUsage, filterText: searchValue }),
5394
5430
  !memberUsage && memberUsageFailed && /* @__PURE__ */ jsx15(Typography12, { variant: "caption", color: "text.secondary", children: "Could not load per-member usage" }),
5395
5431
  !memberUsage && !memberUsageFailed && /* @__PURE__ */ jsx15(Box14, { display: "flex", justifyContent: "center", py: 2, children: /* @__PURE__ */ jsx15(CircularProgress4, { size: 22 }) })
5396
5432
  ] }),
5397
5433
  (keyUsageLoading || keyUsage || keyUsageFailed) && /* @__PURE__ */ jsxs14(Box14, { mb: 2.5, children: [
5398
- sectionLabel("Keys by member"),
5399
- keyUsage && /* @__PURE__ */ jsx15(TeamKeyUsageTable, { usage: keyUsage }),
5434
+ /* @__PURE__ */ jsxs14(Box14, { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1, mb: 1, children: [
5435
+ sectionLabel("Keys by member"),
5436
+ /* @__PURE__ */ jsx15(Typography12, { variant: "caption", color: "text.secondary", noWrap: true, children: "Filter member keys, owner or alias" })
5437
+ ] }),
5438
+ keyUsage && /* @__PURE__ */ jsx15(TeamKeyUsageTable, { usage: keyUsage, filterText: searchValue }),
5400
5439
  !keyUsage && keyUsageFailed && /* @__PURE__ */ jsx15(Typography12, { variant: "caption", color: "text.secondary", children: "Could not load per-key usage" }),
5401
5440
  !keyUsage && !keyUsageFailed && /* @__PURE__ */ jsx15(Box14, { display: "flex", justifyContent: "center", py: 2, children: /* @__PURE__ */ jsx15(CircularProgress4, { size: 22 }) })
5402
5441
  ] }),
@@ -5558,8 +5597,8 @@ import MenuItem5 from "@mui/material/MenuItem";
5558
5597
  import Select from "@mui/material/Select";
5559
5598
  import FormControl from "@mui/material/FormControl";
5560
5599
  import InputLabel from "@mui/material/InputLabel";
5561
- import TextField5 from "@mui/material/TextField";
5562
- import InputAdornment3 from "@mui/material/InputAdornment";
5600
+ import TextField6 from "@mui/material/TextField";
5601
+ import InputAdornment4 from "@mui/material/InputAdornment";
5563
5602
  import { Search as Search2 } from "@mui/icons-material";
5564
5603
  import ContentCopyIcon from "@mui/icons-material/ContentCopy";
5565
5604
  import Tooltip7 from "@mui/material/Tooltip";
@@ -5698,7 +5737,7 @@ var init_ModelsTable = __esm({
5698
5737
  )
5699
5738
  ] }),
5700
5739
  /* @__PURE__ */ jsx16(
5701
- TextField5,
5740
+ TextField6,
5702
5741
  {
5703
5742
  label: "Filter Models",
5704
5743
  size: "small",
@@ -5707,7 +5746,7 @@ var init_ModelsTable = __esm({
5707
5746
  disabled: !selectedTeamId,
5708
5747
  sx: { minWidth: 240, mb: 2 },
5709
5748
  InputProps: {
5710
- startAdornment: /* @__PURE__ */ jsx16(InputAdornment3, { position: "start", children: /* @__PURE__ */ jsx16(Search2, { fontSize: "small" }) })
5749
+ startAdornment: /* @__PURE__ */ jsx16(InputAdornment4, { position: "start", children: /* @__PURE__ */ jsx16(Search2, { fontSize: "small" }) })
5711
5750
  }
5712
5751
  }
5713
5752
  )