@acarmisc/backstage-plugin-litellm 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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_Box5, import_Divider2, import_Typography5, import_IconButton3, import_List, import_ListItem, import_ListItemText, import_icons_material4, 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,14 +1957,34 @@ 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"));
1961
+ import_MenuItem2 = __toESM(require("@mui/material/MenuItem"));
1960
1962
  import_Box5 = __toESM(require("@mui/material/Box"));
1961
1963
  import_Divider2 = __toESM(require("@mui/material/Divider"));
1962
1964
  import_Typography5 = __toESM(require("@mui/material/Typography"));
1963
1965
  import_IconButton3 = __toESM(require("@mui/material/IconButton"));
1964
- import_List = __toESM(require("@mui/material/List"));
1965
- import_ListItem = __toESM(require("@mui/material/ListItem"));
1966
- 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"));
1967
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();
1979
+ BUDGET_DURATION_OPTIONS = [
1980
+ { value: "1d", label: "Daily (1d)" },
1981
+ { value: "7d", label: "Weekly (7d)" },
1982
+ { value: "30d", label: "Monthly (30d)" },
1983
+ { value: "90d", label: "Quarterly (90d)" },
1984
+ { value: "365d", label: "Yearly (365d)" }
1985
+ ];
1986
+ DEFAULT_BUDGET_DURATION = "30d";
1987
+ FALLBACK_BUDGET_CEILING = 1e3;
1968
1988
  ManageTeamDialog = ({
1969
1989
  open,
1970
1990
  onClose,
@@ -1990,6 +2010,7 @@ var init_ManageTeamDialog = __esm({
1990
2010
  const [budgetDuration, setBudgetDuration] = (0, import_react5.useState)("");
1991
2011
  const [submitting, setSubmitting] = (0, import_react5.useState)(false);
1992
2012
  const [error, setError] = (0, import_react5.useState)(null);
2013
+ const [memberQuery, setMemberQuery] = (0, import_react5.useState)("");
1993
2014
  const [memberRef, setMemberRef] = (0, import_react5.useState)("");
1994
2015
  const [memberBudget, setMemberBudget] = (0, import_react5.useState)("");
1995
2016
  const [memberBusy, setMemberBusy] = (0, import_react5.useState)(false);
@@ -2001,23 +2022,56 @@ var init_ManageTeamDialog = __esm({
2001
2022
  const [mcpBusy, setMcpBusy] = (0, import_react5.useState)(false);
2002
2023
  const [mcpError, setMcpError] = (0, import_react5.useState)(null);
2003
2024
  const allowUnlimitedBudget = config?.teamManagement?.allowUnlimitedBudget ?? false;
2004
- const maxBudgetCeiling = config?.teamManagement?.maxBudgetCeiling;
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]);
2005
2056
  (0, import_react5.useEffect)(() => {
2006
2057
  if (open) {
2007
2058
  if (mode === "edit" && team) {
2008
2059
  setAlias(team.team_alias ?? "");
2009
2060
  setModels(team.models ?? []);
2010
- setMaxBudget(team.max_budget ? String(team.max_budget) : "");
2061
+ setMaxBudget(
2062
+ team.max_budget ? String(team.max_budget) : String(maxBudgetCeiling)
2063
+ );
2011
2064
  setUnlimited(allowUnlimitedBudget && !team.max_budget);
2012
- setBudgetDuration("");
2065
+ setBudgetDuration(team.budget_duration ?? DEFAULT_BUDGET_DURATION);
2013
2066
  } else {
2014
2067
  setAlias("");
2015
2068
  setModels([]);
2016
- setMaxBudget("");
2069
+ setMaxBudget(String(maxBudgetCeiling));
2017
2070
  setUnlimited(allowUnlimitedBudget);
2018
- setBudgetDuration("");
2071
+ setBudgetDuration(DEFAULT_BUDGET_DURATION);
2019
2072
  }
2020
2073
  setError(null);
2074
+ setMemberQuery("");
2021
2075
  setMemberRef("");
2022
2076
  setMemberBudget("");
2023
2077
  setMemberError(null);
@@ -2026,7 +2080,7 @@ var init_ManageTeamDialog = __esm({
2026
2080
  setMcpIds(team?.object_permission?.mcp_servers ?? []);
2027
2081
  setMcpError(null);
2028
2082
  }
2029
- }, [open, mode, team, allowUnlimitedBudget]);
2083
+ }, [open, mode, team, allowUnlimitedBudget, maxBudgetCeiling]);
2030
2084
  const handleSubmit = async () => {
2031
2085
  setError(null);
2032
2086
  if (!alias.trim()) {
@@ -2047,7 +2101,7 @@ var init_ManageTeamDialog = __esm({
2047
2101
  setError("Budget must be a positive number");
2048
2102
  return;
2049
2103
  }
2050
- if (maxBudgetCeiling !== null && maxBudgetCeiling !== void 0 && budget > maxBudgetCeiling) {
2104
+ if (budget > maxBudgetCeiling) {
2051
2105
  setError(`Budget cannot exceed $${maxBudgetCeiling}`);
2052
2106
  return;
2053
2107
  }
@@ -2089,6 +2143,7 @@ var init_ManageTeamDialog = __esm({
2089
2143
  try {
2090
2144
  setMemberBusy(true);
2091
2145
  await onAddMember(memberRef.trim(), budget);
2146
+ setMemberQuery("");
2092
2147
  setMemberRef("");
2093
2148
  setMemberBudget("");
2094
2149
  } catch (err) {
@@ -2134,8 +2189,7 @@ var init_ManageTeamDialog = __esm({
2134
2189
  }
2135
2190
  };
2136
2191
  const modelNames = allModels.map((m) => m.model_name);
2137
- const members = team?.members_with_roles ?? [];
2138
- const showMembers = mode === "edit" && !!canManageMembers;
2192
+ const durationOptions = BUDGET_DURATION_OPTIONS.some((o) => o.value === budgetDuration) ? BUDGET_DURATION_OPTIONS : [...BUDGET_DURATION_OPTIONS, { value: budgetDuration, label: budgetDuration }];
2139
2193
  const showKnowledgeBases = mode === "edit" && !!canManageKnowledgeBases;
2140
2194
  const kbOptions = (vectorStores ?? []).map((v) => v.id);
2141
2195
  const kbLabel = (id) => (vectorStores ?? []).find((v) => v.id === id)?.name ?? id;
@@ -2159,7 +2213,15 @@ var init_ManageTeamDialog = __esm({
2159
2213
  value: models,
2160
2214
  onChange: (_, newValue) => setModels(newValue),
2161
2215
  disabled: submitting,
2162
- 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
+ )
2163
2225
  }
2164
2226
  ), /* @__PURE__ */ import_react5.default.createElement(
2165
2227
  import_TextField3.default,
@@ -2169,7 +2231,8 @@ var init_ManageTeamDialog = __esm({
2169
2231
  value: maxBudget,
2170
2232
  onChange: (e) => setMaxBudget(e.target.value),
2171
2233
  disabled: submitting || unlimited,
2172
- helperText: maxBudgetCeiling !== null && maxBudgetCeiling !== void 0 ? `Maximum: $${maxBudgetCeiling}` : void 0,
2234
+ inputProps: { min: 0, max: maxBudgetCeiling },
2235
+ helperText: `Maximum: $${maxBudgetCeiling}`,
2173
2236
  fullWidth: true
2174
2237
  }
2175
2238
  ), allowUnlimitedBudget && /* @__PURE__ */ import_react5.default.createElement(
@@ -2181,41 +2244,78 @@ var init_ManageTeamDialog = __esm({
2181
2244
  ), /* @__PURE__ */ import_react5.default.createElement(
2182
2245
  import_TextField3.default,
2183
2246
  {
2247
+ select: true,
2184
2248
  label: "Budget Duration",
2185
2249
  value: budgetDuration,
2186
2250
  onChange: (e) => setBudgetDuration(e.target.value),
2187
- placeholder: "30d",
2188
- disabled: submitting,
2251
+ disabled: submitting || unlimited,
2252
+ helperText: "Spend-reset period for the team budget",
2189
2253
  fullWidth: true
2190
- }
2191
- ), 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(
2192
- import_ListItem.default,
2254
+ },
2255
+ durationOptions.map((o) => /* @__PURE__ */ import_react5.default.createElement(import_MenuItem2.default, { key: o.value, value: o.value }, o.label))
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,
2193
2258
  {
2194
- key: m.user_id,
2195
- disableGutters: true,
2196
- secondaryAction: /* @__PURE__ */ import_react5.default.createElement(
2197
- import_IconButton3.default,
2198
- {
2199
- edge: "end",
2200
- size: "small",
2201
- "aria-label": `remove ${m.user_id}`,
2202
- disabled: memberBusy,
2203
- onClick: () => handleRemoveMember(m.user_id)
2204
- },
2205
- /* @__PURE__ */ import_react5.default.createElement(import_icons_material4.Delete, { fontSize: "small" })
2206
- )
2259
+ variant: "caption",
2260
+ color: "text.secondary",
2261
+ sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
2207
2262
  },
2208
- /* @__PURE__ */ import_react5.default.createElement(import_ListItemText.default, { primary: m.user_id, secondary: m.role })
2209
- ))), /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, { sx: { display: "flex", gap: 1, alignItems: "flex-start", mt: 1 } }, /* @__PURE__ */ import_react5.default.createElement(
2210
- import_TextField3.default,
2263
+ m.user_id
2264
+ )) : /* @__PURE__ */ import_react5.default.createElement(
2265
+ import_Typography5.default,
2211
2266
  {
2212
- label: "Backstage user ref",
2213
- placeholder: "user:default/alice",
2214
- value: memberRef,
2215
- onChange: (e) => setMemberRef(e.target.value),
2216
- 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",
2217
2275
  size: "small",
2218
- 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
+ )
2219
2319
  }
2220
2320
  ), /* @__PURE__ */ import_react5.default.createElement(
2221
2321
  import_TextField3.default,
@@ -2286,23 +2386,23 @@ function rateTone(rate) {
2286
2386
  if (rate >= 0.9) return "warning";
2287
2387
  return "danger";
2288
2388
  }
2289
- var import_react6, import_Paper3, import_Box6, import_Typography6, import_TextField4, import_MenuItem2, 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;
2290
2390
  var init_UsageStats = __esm({
2291
2391
  "src/components/UsageStats.tsx"() {
2292
2392
  "use strict";
2293
2393
  import_react6 = __toESM(require("react"));
2294
- import_Paper3 = __toESM(require("@mui/material/Paper"));
2394
+ import_Paper4 = __toESM(require("@mui/material/Paper"));
2295
2395
  import_Box6 = __toESM(require("@mui/material/Box"));
2296
2396
  import_Typography6 = __toESM(require("@mui/material/Typography"));
2297
2397
  import_TextField4 = __toESM(require("@mui/material/TextField"));
2298
- import_MenuItem2 = __toESM(require("@mui/material/MenuItem"));
2398
+ import_MenuItem3 = __toESM(require("@mui/material/MenuItem"));
2299
2399
  import_Grid = __toESM(require("@mui/material/Grid"));
2300
- import_Table2 = __toESM(require("@mui/material/Table"));
2301
- import_TableBody2 = __toESM(require("@mui/material/TableBody"));
2302
- import_TableCell2 = __toESM(require("@mui/material/TableCell"));
2303
- import_TableContainer2 = __toESM(require("@mui/material/TableContainer"));
2304
- import_TableHead2 = __toESM(require("@mui/material/TableHead"));
2305
- 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"));
2306
2406
  import_Skeleton3 = __toESM(require("@mui/material/Skeleton"));
2307
2407
  import_recharts = require("recharts");
2308
2408
  init_format();
@@ -2474,21 +2574,21 @@ var init_UsageStats = __esm({
2474
2574
  ];
2475
2575
  const renderKeyRows = () => {
2476
2576
  if (loading) {
2477
- 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 })));
2478
2578
  }
2479
2579
  if (keyRows.length === 0) {
2480
- 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" })));
2481
2581
  }
2482
- 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 }))));
2483
2583
  };
2484
2584
  const renderModelRows = () => {
2485
2585
  if (loading) {
2486
- 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 })));
2487
2587
  }
2488
2588
  if (modelRows.length === 0) {
2489
- 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" })));
2490
2590
  }
2491
- 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 }))));
2492
2592
  };
