@acarmisc/backstage-plugin-litellm 0.17.0 → 0.18.1

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.cjs.js CHANGED
@@ -1942,7 +1942,7 @@ var init_GenerateKeyDialog = __esm({
1942
1942
  });
1943
1943
 
1944
1944
  // src/components/ManageTeamDialog.tsx
1945
- var import_react5, import_Dialog3, import_DialogTitle3, import_DialogContent3, import_DialogActions3, import_TextField3, import_Button4, import_Alert2, import_Checkbox2, import_FormControlLabel2, import_Autocomplete3, import_MenuItem2, import_Box5, import_Divider2, import_Typography5, import_IconButton3, import_List, import_ListItem, import_ListItemText, import_icons_material4, BUDGET_DURATION_OPTIONS, DEFAULT_BUDGET_DURATION, FALLBACK_BUDGET_CEILING, ManageTeamDialog;
1945
+ var import_react5, import_Dialog3, import_DialogTitle3, import_DialogContent3, import_DialogActions3, import_TextField3, import_Button4, import_Alert2, import_Checkbox2, import_FormControlLabel2, import_Autocomplete3, import_CircularProgress3, import_MenuItem2, import_Box5, import_Divider2, import_Typography5, import_IconButton3, import_Paper3, import_Table2, import_TableBody2, import_TableCell2, import_TableContainer2, import_TableHead2, import_TableRow2, import_icons_material4, import_core_plugin_api2, import_plugin_catalog_react, import_catalog_model, import_react_use, BUDGET_DURATION_OPTIONS, DEFAULT_BUDGET_DURATION, FALLBACK_BUDGET_CEILING, ManageTeamDialog;
1946
1946
  var init_ManageTeamDialog = __esm({
1947
1947
  "src/components/ManageTeamDialog.tsx"() {
1948
1948
  "use strict";
@@ -1957,15 +1957,25 @@ var init_ManageTeamDialog = __esm({
1957
1957
  import_Checkbox2 = __toESM(require("@mui/material/Checkbox"));
1958
1958
  import_FormControlLabel2 = __toESM(require("@mui/material/FormControlLabel"));
1959
1959
  import_Autocomplete3 = __toESM(require("@mui/material/Autocomplete"));
1960
+ import_CircularProgress3 = __toESM(require("@mui/material/CircularProgress"));
1960
1961
  import_MenuItem2 = __toESM(require("@mui/material/MenuItem"));
1961
1962
  import_Box5 = __toESM(require("@mui/material/Box"));
1962
1963
  import_Divider2 = __toESM(require("@mui/material/Divider"));
1963
1964
  import_Typography5 = __toESM(require("@mui/material/Typography"));
1964
1965
  import_IconButton3 = __toESM(require("@mui/material/IconButton"));
1965
- import_List = __toESM(require("@mui/material/List"));
1966
- import_ListItem = __toESM(require("@mui/material/ListItem"));
1967
- import_ListItemText = __toESM(require("@mui/material/ListItemText"));
1966
+ import_Paper3 = __toESM(require("@mui/material/Paper"));
1967
+ import_Table2 = __toESM(require("@mui/material/Table"));
1968
+ import_TableBody2 = __toESM(require("@mui/material/TableBody"));
1969
+ import_TableCell2 = __toESM(require("@mui/material/TableCell"));
1970
+ import_TableContainer2 = __toESM(require("@mui/material/TableContainer"));
1971
+ import_TableHead2 = __toESM(require("@mui/material/TableHead"));
1972
+ import_TableRow2 = __toESM(require("@mui/material/TableRow"));
1968
1973
  import_icons_material4 = require("@mui/icons-material");
1974
+ import_core_plugin_api2 = require("@backstage/core-plugin-api");
1975
+ import_plugin_catalog_react = require("@backstage/plugin-catalog-react");
1976
+ import_catalog_model = require("@backstage/catalog-model");
1977
+ import_react_use = require("react-use");
1978
+ init_ui();
1969
1979
  BUDGET_DURATION_OPTIONS = [
1970
1980
  { value: "1d", label: "Daily (1d)" },
1971
1981
  { value: "7d", label: "Weekly (7d)" },
@@ -2000,6 +2010,7 @@ var init_ManageTeamDialog = __esm({
2000
2010
  const [budgetDuration, setBudgetDuration] = (0, import_react5.useState)("");
2001
2011
  const [submitting, setSubmitting] = (0, import_react5.useState)(false);
2002
2012
  const [error, setError] = (0, import_react5.useState)(null);
2013
+ const [memberQuery, setMemberQuery] = (0, import_react5.useState)("");
2003
2014
  const [memberRef, setMemberRef] = (0, import_react5.useState)("");
2004
2015
  const [memberBudget, setMemberBudget] = (0, import_react5.useState)("");
2005
2016
  const [memberBusy, setMemberBusy] = (0, import_react5.useState)(false);
@@ -2012,6 +2023,36 @@ var init_ManageTeamDialog = __esm({
2012
2023
  const [mcpError, setMcpError] = (0, import_react5.useState)(null);
2013
2024
  const allowUnlimitedBudget = config?.teamManagement?.allowUnlimitedBudget ?? false;
2014
2025
  const maxBudgetCeiling = config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;
2026
+ const members = (0, import_react5.useMemo)(() => team?.members_with_roles ?? [], [team]);
2027
+ const showMembers = mode === "edit" && !!canManageMembers;
2028
+ const catalogApi = (0, import_core_plugin_api2.useApi)(import_plugin_catalog_react.catalogApiRef);
2029
+ const { value: catalogUsers, loading: usersLoading } = (0, import_react_use.useAsync)(async () => {
2030
+ if (!open || !showMembers) return [];
2031
+ try {
2032
+ const { items } = await catalogApi.getEntities({
2033
+ filter: { kind: "User" },
2034
+ fields: ["kind", "metadata.namespace", "metadata.name", "metadata.title", "spec.profile"]
2035
+ });
2036
+ return items;
2037
+ } catch {
2038
+ return [];
2039
+ }
2040
+ }, [open, showMembers, catalogApi]);
2041
+ const userOptions = (0, import_react5.useMemo)(() => {
2042
+ const existingEmails = new Set(
2043
+ members.map((m) => m.user_email?.toLowerCase()).filter((e) => !!e)
2044
+ );
2045
+ return (catalogUsers ?? []).map((e) => {
2046
+ const ref = (0, import_catalog_model.stringifyEntityRef)(e);
2047
+ const displayName = e.spec?.profile?.displayName || e.metadata.title || e.metadata.name;
2048
+ const email = e.spec?.profile?.email;
2049
+ return {
2050
+ ref,
2051
+ email,
2052
+ label: email ? `${displayName} (${email})` : displayName
2053
+ };
2054
+ }).filter((o) => !(o.email && existingEmails.has(o.email.toLowerCase()))).sort((a, b) => a.label.localeCompare(b.label));
2055
+ }, [catalogUsers, members]);
2015
2056
  (0, import_react5.useEffect)(() => {
2016
2057
  if (open) {
2017
2058
  if (mode === "edit" && team) {
@@ -2030,6 +2071,7 @@ var init_ManageTeamDialog = __esm({
2030
2071
  setBudgetDuration(DEFAULT_BUDGET_DURATION);
2031
2072
  }
2032
2073
  setError(null);
2074
+ setMemberQuery("");
2033
2075
  setMemberRef("");
2034
2076
  setMemberBudget("");
2035
2077
  setMemberError(null);
@@ -2101,6 +2143,7 @@ var init_ManageTeamDialog = __esm({
2101
2143
  try {
2102
2144
  setMemberBusy(true);
2103
2145
  await onAddMember(memberRef.trim(), budget);
2146
+ setMemberQuery("");
2104
2147
  setMemberRef("");
2105
2148
  setMemberBudget("");
2106
2149
  } catch (err) {
@@ -2147,8 +2190,6 @@ var init_ManageTeamDialog = __esm({
2147
2190
  };
2148
2191
  const modelNames = allModels.map((m) => m.model_name);
2149
2192
  const durationOptions = BUDGET_DURATION_OPTIONS.some((o) => o.value === budgetDuration) ? BUDGET_DURATION_OPTIONS : [...BUDGET_DURATION_OPTIONS, { value: budgetDuration, label: budgetDuration }];
2150
- const members = team?.members_with_roles ?? [];
2151
- const showMembers = mode === "edit" && !!canManageMembers;
2152
2193
  const showKnowledgeBases = mode === "edit" && !!canManageKnowledgeBases;
2153
2194
  const kbOptions = (vectorStores ?? []).map((v) => v.id);
2154
2195
  const kbLabel = (id) => (vectorStores ?? []).find((v) => v.id === id)?.name ?? id;
@@ -2172,7 +2213,15 @@ var init_ManageTeamDialog = __esm({
2172
2213
  value: models,
2173
2214
  onChange: (_, newValue) => setModels(newValue),
2174
2215
  disabled: submitting,
2175
- renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(import_TextField3.default, { ...params, label: "Models" })
2216
+ renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(
2217
+ import_TextField3.default,
2218
+ {
2219
+ ...params,
2220
+ label: "Models",
2221
+ required: true,
2222
+ helperText: "At least one model is required here \u2014 this delegated flow only grants access to models your admin has allow-listed for team creation, not every proxy model. (Teams with no model restriction shown elsewhere were configured directly in LiteLLM.)"
2223
+ }
2224
+ )
2176
2225
  }
2177
2226
  ), /* @__PURE__ */ import_react5.default.createElement(
2178
2227
  import_TextField3.default,
@@ -2204,34 +2253,69 @@ var init_ManageTeamDialog = __esm({
2204
2253
  fullWidth: true
2205
2254
  },
2206
2255
  durationOptions.map((o) => /* @__PURE__ */ import_react5.default.createElement(import_MenuItem2.default, { key: o.value, value: o.value }, o.label))
2207
- ), showMembers && /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "Members"), memberError && /* @__PURE__ */ import_react5.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null) }, memberError), members.length === 0 ? /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "body2", color: "text.secondary" }, "No members yet.") : /* @__PURE__ */ import_react5.default.createElement(import_List.default, { dense: true, disablePadding: true }, members.map((m) => /* @__PURE__ */ import_react5.default.createElement(
2208
- import_ListItem.default,
2256
+ ), showMembers && /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "Members"), memberError && /* @__PURE__ */ import_react5.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null) }, memberError), members.length === 0 ? /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "No members yet.") : /* @__PURE__ */ import_react5.default.createElement(import_TableContainer2.default, { component: import_Paper3.default, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 } }, /* @__PURE__ */ import_react5.default.createElement(import_Table2.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react5.default.createElement(import_TableHead2.default, null, /* @__PURE__ */ import_react5.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, null, "User"), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right" }, "Role"), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right", sx: { width: 40 } }))), /* @__PURE__ */ import_react5.default.createElement(import_TableBody2.default, null, members.map((m) => /* @__PURE__ */ import_react5.default.createElement(import_TableRow2.default, { key: m.user_id }, /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, null, m.user_email ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react5.default.createElement(
2257
+ import_Typography5.default,
2209
2258
  {
2210
- key: m.user_id,
2211
- disableGutters: true,
2212
- secondaryAction: /* @__PURE__ */ import_react5.default.createElement(
2213
- import_IconButton3.default,
2214
- {
2215
- edge: "end",
2216
- size: "small",
2217
- "aria-label": `remove ${m.user_id}`,
2218
- disabled: memberBusy,
2219
- onClick: () => handleRemoveMember(m.user_id)
2220
- },
2221
- /* @__PURE__ */ import_react5.default.createElement(import_icons_material4.Delete, { fontSize: "small" })
2222
- )
2259
+ variant: "caption",
2260
+ color: "text.secondary",
2261
+ sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
2223
2262
  },
2224
- /* @__PURE__ */ import_react5.default.createElement(import_ListItemText.default, { primary: m.user_id, secondary: m.role })
2225
- ))), /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, { sx: { display: "flex", gap: 1, alignItems: "flex-start", mt: 1 } }, /* @__PURE__ */ import_react5.default.createElement(
2226
- import_TextField3.default,
2263
+ m.user_id
2264
+ )) : /* @__PURE__ */ import_react5.default.createElement(
2265
+ import_Typography5.default,
2227
2266
  {
2228
- label: "Backstage user ref",
2229
- placeholder: "user:default/alice",
2230
- value: memberRef,
2231
- onChange: (e) => setMemberRef(e.target.value),
2232
- disabled: memberBusy,
2267
+ variant: "body2",
2268
+ sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
2269
+ },
2270
+ m.user_id
2271
+ )), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right" }, /* @__PURE__ */ import_react5.default.createElement(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false })), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right" }, /* @__PURE__ */ import_react5.default.createElement(
2272
+ import_IconButton3.default,
2273
+ {
2274
+ edge: "end",
2233
2275
  size: "small",
2234
- sx: { flex: 1 }
2276
+ "aria-label": `remove ${m.user_id}`,
2277
+ disabled: memberBusy,
2278
+ onClick: () => handleRemoveMember(m.user_id)
2279
+ },
2280
+ /* @__PURE__ */ import_react5.default.createElement(import_icons_material4.Delete, { fontSize: "small" })
2281
+ ))))))), /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" } }, /* @__PURE__ */ import_react5.default.createElement(
2282
+ import_Autocomplete3.default,
2283
+ {
2284
+ freeSolo: true,
2285
+ autoHighlight: true,
2286
+ options: userOptions,
2287
+ loading: usersLoading,
2288
+ inputValue: memberQuery,
2289
+ onInputChange: (_, newInputValue, reason) => {
2290
+ setMemberQuery(newInputValue);
2291
+ if (reason === "input" || reason === "clear") {
2292
+ setMemberRef(newInputValue);
2293
+ }
2294
+ },
2295
+ onChange: (_, newValue) => {
2296
+ if (newValue && typeof newValue !== "string") {
2297
+ setMemberQuery(newValue.label);
2298
+ setMemberRef(newValue.ref);
2299
+ }
2300
+ },
2301
+ getOptionLabel: (o) => typeof o === "string" ? o : o.label,
2302
+ isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
2303
+ disabled: memberBusy,
2304
+ sx: { flex: 1, minWidth: 260 },
2305
+ renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(
2306
+ import_TextField3.default,
2307
+ {
2308
+ ...params,
2309
+ label: "Add member",
2310
+ placeholder: "Search by name or email\u2026",
2311
+ size: "small",
2312
+ helperText: "Pick a catalog user, or paste a user entity ref",
2313
+ InputProps: {
2314
+ ...params.InputProps,
2315
+ endAdornment: /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, usersLoading ? /* @__PURE__ */ import_react5.default.createElement(import_CircularProgress3.default, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2316
+ }
2317
+ }
2318
+ )
2235
2319
  }
2236
2320
  ), /* @__PURE__ */ import_react5.default.createElement(
2237
2321
  import_TextField3.default,
@@ -2302,23 +2386,23 @@ function rateTone(rate) {
2302
2386
  if (rate >= 0.9) return "warning";
2303
2387
  return "danger";
2304
2388
  }
2305
- var import_react6, import_Paper3, import_Box6, import_Typography6, import_TextField4, import_MenuItem3, import_Grid, import_Table2, import_TableBody2, import_TableCell2, import_TableContainer2, import_TableHead2, import_TableRow2, import_Skeleton3, import_recharts, TOP_N_MODELS, PERIOD_LS_KEY, PRESET_LABELS, fmtPct, ChartSkeleton, ChartOrFallback, SuccessRateCell, UsageStats;
2389
+ var import_react6, import_Paper4, import_Box6, import_Typography6, import_TextField4, import_MenuItem3, import_Grid, import_Table3, import_TableBody3, import_TableCell3, import_TableContainer3, import_TableHead3, import_TableRow3, import_Skeleton3, import_recharts, TOP_N_MODELS, PERIOD_LS_KEY, PRESET_LABELS, fmtPct, ChartSkeleton, ChartOrFallback, SuccessRateCell, UsageStats;
2306
2390
  var init_UsageStats = __esm({
2307
2391
  "src/components/UsageStats.tsx"() {
2308
2392
  "use strict";
2309
2393
  import_react6 = __toESM(require("react"));
2310
- import_Paper3 = __toESM(require("@mui/material/Paper"));
2394
+ import_Paper4 = __toESM(require("@mui/material/Paper"));
2311
2395
  import_Box6 = __toESM(require("@mui/material/Box"));
2312
2396
  import_Typography6 = __toESM(require("@mui/material/Typography"));
2313
2397
  import_TextField4 = __toESM(require("@mui/material/TextField"));
2314
2398
  import_MenuItem3 = __toESM(require("@mui/material/MenuItem"));
2315
2399
  import_Grid = __toESM(require("@mui/material/Grid"));
2316
- import_Table2 = __toESM(require("@mui/material/Table"));
2317
- import_TableBody2 = __toESM(require("@mui/material/TableBody"));
2318
- import_TableCell2 = __toESM(require("@mui/material/TableCell"));
2319
- import_TableContainer2 = __toESM(require("@mui/material/TableContainer"));
2320
- import_TableHead2 = __toESM(require("@mui/material/TableHead"));
2321
- import_TableRow2 = __toESM(require("@mui/material/TableRow"));
2400
+ import_Table3 = __toESM(require("@mui/material/Table"));
2401
+ import_TableBody3 = __toESM(require("@mui/material/TableBody"));
2402
+ import_TableCell3 = __toESM(require("@mui/material/TableCell"));
2403
+ import_TableContainer3 = __toESM(require("@mui/material/TableContainer"));
2404
+ import_TableHead3 = __toESM(require("@mui/material/TableHead"));
2405
+ import_TableRow3 = __toESM(require("@mui/material/TableRow"));
2322
2406
  import_Skeleton3 = __toESM(require("@mui/material/Skeleton"));
2323
2407
  import_recharts = require("recharts");
2324
2408
  init_format();
@@ -2490,21 +2574,21 @@ var init_UsageStats = __esm({
2490
2574
  ];
2491
2575
  const renderKeyRows = () => {
2492
2576
  if (loading) {
2493
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2577
+ return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2494
2578
  }
2495
2579
  if (keyRows.length === 0) {
2496
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { colSpan: 7 }, /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No key activity in this period" })));
2580
+ return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 7 }, /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No key activity in this period" })));
2497
2581
  }
2498
- return [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, { key: r.keyHash }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.keyAlias), r.teamId ? /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.slice(0, 3).map((m) => /* @__PURE__ */ import_react6.default.createElement(TagChip, { key: m, label: m, title: m })), r.models.length > 3 && /* @__PURE__ */ import_react6.default.createElement(TagChip, { label: `+${r.models.length - 3}`, mono: false }))), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtCompact(r.totalTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, /* @__PURE__ */ import_react6.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2582
+ return [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, { key: r.keyHash }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.keyAlias), r.teamId ? /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.slice(0, 3).map((m) => /* @__PURE__ */ import_react6.default.createElement(TagChip, { key: m, label: m, title: m })), r.models.length > 3 && /* @__PURE__ */ import_react6.default.createElement(TagChip, { label: `+${r.models.length - 3}`, mono: false }))), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.totalTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2499
2583
  };
2500
2584
  const renderModelRows = () => {
2501
2585
  if (loading) {
2502
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2586
+ return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2503
2587
  }
2504
2588
  if (modelRows.length === 0) {
2505
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { colSpan: 8 }, /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No model activity in this period" })));
2589
+ return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 8 }, /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No model activity in this period" })));
2506
2590
  }
2507
- return [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, { key: r.model }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: chartColor(r.model), flexShrink: 0 } }), /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.model))), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtCompact(r.promptTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, fmtCompact(r.completionTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, /* @__PURE__ */ import_react6.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2591
+ return [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, { key: r.model }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: chartColor(r.model), flexShrink: 0 } }), /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.model))), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.promptTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.completionTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2508
2592
  };
