@acarmisc/backstage-plugin-litellm 0.41.0 → 0.42.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,6 +1,6 @@
1
1
  import { FC } from 'react';
2
2
  import { type KeyFilterType } from '../keyFilter';
3
- import { VirtualKey } from '../types';
3
+ import { TeamInfo, VirtualKey } from '../types';
4
4
  interface KeysTableProps {
5
5
  keys: VirtualKey[];
6
6
  /** Opens the shared key form dialog in create mode (rendered at page level). */
@@ -16,6 +16,8 @@ interface KeysTableProps {
16
16
  }>;
17
17
  filter?: KeyFilterType;
18
18
  onClearFilter?: () => void;
19
+ /** Used to show team names instead of raw team ids. */
20
+ teams?: TeamInfo[];
19
21
  }
20
22
  export declare const KeysTable: FC<KeysTableProps>;
21
23
  export {};
@@ -1,5 +1,5 @@
1
1
  import { FC } from 'react';
2
- import { TeamInfo, TeamMemberUsage, UsageMetrics } from '../types';
2
+ import { McpServerInfo, TeamInfo, 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.
@@ -27,6 +27,10 @@ interface TeamUsageProps {
27
27
  onManageMembers?: (team: TeamInfo) => void;
28
28
  /** Teams are synced from an identity provider: show a badge, no write controls. */
29
29
  readOnly?: boolean;
30
+ /** Used to show knowledge base names instead of raw ids. */
31
+ vectorStores?: VectorStoreInfo[];
32
+ /** Used to show MCP server names instead of raw ids. */
33
+ mcpServers?: McpServerInfo[];
30
34
  }
31
35
  export declare const TeamUsage: FC<TeamUsageProps>;
32
36
  export {};
package/dist/index.cjs.js CHANGED
@@ -1782,7 +1782,8 @@ var init_KeysTable = __esm({
1782
1782
  onDeleteKey,
1783
1783
  onPruneExpiredKeys,
1784
1784
  filter,
1785
- onClearFilter
1785
+ onClearFilter,
1786
+ teams
1786
1787
  }) => {
1787
1788
  const managePermission = (0, import_plugin_permission_react.usePermission)({ permission: import_backstage_plugin_litellm_common.litellmKeyManagePermission });
1788
1789
  const revokePermission = (0, import_plugin_permission_react.usePermission)({ permission: import_backstage_plugin_litellm_common.litellmKeyRevokePermission });
@@ -1810,9 +1811,14 @@ var init_KeysTable = __esm({
1810
1811
  setSortDirection("asc");
1811
1812
  }
1812
1813
  };
1814
+ const teamNames = (0, import_react4.useMemo)(
1815
+ () => new Map((teams ?? []).map((t) => [t.team_id, t.team_alias || t.team_id])),
1816
+ [teams]
1817
+ );
1818
+ const teamLabel = (id) => teamNames.get(id) ?? id;
1813
1819
  const teamIds = (0, import_react4.useMemo)(
1814
- () => [...new Set(keys.map((k) => k.team_id).filter((t) => !!t))].sort(),
1815
- [keys]
1820
+ () => [...new Set(keys.map((k) => k.team_id).filter((t) => !!t))].sort((a, b) => (teamNames.get(a) ?? a).localeCompare(teamNames.get(b) ?? b)),
1821
+ [keys, teamNames]
1816
1822
  );
1817
1823
  const filteredKeys = (0, import_react4.useMemo)(() => {
1818
1824
  let result = keys;
@@ -1936,7 +1942,7 @@ var init_KeysTable = __esm({
1936
1942
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_Typography5.default, { variant: "body2", children: key.key_alias || "\u2014" }),
1937
1943
  key.blocked && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(StatusPill, { label: "Blocked", tone: "danger" })
1938
1944
  ] }) }),
1939
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_TableCell.default, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_Typography5.default, { variant: "body2", color: "text.secondary", children: key.team_id || "\u2014" }) }),
1945
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_TableCell.default, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_Typography5.default, { variant: "body2", color: "text.secondary", children: key.team_id ? teamLabel(key.team_id) : "\u2014" }) }),
1940
1946
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_TableCell.default, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_Box7.default, { display: "flex", alignItems: "center", gap: 0.5, children: [
1941
1947
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1942
1948
  import_Typography5.default,
@@ -2057,7 +2063,7 @@ var init_KeysTable = __esm({
2057
2063
  sx: { minWidth: 160 },
2058
2064
  children: [
2059
2065
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_MenuItem.default, { value: "", children: "All teams" }),
2060
- teamIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_MenuItem.default, { value: id, children: id }, id))
2066
+ teamIds.map((id) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_MenuItem.default, { value: id, children: teamLabel(id) }, id))
2061
2067
  ]
2062
2068
  }
2063
2069
  ),
@@ -5105,7 +5111,7 @@ var init_TeamUsage = __esm({
5105
5111
  }) })
5106
5112
  ] }) });
5107
5113
  };