2493
2593
  const periodSelect = /* @__PURE__ */ import_react6.default.createElement(
2494
2594
  import_TextField4.default,
@@ -2500,7 +2600,7 @@ var init_UsageStats = __esm({
2500
2600
  onChange: (e) => handlePresetChange(e.target.value),
2501
2601
  sx: { minWidth: 160 }
2502
2602
  },
2503
- Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem2.default, { key: p, value: p }, PRESET_LABELS[p]))
2603
+ Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem3.default, { key: p, value: p }, PRESET_LABELS[p]))
2504
2604
  );
2505
2605
  return /* @__PURE__ */ import_react6.default.createElement(
2506
2606
  SectionCard,
@@ -2545,8 +2645,8 @@ var init_UsageStats = __esm({
2545
2645
  onChange: (e) => setSelectedModel(e.target.value),
2546
2646
  sx: { minWidth: 220 }
2547
2647
  },
2548
- /* @__PURE__ */ import_react6.default.createElement(import_MenuItem2.default, { value: "all" }, "All models"),
2549
- models.map((m) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem2.default, { key: m.model_name, value: m.model_name }, m.model_name))
2648
+ /* @__PURE__ */ import_react6.default.createElement(import_MenuItem3.default, { value: "all" }, "All models"),
2649
+ models.map((m) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem3.default, { key: m.model_name, value: m.model_name }, m.model_name))
2550
2650
  )