2509
2593
  const periodSelect = /* @__PURE__ */ import_react6.default.createElement(
2510
2594
  import_TextField4.default,
@@ -2657,7 +2741,7 @@ var init_UsageStats = __esm({
2657
2741
  height: Math.max(200, topModelSpendBars.length * 34)
2658
2742
  },
2659
2743
  /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtCompact, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtInt, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "promptTokens", name: "Input", fill: SERIES.input, stackId: "t", barSize: 14 }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "completionTokens", name: "Output", fill: SERIES.output, stackId: "t", barSize: 14, radius: [0, 3, 3, 0] })))
2660
- ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(import_TableContainer2.default, { component: import_Paper3.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table2.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, "Model"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Success"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Input"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Output"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody2.default, null, renderModelRows()))))),
2744
+ ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(import_TableContainer3.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, "Model"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Success"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Input"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Output"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody3.default, null, renderModelRows()))))),
2661
2745
  tab === "keys" && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { container: true, spacing: 2 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Spend by key", height: Math.max(160, topKeySpendBars.length * 32) }, /* @__PURE__ */ import_react6.default.createElement(
2662
2746
  ChartOrFallback,
2663
2747
  {
@@ -2666,7 +2750,7 @@ var init_UsageStats = __esm({
2666
2750
  height: Math.max(160, topKeySpendBars.length * 32)
2667
2751
  },
2668
2752
  /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: topKeySpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "keyAlias", width: 160, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", fill: SERIES.input, radius: [0, 3, 3, 0], barSize: 14 })))
2669
- ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(import_TableContainer2.default, { component: import_Paper3.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table2.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, "Key"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, "Models"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Tokens"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody2.default, null, renderKeyRows())))))
2753
+ ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(import_TableContainer3.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, "Key"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, "Models"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Tokens"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody3.default, null, renderKeyRows())))))
2670
2754
  );
2671
2755
  };
2672
2756
  }
@@ -2678,26 +2762,26 @@ function budgetTone2(isOver, isNear) {
2678
2762
  if (isNear) return "warning";
2679
2763
  return "accent";
2680
2764
  }
2681
- var import_react7, import_Paper4, import_Box7, import_Typography7, import_Skeleton4, import_Divider3, import_Table3, import_TableBody3, import_TableCell3, import_TableHead3, import_TableRow3, import_TableContainer3, import_Collapse, import_IconButton4, import_Button5, import_CircularProgress3, import_styles4, import_icons_material5, import_recharts2, fmtUsd2, TeamCard, TeamUsage;
2765
+ var import_react7, import_Paper5, import_Box7, import_Typography7, import_Skeleton4, import_Divider3, import_Table4, import_TableBody4, import_TableCell4, import_TableHead4, import_TableRow4, import_TableContainer4, import_Collapse, import_IconButton4, import_Button5, import_CircularProgress4, import_styles4, import_icons_material5, import_recharts2, fmtUsd2, TeamCard, TeamUsage;
2682
2766
  var init_TeamUsage = __esm({
2683
2767
  "src/components/TeamUsage.tsx"() {
2684
2768
  "use strict";
2685
2769
  import_react7 = __toESM(require("react"));
2686
- import_Paper4 = __toESM(require("@mui/material/Paper"));
2770
+ import_Paper5 = __toESM(require("@mui/material/Paper"));
2687
2771
  import_Box7 = __toESM(require("@mui/material/Box"));
2688
2772
  import_Typography7 = __toESM(require("@mui/material/Typography"));
2689
2773
  import_Skeleton4 = __toESM(require("@mui/material/Skeleton"));
2690
2774
  import_Divider3 = __toESM(require("@mui/material/Divider"));
2691
- import_Table3 = __toESM(require("@mui/material/Table"));
2692
- import_TableBody3 = __toESM(require("@mui/material/TableBody"));
2693
- import_TableCell3 = __toESM(require("@mui/material/TableCell"));
2694
- import_TableHead3 = __toESM(require("@mui/material/TableHead"));
2695
- import_TableRow3 = __toESM(require("@mui/material/TableRow"));
2696
- import_TableContainer3 = __toESM(require("@mui/material/TableContainer"));
2775
+ import_Table4 = __toESM(require("@mui/material/Table"));
2776
+ import_TableBody4 = __toESM(require("@mui/material/TableBody"));
2777
+ import_TableCell4 = __toESM(require("@mui/material/TableCell"));
2778
+ import_TableHead4 = __toESM(require("@mui/material/TableHead"));
2779
+ import_TableRow4 = __toESM(require("@mui/material/TableRow"));
2780
+ import_TableContainer4 = __toESM(require("@mui/material/TableContainer"));
2697
2781
  import_Collapse = __toESM(require("@mui/material/Collapse"));
2698
2782
  import_IconButton4 = __toESM(require("@mui/material/IconButton"));
2699
2783
  import_Button5 = __toESM(require("@mui/material/Button"));
2700
- import_CircularProgress3 = __toESM(require("@mui/material/CircularProgress"));
2784
+ import_CircularProgress4 = __toESM(require("@mui/material/CircularProgress"));
2701
2785
  import_styles4 = require("@mui/material/styles");
2702
2786
  import_icons_material5 = require("@mui/icons-material");
2703
2787
  import_recharts2 = require("recharts");
@@ -2714,7 +2798,7 @@ var init_TeamUsage = __esm({
2714
2798
  const dailyData = usage?.daily_usage?.map((d) => ({ date: d.date, spend: d.spend })) ?? [];
2715
2799
  const renderDailySpendSection = () => {
2716
2800
  if (usageLoading) {
2717
- return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ import_react7.default.createElement(import_CircularProgress3.default, { size: 22 }));
2801
+ return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ import_react7.default.createElement(import_CircularProgress4.default, { size: 22 }));
2718
2802
  }
2719
2803
  if (dailyData.length === 0) return null;
2720
2804
  return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { mb: 2.5 }, /* @__PURE__ */ import_react7.default.createElement(
@@ -2753,7 +2837,7 @@ var init_TeamUsage = __esm({
2753
2837
  },
2754
2838
  label
2755
2839
  );
2756
- return /* @__PURE__ */ import_react7.default.createElement(import_Paper4.default, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 } }, /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { display: "flex", alignItems: "center", gap: 1.5 }, /* @__PURE__ */ import_react7.default.createElement(
2840
+ return /* @__PURE__ */ import_react7.default.createElement(import_Paper5.default, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 } }, /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { display: "flex", alignItems: "center", gap: 1.5 }, /* @__PURE__ */ import_react7.default.createElement(
2757
2841
  import_Box7.default,
2758
2842
  {
2759
2843
  sx: (theme) => ({
@@ -2818,13 +2902,13 @@ var init_TeamUsage = __esm({
2818
2902
  /* @__PURE__ */ import_react7.default.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
2819
2903
  /* @__PURE__ */ import_react7.default.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
2820
2904
  ), budget > 0 && /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ import_react7.default.createElement(Meter, { value: budgetPct, tone: budgetTone2(isOver, isNear), height: 5 })), /* @__PURE__ */ import_react7.default.createElement(import_Collapse.default, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ import_react7.default.createElement(import_Divider3.default, { sx: { my: 2.5 } }), /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ import_react7.default.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ import_react7.default.createElement(
2821
- import_TableContainer3.default,
2905
+ import_TableContainer4.default,
2822
2906
  {
2823
- component: import_Paper4.default,
2907
+ component: import_Paper5.default,
2824
2908
  variant: "outlined",
2825
2909
  sx: { borderRadius: 1.5 }
2826
2910
  },
2827
- /* @__PURE__ */ import_react7.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react7.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, "User"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Role"))), /* @__PURE__ */ import_react7.default.createElement(import_TableBody3.default, null, team.members_with_roles.map((m) => /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, { key: m.user_id }, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, m.user_email ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react7.default.createElement(
2911
+ /* @__PURE__ */ import_react7.default.createElement(import_Table4.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react7.default.createElement(import_TableHead4.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableRow4.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell4.default, null, "User"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell4.default, { align: "right" }, "Role"))), /* @__PURE__ */ import_react7.default.createElement(import_TableBody4.default, null, team.members_with_roles.map((m) => /* @__PURE__ */ import_react7.default.createElement(import_TableRow4.default, { key: m.user_id }, /* @__PURE__ */ import_react7.default.createElement(import_TableCell4.default, null, m.user_email ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react7.default.createElement(
2828
2912
  import_Typography7.default,
2829
2913
  {
2830
2914
  variant: "caption",
@@ -2839,7 +2923,7 @@ var init_TeamUsage = __esm({
2839
2923
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
2840
2924
  },
2841
2925
  m.user_id
2842
- )), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, /* @__PURE__ */ import_react7.default.createElement(
2926
+ )), /* @__PURE__ */ import_react7.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react7.default.createElement(
2843
2927
  StatusPill,
2844
2928
  {
2845
2929
  label: m.role,
@@ -2855,13 +2939,26 @@ var init_TeamUsage = __esm({
2855
2939
  getTeamUsage,
2856
2940
  getTeamUsageLoading,
2857
2941
  canManage,
2858
- onEditTeam
2942
+ onEditTeam,
2943
+ canCreate,
2944
+ onCreateTeam
2859
2945
  }) => {
2946
+ const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ import_react7.default.createElement(
2947
+ import_Button5.default,
2948
+ {
2949
+ variant: "contained",
2950
+ color: "primary",
2951
+ disableElevation: true,
2952
+ startIcon: /* @__PURE__ */ import_react7.default.createElement(import_icons_material5.Add, null),
2953
+ onClick: onCreateTeam
2954
+ },
2955
+ "Create Team"
2956
+ ) : void 0;
2860
2957
  if (loading) {
2861
- return /* @__PURE__ */ import_react7.default.createElement(SectionCard, { title: "Teams" }, /* @__PURE__ */ import_react7.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120, sx: { mb: 2 } }), /* @__PURE__ */ import_react7.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120 }));
2958
+ return /* @__PURE__ */ import_react7.default.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ import_react7.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120, sx: { mb: 2 } }), /* @__PURE__ */ import_react7.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120 }));
2862
2959
  }
2863
2960
  if (!teams.length) {
2864
- return /* @__PURE__ */ import_react7.default.createElement(SectionCard, { title: "Teams" }, /* @__PURE__ */ import_react7.default.createElement(
2961
+ return /* @__PURE__ */ import_react7.default.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ import_react7.default.createElement(
2865
2962
  EmptyState,
2866
2963
  {
2867
2964
  message: "You're not a member of any LiteLLM team yet.",
@@ -2869,17 +2966,25 @@ var init_TeamUsage = __esm({
2869
2966
  }
2870
2967
  ));
2871
2968
  }
2872
- return /* @__PURE__ */ import_react7.default.createElement(SectionCard, { title: "Teams", subtitle: `${teams.length} team${teams.length === 1 ? "" : "s"}` }, /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ import_react7.default.createElement(
2873
- TeamCard,
2969
+ return /* @__PURE__ */ import_react7.default.createElement(
2970
+ SectionCard,
2874
2971
  {
2875
- key: team.team_id,
2876
- team,
2877
- usage: getTeamUsage(team.team_id),
2878
- usageLoading: getTeamUsageLoading(team.team_id),
2879
- canManage,
2880
- onEditTeam
2881
- }
2882
- ))));
2972
+ title: "Teams",
2973
+ subtitle: `${teams.length} team${teams.length === 1 ? "" : "s"}`,
2974
+ actions: createAction
2975
+ },
2976
+ /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ import_react7.default.createElement(
2977
+ TeamCard,
2978
+ {
2979
+ key: team.team_id,
2980
+ team,
2981
+ usage: getTeamUsage(team.team_id),
2982
+ usageLoading: getTeamUsageLoading(team.team_id),
2983
+ canManage,
2984
+ onEditTeam
2985
+ }
2986
+ )))
2987
+ );
2883
2988
  };
2884
2989
  }
2885
2990
  });
@@ -2902,18 +3007,18 @@ function fmtTokens(n) {
2902
3007
  if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
2903
3008
  return String(n);
2904
3009
  }
2905
- var import_react8, import_Box8, import_Table4, import_TableBody4, import_TableCell4, import_TableContainer4, import_TableHead4, import_TableRow4, import_Typography8, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert3, import_styles5, ALL_PROXY_MODELS2, ModelsTable;
3010
+ var import_react8, import_Box8, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_Typography8, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert3, import_styles5, import_TextField5, import_InputAdornment2, import_icons_material6, ALL_PROXY_MODELS2, ModelsTable;
2906
3011
  var init_ModelsTable = __esm({
2907
3012
  "src/components/ModelsTable.tsx"() {
2908
3013
  "use strict";
2909
3014
  import_react8 = __toESM(require("react"));
2910
3015
  import_Box8 = __toESM(require("@mui/material/Box"));
2911
- import_Table4 = __toESM(require("@mui/material/Table"));
2912
- import_TableBody4 = __toESM(require("@mui/material/TableBody"));
2913
- import_TableCell4 = __toESM(require("@mui/material/TableCell"));
2914
- import_TableContainer4 = __toESM(require("@mui/material/TableContainer"));
2915
- import_TableHead4 = __toESM(require("@mui/material/TableHead"));
2916
- import_TableRow4 = __toESM(require("@mui/material/TableRow"));
3016
+ import_Table5 = __toESM(require("@mui/material/Table"));
3017
+ import_TableBody5 = __toESM(require("@mui/material/TableBody"));
3018
+ import_TableCell5 = __toESM(require("@mui/material/TableCell"));
3019
+ import_TableContainer5 = __toESM(require("@mui/material/TableContainer"));
3020
+ import_TableHead5 = __toESM(require("@mui/material/TableHead"));
3021
+ import_TableRow5 = __toESM(require("@mui/material/TableRow"));
2917
3022
  import_Typography8 = __toESM(require("@mui/material/Typography"));
2918
3023
  import_MenuItem4 = __toESM(require("@mui/material/MenuItem"));
2919
3024
  import_Select = __toESM(require("@mui/material/Select"));
@@ -2925,10 +3030,14 @@ var init_ModelsTable = __esm({
2925
3030
  import_Alert3 = __toESM(require("@mui/material/Alert"));
2926
3031
  init_ui();
2927
3032
  import_styles5 = require("@mui/material/styles");
3033
+ import_TextField5 = __toESM(require("@mui/material/TextField"));
3034
+ import_InputAdornment2 = __toESM(require("@mui/material/InputAdornment"));
3035
+ import_icons_material6 = require("@mui/icons-material");
2928
3036
  ALL_PROXY_MODELS2 = "all-proxy-models";
2929
3037
  ModelsTable = ({ allModels, teams, loading }) => {
2930
3038
  const theme = (0, import_styles5.useTheme)();
2931
3039
  const [selectedTeamId, setSelectedTeamId] = (0, import_react8.useState)("");
3040
+ const [filterText, setFilterText] = (0, import_react8.useState)("");
2932
3041
  const [copiedSnackbar, setCopiedSnackbar] = (0, import_react8.useState)(false);
2933
3042
  const selectedTeam = (0, import_react8.useMemo)(
2934
3043
  () => teams.find((t) => t.team_id === selectedTeamId) ?? null,
@@ -2936,8 +3045,15 @@ var init_ModelsTable = __esm({
2936
3045
  );
2937
3046
  const filteredModels = (0, import_react8.useMemo)(() => {
2938
3047
  if (!selectedTeam) return [];
2939
- return allModels.filter((model) => isModelAllowedByTeam2(model, selectedTeam.models));
2940
- }, [allModels, selectedTeam]);
3048
+ let result = allModels.filter((model) => isModelAllowedByTeam2(model, selectedTeam.models));
3049
+ if (filterText.trim()) {
3050
+ const q = filterText.toLowerCase();
3051
+ result = result.filter(
3052
+ (model) => model.model_name.toLowerCase().includes(q) || (model.access_groups || []).some((group) => group.toLowerCase().includes(q))
3053
+ );
3054
+ }
3055
+ return result;
3056
+ }, [allModels, selectedTeam, filterText]);
2941
3057
  const handleCopyModelId = (0, import_react8.useCallback)((modelId) => {
2942
3058
  navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));
2943
3059
  }, []);
@@ -2970,7 +3086,19 @@ var init_ModelsTable = __esm({
2970
3086
  onChange: (e) => setSelectedTeamId(e.target.value)
2971
3087
  },
2972
3088
  teams.map((t) => /* @__PURE__ */ import_react8.default.createElement(import_MenuItem4.default, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
2973
- ))),
3089
+ )), /* @__PURE__ */ import_react8.default.createElement(
3090
+ import_TextField5.default,
3091
+ {
3092
+ label: "Filter Models",
3093
+ size: "small",
3094
+ value: filterText,
3095
+ onChange: (e) => setFilterText(e.target.value),
3096
+ sx: { minWidth: 240, mb: 2 },
3097
+ InputProps: {
3098
+ startAdornment: /* @__PURE__ */ import_react8.default.createElement(import_InputAdornment2.default, { position: "start" }, /* @__PURE__ */ import_react8.default.createElement(import_icons_material6.Search, { fontSize: "small" }))
3099
+ }
3100
+ }
3101
+ )),
2974
3102
  loading && /* @__PURE__ */ import_react8.default.createElement(EmptyState, { message: "Loading models\u2026" }),
2975
3103
  !loading && !selectedTeamId && /* @__PURE__ */ import_react8.default.createElement(
2976
3104
  EmptyState,
@@ -2986,7 +3114,7 @@ var init_ModelsTable = __esm({
2986
3114
  hint: allModels.length === 0 ? "No models are configured in the system" : "None of the team's assigned models were found in the catalog"
2987
3115
  }
2988
3116
  ),
2989
- !loading && filteredModels.length > 0 && /* @__PURE__ */ import_react8.default.createElement(import_TableContainer4.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Table4.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react8.default.createElement(import_TableHead4.default, null, /* @__PURE__ */ import_react8.default.createElement(import_TableRow4.default, null, /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, "Model ID"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, "Mode"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, "Input Cost"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, "Output Cost"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, "Max Input"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, "Max Output"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, "Capabilities"))), /* @__PURE__ */ import_react8.default.createElement(import_TableBody4.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react8.default.createElement(import_TableRow4.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react8.default.createElement(TagChip, { label: m.model_name, title: m.model_name }), /* @__PURE__ */ import_react8.default.createElement(import_Tooltip.default, { title: "Copy model ID" }, /* @__PURE__ */ import_react8.default.createElement(
3117
+ !loading && filteredModels.length > 0 && /* @__PURE__ */ import_react8.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react8.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, "Model ID"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, "Mode"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Input Cost"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Output Cost"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Max Input"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Max Output"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, "Capabilities"))), /* @__PURE__ */ import_react8.default.createElement(import_TableBody5.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react8.default.createElement(import_TableRow5.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react8.default.createElement(TagChip, { label: m.model_name, title: m.model_name }), /* @__PURE__ */ import_react8.default.createElement(import_Tooltip.default, { title: "Copy model ID" }, /* @__PURE__ */ import_react8.default.createElement(
2990
3118
  import_Box8.default,
2991
3119
  {
2992
3120
  component: "span",
@@ -2998,7 +3126,7 @@ var init_ModelsTable = __esm({
2998
3126
  style: { cursor: "pointer", display: "inline-flex" }
2999
3127
  },
3000
3128
  /* @__PURE__ */ import_react8.default.createElement(import_ContentCopy.default, { sx: { fontSize: 14 } })
3001
- )))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, /* @__PURE__ */ import_react8.default.createElement(
3129
+ )))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react8.default.createElement(
3002
3130
  import_Box8.default,
3003
3131
  {
3004
3132
  component: "span",
@@ -3015,7 +3143,7 @@ var init_ModelsTable = __esm({
3015
3143
  }
3016
3144
  },
3017
3145
  m.mode
3018
- )), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.input_cost_per_token))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.output_cost_per_token))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_input_tokens))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_output_tokens))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" } }, m.supports_function_calling && /* @__PURE__ */ import_react8.default.createElement(TagChip, { label: "Fn", title: "Function calling" }), m.supports_vision && /* @__PURE__ */ import_react8.default.createElement(TagChip, { label: "\u{1F441}", title: "Vision" })))))))),
3146
+ )), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.input_cost_per_token))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.output_cost_per_token))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_input_tokens))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_output_tokens))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" } }, m.supports_function_calling && /* @__PURE__ */ import_react8.default.createElement(TagChip, { label: "Fn", title: "Function calling" }), m.supports_vision && /* @__PURE__ */ import_react8.default.createElement(TagChip, { label: "\u{1F441}", title: "Vision" })))))))),
3019
3147
  /* @__PURE__ */ import_react8.default.createElement(
3020
3148
  import_Snackbar.default,
3021
3149
  {
@@ -3052,10 +3180,10 @@ function formatDateTime(iso) {
3052
3180
  }
3053
3181
  function renderAuditLogBody(loading, entries) {
3054
3182
  if (loading) {
3055
- return /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ import_react9.default.createElement(import_Skeleton5.default, { variant: "rounded", height: 160 })));
3183
+ return /* @__PURE__ */ import_react9.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ import_react9.default.createElement(import_Skeleton5.default, { variant: "rounded", height: 160 })));
3056
3184
  }