5108
- TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand }) => {
5114
+ TeamCard = ({ team, usage, usageLoading, memberUsage, memberUsageLoading, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand, vectorStores, mcpServers }) => {
5109
5115
  const [expanded, setExpanded] = (0, import_react10.useState)(false);
5110
5116
  const chart = useChartTheme();
5111
5117
  const handleExpandChange = (newExpanded) => {
@@ -5172,6 +5178,10 @@ var init_TeamUsage = __esm({
5172
5178
  children: label
5173
5179
  }
5174
5180
  );
5181
+ const renderNamedTags = (label, ids, items) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
5182
+ sectionLabel(label),
5183
+ ids?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { display: "flex", gap: 0.5, flexWrap: "wrap", children: ids.map((id) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TagChip, { label: items?.find((i) => i.id === id)?.name ?? id, title: id }, id)) }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "None configured" })
5184
+ ] });
5175
5185
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Paper8.default, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 }, children: [
5176
5186
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { display: "flex", alignItems: "center", gap: 1.5, children: [
5177
5187
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
@@ -5297,6 +5307,8 @@ var init_TeamUsage = __esm({
5297
5307
  sectionLabel("Models"),
5298
5308
  team.models?.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Box14.default, { display: "flex", gap: 0.5, flexWrap: "wrap", children: team.models.map((m) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TagChip, { label: m, title: m }, m)) }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Typography12.default, { variant: "body2", color: "text.secondary", children: "All models allowed" })
5299
5309
  ] }),
5310
+ renderNamedTags("Knowledge bases", team.object_permission?.vector_stores, vectorStores),
5311
+ renderNamedTags("MCP servers", team.object_permission?.mcp_servers, mcpServers),
5300
5312
  renderDailySpendSection(),
5301
5313
  (memberUsageLoading || memberUsage) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_Box14.default, { mb: 2.5, children: [
5302
5314
  sectionLabel("Usage by member"),
@@ -5365,7 +5377,9 @@ var init_TeamUsage = __esm({
5365
5377
  onTeamExpand,
5366
5378
  canManageMembers,
5367
5379
  onManageMembers,
5368
- readOnly
5380
+ readOnly,
5381
+ vectorStores,
5382
+ mcpServers
5369
5383
  }) => {
5370
5384
  const readOnlyBadge = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_Tooltip5.default, { title: "Teams and memberships are managed in your identity provider. Changes made here would be overwritten, so editing is disabled.", children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
5371
5385
  import_Box14.default,
@@ -5423,7 +5437,9 @@ var init_TeamUsage = __esm({
5423
5437
  onEditTeam,
5424
5438
  canManageMembers: canManageMembers?.(team),
5425
5439
  onManageMembers,
5426
- onExpand: onTeamExpand
5440
+ onExpand: onTeamExpand,
5441
+ vectorStores,
5442
+ mcpServers
5427
5443
  },
5428
5444
  team.team_id
5429
5445
  )) })
@@ -6392,12 +6408,12 @@ var init_LiteLLMPage = __esm({
6392
6408
  const teamMgmtEnabled = liteLlmConfig?.teamManagement?.enabled ?? false;
6393
6409
  const objectPermsEnabled = liteLlmConfig?.teamManagement?.objectPermissionsEnabled ?? false;
6394
6410
  const { value: vectorStores } = (0, import_react_use2.useAsync)(
6395
- async () => objectPermsEnabled ? api.getVectorStores().catch(() => []) : [],
6396
- [api, objectPermsEnabled]
6411
+ () => api.getVectorStores().catch(() => []),
6412
+ [api]
6397
6413
  );
6398
6414
  const { value: mcpServers } = (0, import_react_use2.useAsync)(
6399
- async () => objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],
6400
- [api, objectPermsEnabled]
6415
+ () => api.getMcpServers().catch(() => []),
6416
+ [api]
6401
6417
  );
6402
6418
  const teams = (0, import_react13.useMemo)(() => {
6403
6419
  if (!allTeams?.length) return [];
@@ -6723,7 +6739,8 @@ var init_LiteLLMPage = __esm({
6723
6739
  onDeleteKey: handleDeleteKey,
6724
6740
  onPruneExpiredKeys: handlePruneExpiredKeys,
6725
6741
  filter,
6726
- onClearFilter: clearFilter
6742
+ onClearFilter: clearFilter,
6743
+ teams: allTeams ?? []
6727
6744
  }
6728
6745
  );
6729
6746
  })(),
@@ -6754,6 +6771,8 @@ var init_LiteLLMPage = __esm({
6754
6771
  onEditTeam: (t) => setManageTeam({ mode: "edit", team: t }),
6755
6772
  canCreate: teamMgmtEnabled && canCreateTeam && !readOnly,
6756
6773
  onCreateTeam: () => setManageTeam({ mode: "create" }),
6774
+ vectorStores: vectorStores ?? [],
6775
+ mcpServers: mcpServers ?? [],
6757
6776
  canManageMembers: (t) => teamMgmtEnabled && canManageMembers && isTeamMemberManager(t, userInfo?.user_id, memberManagerRoles, readOnly),
6758
6777
  onManageMembers: (t) => setManageTeam({ mode: "members", team: t }),
6759
6778
  readOnly,