2551
2651
  ),
2552
2652
  tab === "costs" && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { container: true, spacing: 2 }, /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Daily spend by model", height: 260 }, /* @__PURE__ */ import_react6.default.createElement(ChartOrFallback, { loading, empty: modelSpendByDate.length === 0, height: 260 }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.AreaChart, { data: modelSpendByDate, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { tickFormatter: fmtUsdCompact, width: 56, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(
@@ -2641,7 +2741,7 @@ var init_UsageStats = __esm({
2641
2741
  height: Math.max(200, topModelSpendBars.length * 34)
2642
2742
  },
2643
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] })))
2644
- ))), /* @__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()))))),
2645
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(
2646
2746
  ChartOrFallback,
2647
2747
  {
@@ -2650,7 +2750,7 @@ var init_UsageStats = __esm({
2650
2750
  height: Math.max(160, topKeySpendBars.length * 32)
2651
2751
  },
2652
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 })))
2653
- ))), /* @__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())))))
2654
2754
  );
2655
2755
  };
2656
2756
  }
@@ -2662,26 +2762,26 @@ function budgetTone2(isOver, isNear) {
2662
2762
  if (isNear) return "warning";
2663
2763
  return "accent";
2664
2764
  }
2665
- 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;
2666
2766
  var init_TeamUsage = __esm({
2667
2767
  "src/components/TeamUsage.tsx"() {
2668
2768
  "use strict";
2669
2769
  import_react7 = __toESM(require("react"));
2670
- import_Paper4 = __toESM(require("@mui/material/Paper"));
2770
+ import_Paper5 = __toESM(require("@mui/material/Paper"));
2671
2771
  import_Box7 = __toESM(require("@mui/material/Box"));
2672
2772
  import_Typography7 = __toESM(require("@mui/material/Typography"));
2673
2773
  import_Skeleton4 = __toESM(require("@mui/material/Skeleton"));
2674
2774
  import_Divider3 = __toESM(require("@mui/material/Divider"));
2675
- import_Table3 = __toESM(require("@mui/material/Table"));
2676
- import_TableBody3 = __toESM(require("@mui/material/TableBody"));
2677
- import_TableCell3 = __toESM(require("@mui/material/TableCell"));
2678
- import_TableHead3 = __toESM(require("@mui/material/TableHead"));
2679
- import_TableRow3 = __toESM(require("@mui/material/TableRow"));
2680
- 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"));
2681
2781
  import_Collapse = __toESM(require("@mui/material/Collapse"));
2682
2782
  import_IconButton4 = __toESM(require("@mui/material/IconButton"));
2683
2783
  import_Button5 = __toESM(require("@mui/material/Button"));
2684
- import_CircularProgress3 = __toESM(require("@mui/material/CircularProgress"));
2784
+ import_CircularProgress4 = __toESM(require("@mui/material/CircularProgress"));
2685
2785
  import_styles4 = require("@mui/material/styles");
2686
2786
  import_icons_material5 = require("@mui/icons-material");
2687
2787
  import_recharts2 = require("recharts");
@@ -2698,7 +2798,7 @@ var init_TeamUsage = __esm({
2698
2798
  const dailyData = usage?.daily_usage?.map((d) => ({ date: d.date, spend: d.spend })) ?? [];
2699
2799
  const renderDailySpendSection = () => {
2700
2800
  if (usageLoading) {
2701
- 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 }));
2702
2802
  }
2703
2803
  if (dailyData.length === 0) return null;
2704
2804
  return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { mb: 2.5 }, /* @__PURE__ */ import_react7.default.createElement(
@@ -2737,7 +2837,7 @@ var init_TeamUsage = __esm({
2737
2837
  },
2738
2838
  label
2739
2839
  );
2740
- 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(
2741
2841
  import_Box7.default,
2742
2842
  {
2743
2843
  sx: (theme) => ({
@@ -2802,13 +2902,13 @@ var init_TeamUsage = __esm({
2802
2902
  /* @__PURE__ */ import_react7.default.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
2803
2903
  /* @__PURE__ */ import_react7.default.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
2804
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(
2805
- import_TableContainer3.default,
2905
+ import_TableContainer4.default,
2806
2906
  {
2807
- component: import_Paper4.default,
2907
+ component: import_Paper5.default,
2808
2908
  variant: "outlined",
2809
2909
  sx: { borderRadius: 1.5 }
2810
2910
  },
2811
- /* @__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(
2812
2912
  import_Typography7.default,
2813
2913
  {
2814
2914
  variant: "caption",
@@ -2823,7 +2923,7 @@ var init_TeamUsage = __esm({
2823
2923
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
2824
2924
  },
2825
2925
  m.user_id
2826
- )), /* @__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(
2827
2927
  StatusPill,
2828
2928
  {
2829
2929
  label: m.role,
@@ -2839,13 +2939,26 @@ var init_TeamUsage = __esm({
2839
2939
  getTeamUsage,
2840
2940
  getTeamUsageLoading,
2841
2941
  canManage,
2842
- onEditTeam
2942
+ onEditTeam,
2943
+ canCreate,
2944
+ onCreateTeam
2843
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;
2844
2957
  if (loading) {
2845
- 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 }));
2846
2959
  }
2847
2960
  if (!teams.length) {
2848
- 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(
2849
2962
  EmptyState,
2850
2963
  {
2851
2964
  message: "You're not a member of any LiteLLM team yet.",
@@ -2853,17 +2966,25 @@ var init_TeamUsage = __esm({
2853
2966
  }
2854
2967
  ));
2855
2968
  }
2856
- 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(
2857
- TeamCard,
2969
+ return /* @__PURE__ */ import_react7.default.createElement(
2970
+ SectionCard,
2858
2971
  {
2859
- key: team.team_id,
2860
- team,
2861
- usage: getTeamUsage(team.team_id),
2862
- usageLoading: getTeamUsageLoading(team.team_id),
2863
- canManage,
2864
- onEditTeam
2865
- }
2866
- ))));
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
+ );
2867
2988
  };
2868
2989
  }
2869
2990
  });