3057
3185
  if (entries.length === 0) {
3058
- return /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { colSpan: 6 }, /* @__PURE__ */ import_react9.default.createElement(
3186
+ return /* @__PURE__ */ import_react9.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { colSpan: 6 }, /* @__PURE__ */ import_react9.default.createElement(
3059
3187
  EmptyState,
3060
3188
  {
3061
3189
  message: "No audit events found",
@@ -3065,29 +3193,29 @@ function renderAuditLogBody(loading, entries) {
3065
3193
  }
3066
3194
  return entries.map((entry) => /* @__PURE__ */ import_react9.default.createElement(DetailRow, { key: entry.id, entry }));
3067
3195
  }
3068
- var import_react9, import_Box9, import_Typography9, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TablePagination, import_TextField5, import_MenuItem5, import_Skeleton5, import_Collapse2, import_IconButton5, import_Alert4, import_styles6, import_icons_material6, import_react_use, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3196
+ var import_react9, import_Box9, import_Typography9, import_Table6, import_TableBody6, import_TableCell6, import_TableContainer6, import_TableHead6, import_TableRow6, import_TablePagination, import_TextField6, import_MenuItem5, import_Skeleton5, import_Collapse2, import_IconButton5, import_Alert4, import_styles6, import_icons_material7, import_react_use2, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3069
3197
  var init_AuditLog = __esm({
3070
3198
  "src/components/AuditLog.tsx"() {
3071
3199
  "use strict";
3072
3200
  import_react9 = __toESM(require("react"));
3073
3201
  import_Box9 = __toESM(require("@mui/material/Box"));
3074
3202
  import_Typography9 = __toESM(require("@mui/material/Typography"));
3075
- import_Table5 = __toESM(require("@mui/material/Table"));
3076
- import_TableBody5 = __toESM(require("@mui/material/TableBody"));
3077
- import_TableCell5 = __toESM(require("@mui/material/TableCell"));
3078
- import_TableContainer5 = __toESM(require("@mui/material/TableContainer"));
3079
- import_TableHead5 = __toESM(require("@mui/material/TableHead"));
3080
- import_TableRow5 = __toESM(require("@mui/material/TableRow"));
3203
+ import_Table6 = __toESM(require("@mui/material/Table"));
3204
+ import_TableBody6 = __toESM(require("@mui/material/TableBody"));
3205
+ import_TableCell6 = __toESM(require("@mui/material/TableCell"));
3206
+ import_TableContainer6 = __toESM(require("@mui/material/TableContainer"));
3207
+ import_TableHead6 = __toESM(require("@mui/material/TableHead"));
3208
+ import_TableRow6 = __toESM(require("@mui/material/TableRow"));
3081
3209
  import_TablePagination = __toESM(require("@mui/material/TablePagination"));
3082
- import_TextField5 = __toESM(require("@mui/material/TextField"));
3210
+ import_TextField6 = __toESM(require("@mui/material/TextField"));
3083
3211
  import_MenuItem5 = __toESM(require("@mui/material/MenuItem"));
3084
3212
  import_Skeleton5 = __toESM(require("@mui/material/Skeleton"));
3085
3213
  import_Collapse2 = __toESM(require("@mui/material/Collapse"));
3086
3214
  import_IconButton5 = __toESM(require("@mui/material/IconButton"));
3087
3215
  import_Alert4 = __toESM(require("@mui/material/Alert"));
3088
3216
  import_styles6 = require("@mui/material/styles");
3089
- import_icons_material6 = require("@mui/icons-material");
3090
- import_react_use = require("react-use");
3217
+ import_icons_material7 = require("@mui/icons-material");
3218
+ import_react_use2 = require("react-use");
3091
3219
  init_ui();
3092
3220
  ACTION_TONES = {
3093
3221
  created: "success",
@@ -3106,7 +3234,7 @@ var init_AuditLog = __esm({
3106
3234
  DetailRow = ({ entry }) => {
3107
3235
  const [open, setOpen] = (0, import_react9.useState)(false);
3108
3236
  const hasDetail = entry.before_value || entry.updated_values;
3109
- return /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { sx: { width: 40, pr: 0 } }, hasDetail && /* @__PURE__ */ import_react9.default.createElement(
3237
+ return /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { sx: { width: 40, pr: 0 } }, hasDetail && /* @__PURE__ */ import_react9.default.createElement(
3110
3238
  import_IconButton5.default,
3111
3239
  {
3112
3240
  size: "small",
@@ -3119,8 +3247,8 @@ var init_AuditLog = __esm({
3119
3247
  transition: theme.transitions.create("transform")
3120
3248
  })
3121
3249
  },
3122
- /* @__PURE__ */ import_react9.default.createElement(import_icons_material6.KeyboardArrowDown, { fontSize: "small" })
3123
- )), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, entry.action && /* @__PURE__ */ import_react9.default.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react9.default.createElement(
3250
+ /* @__PURE__ */ import_react9.default.createElement(import_icons_material7.KeyboardArrowDown, { fontSize: "small" })
3251
+ )), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, entry.action && /* @__PURE__ */ import_react9.default.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react9.default.createElement(
3124
3252
  import_Typography9.default,
3125
3253
  {
3126
3254
  variant: "body2",
@@ -3130,7 +3258,7 @@ var init_AuditLog = __esm({
3130
3258
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 12 }
3131
3259
  },
3132
3260
  entry.object_id ? entry.object_id.slice(0, 20) + (entry.object_id.length > 20 ? "\u2026" : "") : "\u2014"
3133
- )), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, entry.changed_by ?? "\u2014")), hasDetail && /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, { sx: { "&&:hover": { bgcolor: "transparent" } } }, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { colSpan: 6, sx: { "&&": { py: 0, border: 0 } } }, /* @__PURE__ */ import_react9.default.createElement(import_Collapse2.default, { in: open, unmountOnExit: true }, /* @__PURE__ */ import_react9.default.createElement(
3261
+ )), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, entry.changed_by ?? "\u2014")), hasDetail && /* @__PURE__ */ import_react9.default.createElement(import_TableRow6.default, { sx: { "&&:hover": { bgcolor: "transparent" } } }, /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { colSpan: 6, sx: { "&&": { py: 0, border: 0 } } }, /* @__PURE__ */ import_react9.default.createElement(import_Collapse2.default, { in: open, unmountOnExit: true }, /* @__PURE__ */ import_react9.default.createElement(
3134
3262
  import_Box9.default,
3135
3263
  {
3136
3264
  display: "flex",
@@ -3175,7 +3303,7 @@ var init_AuditLog = __esm({
3175
3303
  () => ({ page: page + 1, page_size: pageSize, ...filters }),
3176
3304
  [page, pageSize, filters]
3177
3305
  )();
3178
- const { value, loading, error } = (0, import_react_use.useAsync)(
3306
+ const { value, loading, error } = (0, import_react_use2.useAsync)(
3179
3307
  () => api.getAuditLogs(fetchParams),
3180
3308
  [api, fetchParams]
3181
3309
  );
@@ -3188,7 +3316,7 @@ var init_AuditLog = __esm({
3188
3316
  subtitle: loading ? "Loading\u2026" : `${total.toLocaleString()} event${total === 1 ? "" : "s"}`,
3189
3317
  flush: true,
3190
3318
  actions: /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(
3191
- import_TextField5.default,
3319
+ import_TextField6.default,
3192
3320
  {
3193
3321
  size: "small",
3194
3322
  label: "Action",
@@ -3206,7 +3334,7 @@ var init_AuditLog = __esm({
3206
3334
  /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "deleted" }, "Deleted"),
3207
3335
  /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "blocked" }, "Blocked")
3208
3336
  ), /* @__PURE__ */ import_react9.default.createElement(
3209
- import_TextField5.default,
3337
+ import_TextField6.default,
3210
3338
  {
3211
3339
  size: "small",
3212
3340
  label: "Table",
@@ -3225,7 +3353,7 @@ var init_AuditLog = __esm({
3225
3353
  /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
3226
3354
  /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_UserTable" }, "User")
3227
3355
  ), /* @__PURE__ */ import_react9.default.createElement(
3228
- import_TextField5.default,
3356
+ import_TextField6.default,
3229
3357
  {
3230
3358
  size: "small",
3231
3359
  label: "Changed by",
@@ -3239,7 +3367,7 @@ var init_AuditLog = __esm({
3239
3367
  ))
3240
3368
  },
3241
3369
  error && /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { px: 2.5, pb: 2 }, /* @__PURE__ */ import_react9.default.createElement(import_Alert4.default, { severity: "error" }, error.message)),
3242
- /* @__PURE__ */ import_react9.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react9.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, { sx: { width: 40 } }), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Time"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Action"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Table"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Object ID"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell5.default, null, "Changed By"))), /* @__PURE__ */ import_react9.default.createElement(import_TableBody5.default, null, renderAuditLogBody(loading, entries)))),
3370
+ /* @__PURE__ */ import_react9.default.createElement(import_TableContainer6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Table6.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react9.default.createElement(import_TableHead6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { sx: { width: 40 } }), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, "Time"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, "Action"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, "Table"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, "Object ID"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, "Changed By"))), /* @__PURE__ */ import_react9.default.createElement(import_TableBody6.default, null, renderAuditLogBody(loading, entries)))),
3243
3371
  /* @__PURE__ */ import_react9.default.createElement(
3244
3372
  import_TablePagination.default,
3245
3373
  {
@@ -3309,7 +3437,7 @@ function initDateRange() {
3309
3437
  else start.setDate(start.getDate() - 7);
3310
3438
  return { start, end };
3311
3439
  }
3312
- var import_react10, import_Box10, import_Snackbar2, import_Alert5, import_CircularProgress4, import_Typography10, import_Paper5, import_Tabs2, import_Tab2, import_Button6, import_react_use2, import_core_plugin_api2, import_plugin_permission_react, PERIOD_LS_KEY2, LiteLLMPage;
3440
+ var import_react10, import_Box10, import_Snackbar2, import_Alert5, import_CircularProgress5, import_Typography10, import_Paper6, import_Tabs2, import_Tab2, import_react_use3, import_core_plugin_api3, import_plugin_permission_react, PERIOD_LS_KEY2, LiteLLMPage;
3313
3441
  var init_LiteLLMPage = __esm({
3314
3442
  "src/components/LiteLLMPage.tsx"() {
3315
3443
  "use strict";
@@ -3317,14 +3445,13 @@ var init_LiteLLMPage = __esm({
3317
3445
  import_Box10 = __toESM(require("@mui/material/Box"));
3318
3446
  import_Snackbar2 = __toESM(require("@mui/material/Snackbar"));
3319
3447
  import_Alert5 = __toESM(require("@mui/material/Alert"));
3320
- import_CircularProgress4 = __toESM(require("@mui/material/CircularProgress"));
3448
+ import_CircularProgress5 = __toESM(require("@mui/material/CircularProgress"));
3321
3449
  import_Typography10 = __toESM(require("@mui/material/Typography"));
3322
- import_Paper5 = __toESM(require("@mui/material/Paper"));
3450
+ import_Paper6 = __toESM(require("@mui/material/Paper"));
3323
3451
  import_Tabs2 = __toESM(require("@mui/material/Tabs"));
3324
3452
  import_Tab2 = __toESM(require("@mui/material/Tab"));
3325
- import_Button6 = __toESM(require("@mui/material/Button"));
3326
- import_react_use2 = require("react-use");
3327
- import_core_plugin_api2 = require("@backstage/core-plugin-api");
3453
+ import_react_use3 = require("react-use");
3454
+ import_core_plugin_api3 = require("@backstage/core-plugin-api");
3328
3455
  import_plugin_permission_react = require("@backstage/plugin-permission-react");
3329
3456
  init_DashboardHeader();
3330
3457
  init_KeysTable();
@@ -3338,7 +3465,7 @@ var init_LiteLLMPage = __esm({
3338
3465
  init_permissions();
3339
3466
  PERIOD_LS_KEY2 = "litellm_usage_period";
3340
3467
  LiteLLMPage = () => {
3341
- const api = (0, import_core_plugin_api2.useApi)(liteLlmApiRef);
3468
+ const api = (0, import_core_plugin_api3.useApi)(liteLlmApiRef);
3342
3469
  const [dateRange, setDateRange] = (0, import_react10.useState)(initDateRange);
3343
3470
  const [currentPreset, setCurrentPreset] = (0, import_react10.useState)(() => {
3344
3471
  try {
@@ -3353,11 +3480,11 @@ var init_LiteLLMPage = __esm({
3353
3480
  const [manageTeam, setManageTeam] = (0, import_react10.useState)(null);
3354
3481
  const [teamUsageCache, setTeamUsageCache] = (0, import_react10.useState)({});
3355
3482
  const [teamUsageLoading, setTeamUsageLoading] = (0, import_react10.useState)({});
3356
- const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use2.useAsync)(
3483
+ const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use3.useAsync)(
3357
3484
  () => api.getUserInfo(),
3358
3485
  [api]
3359
3486
  );
3360
- const { value: keys, loading: keysLoading, retry: refreshKeys } = (0, import_react_use2.useAsyncRetry)(
3487
+ const { value: keys, loading: keysLoading, retry: refreshKeys } = (0, import_react_use3.useAsyncRetry)(
3361
3488
  async () => {
3362
3489
  try {
3363
3490
  return await api.listKeys();
@@ -3368,16 +3495,16 @@ var init_LiteLLMPage = __esm({
3368
3495
  },
3369
3496
  [api]
3370
3497
  );
3371
- const { value: allModels, loading: modelsLoading } = (0, import_react_use2.useAsync)(
3498
+ const { value: allModels, loading: modelsLoading } = (0, import_react_use3.useAsync)(
3372
3499
  () => api.listModels().catch(() => []),
3373
3500
  [api]
3374
3501
  );
3375
- const { value: allTeams, loading: teamsLoading, retry: refreshTeams } = (0, import_react_use2.useAsyncRetry)(
3502
+ const { value: allTeams, loading: teamsLoading, retry: refreshTeams } = (0, import_react_use3.useAsyncRetry)(
3376
3503
  () => api.getTeams().catch(() => []),
3377
3504
  [api]
3378
3505
  );
3379
- const { value: liteLlmConfig } = (0, import_react_use2.useAsync)(() => api.getConfig(), [api]);
3380
- const { value: managedTeams } = (0, import_react_use2.useAsync)(
3506
+ const { value: liteLlmConfig } = (0, import_react_use3.useAsync)(() => api.getConfig(), [api]);
3507
+ const { value: managedTeams } = (0, import_react_use3.useAsync)(
3381
3508
  async () => liteLlmConfig?.teamManagement?.enabled ? api.getManagedTeams().catch(() => []) : [],
3382
3509
  [api, liteLlmConfig]
3383
3510
  );
@@ -3388,11 +3515,11 @@ var init_LiteLLMPage = __esm({
3388
3515
  const { allowed: canManageMcpServers } = (0, import_plugin_permission_react.usePermission)({ permission: litellmTeamMcpManagePermission });
3389
3516
  const teamMgmtEnabled = liteLlmConfig?.teamManagement?.enabled ?? false;
3390
3517
  const objectPermsEnabled = liteLlmConfig?.teamManagement?.objectPermissionsEnabled ?? false;
3391
- const { value: vectorStores } = (0, import_react_use2.useAsync)(
3518
+ const { value: vectorStores } = (0, import_react_use3.useAsync)(
3392
3519
  async () => objectPermsEnabled ? api.getVectorStores().catch(() => []) : [],
3393
3520
  [api, objectPermsEnabled]
3394
3521
  );
3395
- const { value: mcpServers } = (0, import_react_use2.useAsync)(
3522
+ const { value: mcpServers } = (0, import_react_use3.useAsync)(
3396
3523
  async () => objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],
3397
3524
  [api, objectPermsEnabled]
3398
3525
  );
@@ -3408,7 +3535,7 @@ var init_LiteLLMPage = __esm({
3408
3535
  );
3409
3536
  return byMembership.length > 0 ? byMembership : allTeams;
3410
3537
  }, [allTeams, userInfo]);
3411
- const { value: usage, loading: usageLoading } = (0, import_react_use2.useAsync)(async () => {
3538
+ const { value: usage, loading: usageLoading } = (0, import_react_use3.useAsync)(async () => {
3412
3539
  const startDate = dateRange.start.toISOString().split("T")[0];
3413
3540
  const endDate = dateRange.end.toISOString().split("T")[0];
3414
3541
  return api.getUsage(startDate, endDate);
@@ -3543,12 +3670,12 @@ var init_LiteLLMPage = __esm({
3543
3670
  );
3544
3671
  const isInitialLoading = userLoading && !userInfo;
3545
3672
  if (isInitialLoading) {
3546
- return /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ import_react10.default.createElement(import_CircularProgress4.default, null));
3673
+ return /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ import_react10.default.createElement(import_CircularProgress5.default, null));
3547
3674
  }
3548
3675
  if (userError || !userInfo) {
3549
3676
  const isProvisioningEnabled = userError?.body?.provisioning === true;
3550
3677
  const hint = userError?.body?.hint;
3551
- return /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { p: 3 }, /* @__PURE__ */ import_react10.default.createElement(import_Paper5.default, { sx: { p: 3 } }, /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "h6", gutterBottom: true }, "Account not provisioned"), /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { color: "text.secondary", paragraph: true }, "Your Backstage account is not linked to a LiteLLM user."), hint ? /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", color: "text.secondary" }, hint) : /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", color: "text.secondary" }, isProvisioningEnabled ? "Auto-provisioning is enabled but failed. Check the backend logs." : "Set litellm.provisioning.enabled: true in app-config.yaml to enable auto-provisioning, or ask your administrator to create the account manually.")));
3678
+ return /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { p: 3 }, /* @__PURE__ */ import_react10.default.createElement(import_Paper6.default, { sx: { p: 3 } }, /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "h6", gutterBottom: true }, "Account not provisioned"), /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { color: "text.secondary", paragraph: true }, "Your Backstage account is not linked to a LiteLLM user."), hint ? /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", color: "text.secondary" }, hint) : /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", color: "text.secondary" }, isProvisioningEnabled ? "Auto-provisioning is enabled but failed. Check the backend logs." : "Set litellm.provisioning.enabled: true in app-config.yaml to enable auto-provisioning, or ask your administrator to create the account manually.")));
3552
3679
  }
3553
3680
  const pageTabs = /* @__PURE__ */ import_react10.default.createElement(
3554
3681
  import_Tabs2.default,
@@ -3609,14 +3736,7 @@ var init_LiteLLMPage = __esm({
3609
3736
  for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);
3610
3737
  for (const t of teams ?? []) teamsById.set(t.team_id, t);
3611
3738
  const visibleTeams = Array.from(teamsById.values());
3612
- return /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teamMgmtEnabled && canCreateTeam && /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { sx: { display: "flex", justifyContent: "flex-end" } }, /* @__PURE__ */ import_react10.default.createElement(
3613
- import_Button6.default,
3614
- {
3615
- variant: "contained",
3616
- onClick: () => setManageTeam({ mode: "create" })
3617
- },
3618
- "Create Team"
3619
- )), /* @__PURE__ */ import_react10.default.createElement(
3739
+ return /* @__PURE__ */ import_react10.default.createElement(
3620
3740
  TeamUsage,
3621
3741
  {
3622
3742
  teams: visibleTeams,
@@ -3627,9 +3747,11 @@ var init_LiteLLMPage = __esm({
3627
3747
  },
3628
3748
  getTeamUsageLoading: (teamId) => teamUsageLoading[teamId] ?? false,
3629
3749
  canManage: teamMgmtEnabled && canManageTeam,
3630
- onEditTeam: (t) => setManageTeam({ mode: "edit", team: t })
3750
+ onEditTeam: (t) => setManageTeam({ mode: "edit", team: t }),
3751
+ canCreate: teamMgmtEnabled && canCreateTeam,
3752
+ onCreateTeam: () => setManageTeam({ mode: "create" })
3631
3753
  }
3632
- ));
3754
+ );
3633
3755
  })(), activeTab === "models" && /* @__PURE__ */ import_react10.default.createElement(
3634
3756
  ModelsTable,
3635
3757
  {
@@ -3750,7 +3872,7 @@ module.exports = __toCommonJS(index_exports);
3750
3872
 
3751
3873
  // src/plugin.tsx
3752
3874
  var import_react11 = __toESM(require("react"));
3753
- var import_icons_material7 = require("@mui/icons-material");
3875
+ var import_icons_material8 = require("@mui/icons-material");
3754
3876
  var import_frontend_plugin_api = require("@backstage/frontend-plugin-api");
3755
3877
  init_api();
3756
3878
  var liteLlmApi = import_frontend_plugin_api.ApiBlueprint.make({
@@ -3764,7 +3886,7 @@ var liteLlmPage = import_frontend_plugin_api.PageBlueprint.make({
3764
3886
  params: {
3765
3887
  path: "/litellm",
3766
3888
  title: "LiteLLM",
3767
- icon: /* @__PURE__ */ import_react11.default.createElement(import_icons_material7.TrendingUp, null),
3889
+ icon: /* @__PURE__ */ import_react11.default.createElement(import_icons_material8.TrendingUp, null),
3768
3890
  loader: async () => {
3769
3891
  const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
3770
3892
  return /* @__PURE__ */ import_react11.default.createElement(LiteLLMPage2, null);
@@ -3785,17 +3907,17 @@ init_TeamUsage();
3785
3907
 
3786
3908
  // src/components/LiteLLMHomeWidget.tsx
3787
3909
  var import_react12 = __toESM(require("react"));
3788
- var import_Paper6 = __toESM(require("@mui/material/Paper"));
3910
+ var import_Paper7 = __toESM(require("@mui/material/Paper"));
3789
3911
  var import_Box11 = __toESM(require("@mui/material/Box"));
3790
3912
  var import_Typography11 = __toESM(require("@mui/material/Typography"));
3791
3913
  var import_FormControl2 = __toESM(require("@mui/material/FormControl"));
3792
3914
  var import_Select2 = __toESM(require("@mui/material/Select"));
3793
3915
  var import_MenuItem6 = __toESM(require("@mui/material/MenuItem"));
3794
3916
  var import_Grid2 = __toESM(require("@mui/material/Grid"));
3795
- var import_CircularProgress5 = __toESM(require("@mui/material/CircularProgress"));
3917
+ var import_CircularProgress6 = __toESM(require("@mui/material/CircularProgress"));
3796
3918
  var import_Alert6 = __toESM(require("@mui/material/Alert"));
3797
3919
  var import_recharts3 = require("recharts");
3798
- var import_core_plugin_api3 = require("@backstage/core-plugin-api");
3920
+ var import_core_plugin_api4 = require("@backstage/core-plugin-api");
3799
3921
  init_api();
3800
3922
  init_format();
3801
3923
  function presetToDateRange(preset) {
@@ -3815,7 +3937,7 @@ var LiteLLMHomeWidget = ({
3815
3937
  defaultPeriod = "7d",
3816
3938
  title = "LiteLLM Usage"
3817
3939
  }) => {
3818
- const api = (0, import_core_plugin_api3.useApi)(liteLlmApiRef);
3940
+ const api = (0, import_core_plugin_api4.useApi)(liteLlmApiRef);
3819
3941
  const [period, setPeriod] = (0, import_react12.useState)(defaultPeriod);
3820
3942
  const [loading, setLoading] = (0, import_react12.useState)(true);
3821
3943
  const [usageError, setUsageError] = (0, import_react12.useState)(null);
@@ -3859,7 +3981,7 @@ var LiteLLMHomeWidget = ({
3859
3981
  spend: d.spend
3860
3982
  }));
3861
3983
  const hasSparkline = dailyData.length > 0;
3862
- return /* @__PURE__ */ import_react12.default.createElement(import_Paper6.default, { sx: { p: 2 } }, /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ import_react12.default.createElement(import_Typography11.default, { variant: "h6" }, title), /* @__PURE__ */ import_react12.default.createElement(import_FormControl2.default, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ import_react12.default.createElement(
3984
+ return /* @__PURE__ */ import_react12.default.createElement(import_Paper7.default, { sx: { p: 2 } }, /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ import_react12.default.createElement(import_Typography11.default, { variant: "h6" }, title), /* @__PURE__ */ import_react12.default.createElement(import_FormControl2.default, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ import_react12.default.createElement(
3863
3985
  import_Select2.default,
3864
3986
  {
3865
3987
  value: period,
@@ -3869,7 +3991,7 @@ var LiteLLMHomeWidget = ({
3869
3991
  /* @__PURE__ */ import_react12.default.createElement(import_MenuItem6.default, { value: "today" }, "Today"),
3870
3992
  /* @__PURE__ */ import_react12.default.createElement(import_MenuItem6.default, { value: "7d" }, "7d"),
3871
3993
  /* @__PURE__ */ import_react12.default.createElement(import_MenuItem6.default, { value: "30d" }, "30d")
3872
- ))), loading && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ import_react12.default.createElement(import_CircularProgress5.default, { size: 32 })), !loading && totalFailure && /* @__PURE__ */ import_react12.default.createElement(import_Alert6.default, { severity: "error", sx: { mt: 1 } }, usageError ?? "Failed to load usage data"), !loading && !totalFailure && /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, partialFailure && /* @__PURE__ */ import_react12.default.createElement(import_Alert6.default, { severity: "warning", sx: { mt: 1, mb: 1 } }, usageError ? `Usage data unavailable (${usageError}).` : "", keysError ? ` Key list unavailable (${keysError}).` : "", " Showing what loaded."), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "USD Spent", value: fmtUsd(usage?.total_spend ?? 0) })), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "Tokens In", value: fmtInt(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "Tokens Out", value: fmtInt(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "Keys", value: fmtInt(keys.length) }))), hasSparkline && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { height: 120 }, /* @__PURE__ */ import_react12.default.createElement(import_recharts3.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react12.default.createElement(import_recharts3.AreaChart, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ import_react12.default.createElement(
3994
+ ))), loading && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ import_react12.default.createElement(import_CircularProgress6.default, { size: 32 })), !loading && totalFailure && /* @__PURE__ */ import_react12.default.createElement(import_Alert6.default, { severity: "error", sx: { mt: 1 } }, usageError ?? "Failed to load usage data"), !loading && !totalFailure && /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, partialFailure && /* @__PURE__ */ import_react12.default.createElement(import_Alert6.default, { severity: "warning", sx: { mt: 1, mb: 1 } }, usageError ? `Usage data unavailable (${usageError}).` : "", keysError ? ` Key list unavailable (${keysError}).` : "", " Showing what loaded."), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "USD Spent", value: fmtUsd(usage?.total_spend ?? 0) })), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "Tokens In", value: fmtInt(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "Tokens Out", value: fmtInt(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react12.default.createElement(Kpi, { label: "Keys", value: fmtInt(keys.length) }))), hasSparkline && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { height: 120 }, /* @__PURE__ */ import_react12.default.createElement(import_recharts3.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react12.default.createElement(import_recharts3.AreaChart, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ import_react12.default.createElement(
3873
3995
  import_recharts3.Area,
3874
3996
  {
3875
3997
  type: "monotone",