@@ -2886,20 +3007,20 @@ function fmtTokens(n) {
2886
3007
  if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
2887
3008
  return String(n);
2888
3009
  }
2889
- var import_react8, import_Box8, import_Table4, import_TableBody4, import_TableCell4, import_TableContainer4, import_TableHead4, import_TableRow4, import_Typography8, import_MenuItem3, 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, ALL_PROXY_MODELS2, ModelsTable;
2890
3011
  var init_ModelsTable = __esm({
2891
3012
  "src/components/ModelsTable.tsx"() {
2892
3013
  "use strict";
2893
3014
  import_react8 = __toESM(require("react"));
2894
3015
  import_Box8 = __toESM(require("@mui/material/Box"));
2895
- import_Table4 = __toESM(require("@mui/material/Table"));
2896
- import_TableBody4 = __toESM(require("@mui/material/TableBody"));
2897
- import_TableCell4 = __toESM(require("@mui/material/TableCell"));
2898
- import_TableContainer4 = __toESM(require("@mui/material/TableContainer"));
2899
- import_TableHead4 = __toESM(require("@mui/material/TableHead"));
2900
- 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"));
2901
3022
  import_Typography8 = __toESM(require("@mui/material/Typography"));
2902
- import_MenuItem3 = __toESM(require("@mui/material/MenuItem"));
3023
+ import_MenuItem4 = __toESM(require("@mui/material/MenuItem"));
2903
3024
  import_Select = __toESM(require("@mui/material/Select"));
2904
3025
  import_FormControl = __toESM(require("@mui/material/FormControl"));
2905
3026
  import_InputLabel = __toESM(require("@mui/material/InputLabel"));
@@ -2953,7 +3074,7 @@ var init_ModelsTable = __esm({
2953
3074
  label: "Team",
2954
3075
  onChange: (e) => setSelectedTeamId(e.target.value)
2955
3076
  },
2956
- teams.map((t) => /* @__PURE__ */ import_react8.default.createElement(import_MenuItem3.default, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
3077
+ 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))
2957
3078
  ))),
2958
3079
  loading && /* @__PURE__ */ import_react8.default.createElement(EmptyState, { message: "Loading models\u2026" }),
2959
3080
  !loading && !selectedTeamId && /* @__PURE__ */ import_react8.default.createElement(
@@ -2970,7 +3091,7 @@ var init_ModelsTable = __esm({
2970
3091
  hint: allModels.length === 0 ? "No models are configured in the system" : "None of the team's assigned models were found in the catalog"
2971
3092
  }
2972
3093
  ),
2973
- !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(
3094
+ !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(
2974
3095
  import_Box8.default,
2975
3096
  {
2976
3097
  component: "span",
@@ -2982,7 +3103,7 @@ var init_ModelsTable = __esm({
2982
3103
  style: { cursor: "pointer", display: "inline-flex" }
2983
3104
  },
2984
3105
  /* @__PURE__ */ import_react8.default.createElement(import_ContentCopy.default, { sx: { fontSize: 14 } })
2985
- )))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell4.default, null, /* @__PURE__ */ import_react8.default.createElement(
3106
+ )))), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react8.default.createElement(
2986
3107
  import_Box8.default,
2987
3108
  {
2988
3109
  component: "span",
@@ -2999,7 +3120,7 @@ var init_ModelsTable = __esm({
2999
3120
  }
3000
3121
  },
3001
3122
  m.mode
3002
- )), /* @__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" })))))))),
3123
+ )), /* @__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" })))))))),
3003
3124
  /* @__PURE__ */ import_react8.default.createElement(
3004
3125
  import_Snackbar.default,
3005
3126
  {
@@ -3036,10 +3157,10 @@ function formatDateTime(iso) {
3036
3157
  }
3037
3158
  function renderAuditLogBody(loading, entries) {
3038
3159
  if (loading) {
3039
- 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 })));
3160
+ 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 })));
3040
3161
  }
3041
3162
  if (entries.length === 0) {
3042
- 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(
3163
+ 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(
3043
3164
  EmptyState,
3044
3165
  {
3045
3166
  message: "No audit events found",
@@ -3049,29 +3170,29 @@ function renderAuditLogBody(loading, entries) {
3049
3170
  }
3050
3171
  return entries.map((entry) => /* @__PURE__ */ import_react9.default.createElement(DetailRow, { key: entry.id, entry }));
3051
3172
  }
3052
- var import_react9, import_Box9, import_Typography9, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TablePagination, import_TextField5, import_MenuItem4, import_Skeleton5, import_Collapse2, import_IconButton5, import_Alert4, import_styles6, import_icons_material6, import_react_use, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3173
+ var import_react9, import_Box9, import_Typography9, import_Table6, import_TableBody6, import_TableCell6, import_TableContainer6, import_TableHead6, import_TableRow6, import_TablePagination, import_TextField5, import_MenuItem5, import_Skeleton5, import_Collapse2, import_IconButton5, import_Alert4, import_styles6, import_icons_material6, import_react_use2, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3053
3174
  var init_AuditLog = __esm({
3054
3175
  "src/components/AuditLog.tsx"() {
3055
3176
  "use strict";
3056
3177
  import_react9 = __toESM(require("react"));
3057
3178
  import_Box9 = __toESM(require("@mui/material/Box"));
3058
3179
  import_Typography9 = __toESM(require("@mui/material/Typography"));
3059
- import_Table5 = __toESM(require("@mui/material/Table"));
3060
- import_TableBody5 = __toESM(require("@mui/material/TableBody"));
3061
- import_TableCell5 = __toESM(require("@mui/material/TableCell"));
3062
- import_TableContainer5 = __toESM(require("@mui/material/TableContainer"));
3063
- import_TableHead5 = __toESM(require("@mui/material/TableHead"));
3064
- import_TableRow5 = __toESM(require("@mui/material/TableRow"));
3180
+ import_Table6 = __toESM(require("@mui/material/Table"));
3181
+ import_TableBody6 = __toESM(require("@mui/material/TableBody"));
3182
+ import_TableCell6 = __toESM(require("@mui/material/TableCell"));
3183
+ import_TableContainer6 = __toESM(require("@mui/material/TableContainer"));
3184
+ import_TableHead6 = __toESM(require("@mui/material/TableHead"));
3185
+ import_TableRow6 = __toESM(require("@mui/material/TableRow"));
3065
3186
  import_TablePagination = __toESM(require("@mui/material/TablePagination"));
3066
3187
  import_TextField5 = __toESM(require("@mui/material/TextField"));
3067
- import_MenuItem4 = __toESM(require("@mui/material/MenuItem"));
3188
+ import_MenuItem5 = __toESM(require("@mui/material/MenuItem"));
3068
3189
  import_Skeleton5 = __toESM(require("@mui/material/Skeleton"));
3069
3190
  import_Collapse2 = __toESM(require("@mui/material/Collapse"));
3070
3191
  import_IconButton5 = __toESM(require("@mui/material/IconButton"));
3071
3192
  import_Alert4 = __toESM(require("@mui/material/Alert"));
3072
3193
  import_styles6 = require("@mui/material/styles");
3073
3194
  import_icons_material6 = require("@mui/icons-material");
3074
- import_react_use = require("react-use");
3195
+ import_react_use2 = require("react-use");
3075
3196
  init_ui();
3076
3197
  ACTION_TONES = {
3077
3198
  created: "success",
@@ -3090,7 +3211,7 @@ var init_AuditLog = __esm({
3090
3211
  DetailRow = ({ entry }) => {
3091
3212
  const [open, setOpen] = (0, import_react9.useState)(false);
3092
3213
  const hasDetail = entry.before_value || entry.updated_values;
3093
- 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(
3214
+ 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(
3094
3215
  import_IconButton5.default,
3095
3216
  {
3096
3217
  size: "small",
@@ -3104,7 +3225,7 @@ var init_AuditLog = __esm({
3104
3225
  })
3105
3226
  },
3106
3227
  /* @__PURE__ */ import_react9.default.createElement(import_icons_material6.KeyboardArrowDown, { fontSize: "small" })
3107
- )), /* @__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(
3228
+ )), /* @__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(
3108
3229
  import_Typography9.default,
3109
3230
  {
3110
3231
  variant: "body2",
@@ -3114,7 +3235,7 @@ var init_AuditLog = __esm({
3114
3235
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 12 }
3115
3236
  },
3116
3237
  entry.object_id ? entry.object_id.slice(0, 20) + (entry.object_id.length > 20 ? "\u2026" : "") : "\u2014"
3117
- )), /* @__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(
3238
+ )), /* @__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(
3118
3239
  import_Box9.default,
3119
3240
  {
3120
3241
  display: "flex",
@@ -3159,7 +3280,7 @@ var init_AuditLog = __esm({
3159
3280
  () => ({ page: page + 1, page_size: pageSize, ...filters }),
3160
3281
  [page, pageSize, filters]
3161
3282
  )();
3162
- const { value, loading, error } = (0, import_react_use.useAsync)(
3283
+ const { value, loading, error } = (0, import_react_use2.useAsync)(
3163
3284
  () => api.getAuditLogs(fetchParams),
3164
3285
  [api, fetchParams]
3165
3286
  );
@@ -3184,11 +3305,11 @@ var init_AuditLog = __esm({
3184
3305
  },
3185
3306
  sx: { minWidth: 150 }
3186
3307
  },
3187
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "" }, "All actions"),
3188
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "created" }, "Created"),
3189
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "updated" }, "Updated"),
3190
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "deleted" }, "Deleted"),
3191
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "blocked" }, "Blocked")
3308
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "" }, "All actions"),
3309
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "created" }, "Created"),
3310
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "updated" }, "Updated"),
3311
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "deleted" }, "Deleted"),
3312
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "blocked" }, "Blocked")
3192
3313
  ), /* @__PURE__ */ import_react9.default.createElement(
3193
3314
  import_TextField5.default,
3194
3315
  {
@@ -3202,12 +3323,12 @@ var init_AuditLog = __esm({
3202
3323
  },
3203
3324
  sx: { minWidth: 150 }
3204
3325
  },
3205
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "" }, "All tables"),
3206
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "LiteLLM_VerificationToken" }, "Key"),
3207
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "LiteLLM_TeamTable" }, "Team"),
3208
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "LiteLLM_TeamMembership" }, "Team member"),
3209
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
3210
- /* @__PURE__ */ import_react9.default.createElement(import_MenuItem4.default, { value: "LiteLLM_UserTable" }, "User")
3326
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "" }, "All tables"),
3327
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_VerificationToken" }, "Key"),
3328
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_TeamTable" }, "Team"),
3329
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_TeamMembership" }, "Team member"),
3330
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
3331
+ /* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_UserTable" }, "User")
3211
3332
  ), /* @__PURE__ */ import_react9.default.createElement(
3212
3333
  import_TextField5.default,
3213
3334
  {
@@ -3223,7 +3344,7 @@ var init_AuditLog = __esm({
3223
3344
  ))
3224
3345
  },
3225
3346
  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)),
3226
- /* @__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)))),
3347
+ /* @__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)))),
3227
3348
  /* @__PURE__ */ import_react9.default.createElement(
3228
3349
  import_TablePagination.default,
3229
3350
  {
@@ -3293,7 +3414,7 @@ function initDateRange() {
3293
3414
  else start.setDate(start.getDate() - 7);
3294
3415
  return { start, end };
3295
3416
  }
3296
- 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;
3417
+ 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;
3297
3418
  var init_LiteLLMPage = __esm({
3298
3419
  "src/components/LiteLLMPage.tsx"() {
3299
3420
  "use strict";
@@ -3301,14 +3422,13 @@ var init_LiteLLMPage = __esm({
3301
3422
  import_Box10 = __toESM(require("@mui/material/Box"));
3302
3423
  import_Snackbar2 = __toESM(require("@mui/material/Snackbar"));
3303
3424
  import_Alert5 = __toESM(require("@mui/material/Alert"));
3304
- import_CircularProgress4 = __toESM(require("@mui/material/CircularProgress"));
3425
+ import_CircularProgress5 = __toESM(require("@mui/material/CircularProgress"));
3305
3426
  import_Typography10 = __toESM(require("@mui/material/Typography"));
3306
- import_Paper5 = __toESM(require("@mui/material/Paper"));
3427
+ import_Paper6 = __toESM(require("@mui/material/Paper"));
3307
3428
  import_Tabs2 = __toESM(require("@mui/material/Tabs"));
3308
3429
  import_Tab2 = __toESM(require("@mui/material/Tab"));
3309
- import_Button6 = __toESM(require("@mui/material/Button"));
3310
- import_react_use2 = require("react-use");
3311
- import_core_plugin_api2 = require("@backstage/core-plugin-api");
3430
+ import_react_use3 = require("react-use");
3431
+ import_core_plugin_api3 = require("@backstage/core-plugin-api");
3312
3432
  import_plugin_permission_react = require("@backstage/plugin-permission-react");
3313
3433
  init_DashboardHeader();
3314
3434
  init_KeysTable();
@@ -3322,7 +3442,7 @@ var init_LiteLLMPage = __esm({
3322
3442
  init_permissions();
3323
3443
  PERIOD_LS_KEY2 = "litellm_usage_period";
3324
3444
  LiteLLMPage = () => {
3325
- const api = (0, import_core_plugin_api2.useApi)(liteLlmApiRef);
3445
+ const api = (0, import_core_plugin_api3.useApi)(liteLlmApiRef);
3326
3446
  const [dateRange, setDateRange] = (0, import_react10.useState)(initDateRange);
3327
3447
  const [currentPreset, setCurrentPreset] = (0, import_react10.useState)(() => {
3328
3448
  try {
@@ -3337,11 +3457,11 @@ var init_LiteLLMPage = __esm({
3337
3457
  const [manageTeam, setManageTeam] = (0, import_react10.useState)(null);
3338
3458
  const [teamUsageCache, setTeamUsageCache] = (0, import_react10.useState)({});
3339
3459
  const [teamUsageLoading, setTeamUsageLoading] = (0, import_react10.useState)({});
3340
- const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use2.useAsync)(
3460
+ const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use3.useAsync)(
3341
3461
  () => api.getUserInfo(),
3342
3462
  [api]
3343
3463
  );
3344
- const { value: keys, loading: keysLoading, retry: refreshKeys } = (0, import_react_use2.useAsyncRetry)(
3464
+ const { value: keys, loading: keysLoading, retry: refreshKeys } = (0, import_react_use3.useAsyncRetry)(
3345
3465
  async () => {
3346
3466
  try {
3347
3467
  return await api.listKeys();
@@ -3352,16 +3472,16 @@ var init_LiteLLMPage = __esm({
3352
3472
  },
3353
3473
  [api]
3354
3474
  );
3355
- const { value: allModels, loading: modelsLoading } = (0, import_react_use2.useAsync)(
3475
+ const { value: allModels, loading: modelsLoading } = (0, import_react_use3.useAsync)(
3356
3476
  () => api.listModels().catch(() => []),
3357
3477
  [api]
3358
3478
  );
3359
- const { value: allTeams, loading: teamsLoading, retry: refreshTeams } = (0, import_react_use2.useAsyncRetry)(
3479
+ const { value: allTeams, loading: teamsLoading, retry: refreshTeams } = (0, import_react_use3.useAsyncRetry)(
3360
3480
  () => api.getTeams().catch(() => []),
3361
3481
  [api]
3362
3482
  );
3363
- const { value: liteLlmConfig } = (0, import_react_use2.useAsync)(() => api.getConfig(), [api]);
3364
- const { value: managedTeams } = (0, import_react_use2.useAsync)(
3483
+ const { value: liteLlmConfig } = (0, import_react_use3.useAsync)(() => api.getConfig(), [api]);
3484
+ const { value: managedTeams } = (0, import_react_use3.useAsync)(
3365
3485
  async () => liteLlmConfig?.teamManagement?.enabled ? api.getManagedTeams().catch(() => []) : [],
3366
3486
  [api, liteLlmConfig]
3367
3487
  );
@@ -3372,11 +3492,11 @@ var init_LiteLLMPage = __esm({
3372
3492
  const { allowed: canManageMcpServers } = (0, import_plugin_permission_react.usePermission)({ permission: litellmTeamMcpManagePermission });
3373
3493
  const teamMgmtEnabled = liteLlmConfig?.teamManagement?.enabled ?? false;
3374
3494
  const objectPermsEnabled = liteLlmConfig?.teamManagement?.objectPermissionsEnabled ?? false;
3375
- const { value: vectorStores } = (0, import_react_use2.useAsync)(
3495
+ const { value: vectorStores } = (0, import_react_use3.useAsync)(
3376
3496
  async () => objectPermsEnabled ? api.getVectorStores().catch(() => []) : [],
3377
3497
  [api, objectPermsEnabled]
3378
3498
  );
3379
- const { value: mcpServers } = (0, import_react_use2.useAsync)(
3499
+ const { value: mcpServers } = (0, import_react_use3.useAsync)(
3380
3500
  async () => objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],
3381
3501
  [api, objectPermsEnabled]
3382
3502
  );
@@ -3392,7 +3512,7 @@ var init_LiteLLMPage = __esm({
3392
3512
  );
3393
3513
  return byMembership.length > 0 ? byMembership : allTeams;
3394
3514
  }, [allTeams, userInfo]);
3395
- const { value: usage, loading: usageLoading } = (0, import_react_use2.useAsync)(async () => {
3515
+ const { value: usage, loading: usageLoading } = (0, import_react_use3.useAsync)(async () => {
3396
3516
  const startDate = dateRange.start.toISOString().split("T")[0];
3397
3517
  const endDate = dateRange.end.toISOString().split("T")[0];
3398
3518
  return api.getUsage(startDate, endDate);
@@ -3527,12 +3647,12 @@ var init_LiteLLMPage = __esm({
3527
3647
  );
3528
3648
  const isInitialLoading = userLoading && !userInfo;
3529
3649
  if (isInitialLoading) {
3530
- 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));
3650
+ 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));
3531
3651
  }
3532
3652
  if (userError || !userInfo) {
3533
3653
  const isProvisioningEnabled = userError?.body?.provisioning === true;
3534
3654
  const hint = userError?.body?.hint;
3535
- 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.")));
3655
+ 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.")));
3536
3656
  }
3537
3657
  const pageTabs = /* @__PURE__ */ import_react10.default.createElement(
3538
3658
  import_Tabs2.default,
@@ -3593,14 +3713,7 @@ var init_LiteLLMPage = __esm({
3593
3713
  for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);
3594
3714
  for (const t of teams ?? []) teamsById.set(t.team_id, t);
3595
3715
  const visibleTeams = Array.from(teamsById.values());
3596
- 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(
3597
- import_Button6.default,
3598
- {
3599
- variant: "contained",
3600
- onClick: () => setManageTeam({ mode: "create" })
3601
- },
3602
- "Create Team"
3603
- )), /* @__PURE__ */ import_react10.default.createElement(
3716
+ return /* @__PURE__ */ import_react10.default.createElement(
3604
3717
  TeamUsage,
3605
3718
  {
3606
3719
  teams: visibleTeams,
@@ -3611,9 +3724,11 @@ var init_LiteLLMPage = __esm({
3611
3724
  },
3612
3725
  getTeamUsageLoading: (teamId) => teamUsageLoading[teamId] ?? false,
3613
3726
  canManage: teamMgmtEnabled && canManageTeam,
3614
- onEditTeam: (t) => setManageTeam({ mode: "edit", team: t })
3727
+ onEditTeam: (t) => setManageTeam({ mode: "edit", team: t }),
3728
+ canCreate: teamMgmtEnabled && canCreateTeam,
3729
+ onCreateTeam: () => setManageTeam({ mode: "create" })
3615
3730
  }
3616
- ));
3731
+ );
3617
3732
  })(), activeTab === "models" && /* @__PURE__ */ import_react10.default.createElement(
3618
3733
  ModelsTable,
3619
3734
  {
@@ -3769,17 +3884,17 @@ init_TeamUsage();
3769
3884
 
3770
3885
  // src/components/LiteLLMHomeWidget.tsx
3771
3886
  var import_react12 = __toESM(require("react"));
3772
- var import_Paper6 = __toESM(require("@mui/material/Paper"));
3887
+ var import_Paper7 = __toESM(require("@mui/material/Paper"));
3773
3888
  var import_Box11 = __toESM(require("@mui/material/Box"));
3774
3889
  var import_Typography11 = __toESM(require("@mui/material/Typography"));
3775
3890
  var import_FormControl2 = __toESM(require("@mui/material/FormControl"));
3776
3891
  var import_Select2 = __toESM(require("@mui/material/Select"));
3777
- var import_MenuItem5 = __toESM(require("@mui/material/MenuItem"));
3892
+ var import_MenuItem6 = __toESM(require("@mui/material/MenuItem"));
3778
3893
  var import_Grid2 = __toESM(require("@mui/material/Grid"));
3779
- var import_CircularProgress5 = __toESM(require("@mui/material/CircularProgress"));
3894
+ var import_CircularProgress6 = __toESM(require("@mui/material/CircularProgress"));
3780
3895
  var import_Alert6 = __toESM(require("@mui/material/Alert"));
3781
3896
  var import_recharts3 = require("recharts");
3782
- var import_core_plugin_api3 = require("@backstage/core-plugin-api");
3897
+ var import_core_plugin_api4 = require("@backstage/core-plugin-api");
3783
3898
  init_api();
3784
3899
  init_format();
3785
3900
  function presetToDateRange(preset) {
@@ -3799,7 +3914,7 @@ var LiteLLMHomeWidget = ({
3799
3914
  defaultPeriod = "7d",
3800
3915
  title = "LiteLLM Usage"
3801
3916
  }) => {
3802
- const api = (0, import_core_plugin_api3.useApi)(liteLlmApiRef);
3917
+ const api = (0, import_core_plugin_api4.useApi)(liteLlmApiRef);
3803
3918
  const [period, setPeriod] = (0, import_react12.useState)(defaultPeriod);
3804
3919
  const [loading, setLoading] = (0, import_react12.useState)(true);
3805
3920
  const [usageError, setUsageError] = (0, import_react12.useState)(null);
@@ -3843,17 +3958,17 @@ var LiteLLMHomeWidget = ({
3843
3958
  spend: d.spend
3844
3959
  }));
3845
3960
  const hasSparkline = dailyData.length > 0;
3846
- 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(
3961
+ 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(
3847
3962
  import_Select2.default,
3848
3963
  {
3849
3964
  value: period,
3850
3965
  onChange: (e) => setPeriod(e.target.value),
3851
3966
  displayEmpty: true
3852
3967
  },
3853
- /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "today" }, "Today"),
3854
- /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "7d" }, "7d"),
3855
- /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "30d" }, "30d")
3856
- ))), 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(
3968
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem6.default, { value: "today" }, "Today"),
3969
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem6.default, { value: "7d" }, "7d"),
3970
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem6.default, { value: "30d" }, "30d")
3971
+ ))), 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(
3857
3972
  import_recharts3.Area,
3858
3973
  {
3859
3974
  type: "monotone",