@acarmisc/backstage-plugin-litellm 0.26.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -836,16 +836,74 @@ var init_ui = __esm({
836
836
  }
837
837
  });
838
838
 
839
+ // src/components/GenerateKeyButton.tsx
840
+ import React2 from "react";
841
+ import Button from "@mui/material/Button";
842
+ import { Add } from "@mui/icons-material";
843
+ import { Link } from "@backstage/core-components";
844
+ var GenerateKeyButton;
845
+ var init_GenerateKeyButton = __esm({
846
+ "src/components/GenerateKeyButton.tsx"() {
847
+ "use strict";
848
+ GenerateKeyButton = ({
849
+ to,
850
+ onClick,
851
+ label = "Generate New Key",
852
+ size
853
+ }) => {
854
+ if (onClick) {
855
+ return /* @__PURE__ */ React2.createElement(
856
+ Button,
857
+ {
858
+ variant: "contained",
859
+ color: "primary",
860
+ disableElevation: true,
861
+ size,
862
+ startIcon: /* @__PURE__ */ React2.createElement(Add, null),
863
+ onClick
864
+ },
865
+ label
866
+ );
867
+ }
868
+ if (to) {
869
+ return /* @__PURE__ */ React2.createElement(
870
+ Button,
871
+ {
872
+ variant: "contained",
873
+ color: "primary",
874
+ disableElevation: true,
875
+ size,
876
+ startIcon: /* @__PURE__ */ React2.createElement(Add, null),
877
+ component: Link,
878
+ to
879
+ },
880
+ label
881
+ );
882
+ }
883
+ return /* @__PURE__ */ React2.createElement(
884
+ Button,
885
+ {
886
+ variant: "contained",
887
+ color: "primary",
888
+ disableElevation: true,
889
+ size,
890
+ startIcon: /* @__PURE__ */ React2.createElement(Add, null),
891
+ disabled: true
892
+ },
893
+ label
894
+ );
895
+ };
896
+ }
897
+ });
898
+
839
899
  // src/components/DashboardHeader.tsx
840
- import React2, { useMemo } from "react";
900
+ import React3, { useMemo } from "react";
841
901
  import Box2 from "@mui/material/Box";
842
902
  import Typography2 from "@mui/material/Typography";
843
903
  import Skeleton from "@mui/material/Skeleton";
844
904
  import Paper2 from "@mui/material/Paper";
845
- import Button from "@mui/material/Button";
846
905
  import Divider from "@mui/material/Divider";
847
906
  import { alpha as alpha2 } from "@mui/material/styles";
848
- import { Add } from "@mui/icons-material";
849
907
  function initials(name) {
850
908
  const local = name.split("@")[0] ?? name;
851
909
  const parts = local.split(/[.\-_\s]+/).filter(Boolean);
@@ -858,9 +916,10 @@ var init_DashboardHeader = __esm({
858
916
  "use strict";
859
917
  init_api();
860
918
  init_ui();
919
+ init_GenerateKeyButton();
861
920
  CountStat = ({ value, label, tone }) => {
862
921
  const active = value > 0;
863
- return /* @__PURE__ */ React2.createElement(Box2, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ React2.createElement(
922
+ return /* @__PURE__ */ React3.createElement(Box2, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ React3.createElement(
864
923
  Box2,
865
924
  {
866
925
  sx: (theme) => ({
@@ -871,14 +930,14 @@ var init_DashboardHeader = __esm({
871
930
  bgcolor: active ? tone === "danger" && theme.palette.error.main || tone === "warning" && theme.palette.warning.main || theme.palette.primary.main : alpha2(theme.palette.text.primary, 0.25)
872
931
  })
873
932
  }
874
- ), /* @__PURE__ */ React2.createElement(
933
+ ), /* @__PURE__ */ React3.createElement(
875
934
  Typography2,
876
935
  {
877
936
  component: "span",
878
937
  sx: { fontSize: 15, fontWeight: 700, lineHeight: 1, fontVariantNumeric: "tabular-nums" }
879
938
  },
880
939
  value
881
- ), /* @__PURE__ */ React2.createElement(
940
+ ), /* @__PURE__ */ React3.createElement(
882
941
  Typography2,
883
942
  {
884
943
  component: "span",
@@ -902,7 +961,7 @@ var init_DashboardHeader = __esm({
902
961
  return { total: keys.length, expired, expiringSoon };
903
962
  }, [keys]);
904
963
  const displayName = userInfo.user_email ?? userInfo.email ?? userInfo.user_id;
905
- return /* @__PURE__ */ React2.createElement(Paper2, { sx: { borderRadius: 2, overflow: "hidden" } }, /* @__PURE__ */ React2.createElement(
964
+ return /* @__PURE__ */ React3.createElement(Paper2, { sx: { borderRadius: 2, overflow: "hidden" } }, /* @__PURE__ */ React3.createElement(
906
965
  Box2,
907
966
  {
908
967
  sx: {
@@ -915,7 +974,7 @@ var init_DashboardHeader = __esm({
915
974
  pb: 2
916
975
  }
917
976
  },
918
- /* @__PURE__ */ React2.createElement(
977
+ /* @__PURE__ */ React3.createElement(
919
978
  Box2,
920
979
  {
921
980
  sx: (theme) => ({
@@ -935,7 +994,7 @@ var init_DashboardHeader = __esm({
935
994
  },
936
995
  initials(displayName)
937
996
  ),
938
- /* @__PURE__ */ React2.createElement(Box2, { sx: { flexGrow: 1, minWidth: 220 } }, /* @__PURE__ */ React2.createElement(Typography2, { variant: "h6", sx: { lineHeight: 1.25, wordBreak: "break-word" } }, displayName), /* @__PURE__ */ React2.createElement(
997
+ /* @__PURE__ */ React3.createElement(Box2, { sx: { flexGrow: 1, minWidth: 220 } }, /* @__PURE__ */ React3.createElement(Typography2, { variant: "h6", sx: { lineHeight: 1.25, wordBreak: "break-word" } }, displayName), /* @__PURE__ */ React3.createElement(
939
998
  Typography2,
940
999
  {
941
1000
  variant: "caption",
@@ -943,7 +1002,7 @@ var init_DashboardHeader = __esm({
943
1002
  sx: { display: "block", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
944
1003
  },
945
1004
  userInfo.user_id
946
- ), /* @__PURE__ */ React2.createElement(Box2, { sx: { display: "flex", gap: 0.75, flexWrap: "wrap", mt: 1, minHeight: 20 } }, loading ? /* @__PURE__ */ React2.createElement(Skeleton, { variant: "rounded", width: 140, height: 20 }) : teams.map((team) => /* @__PURE__ */ React2.createElement(
1005
+ ), /* @__PURE__ */ React3.createElement(Box2, { sx: { display: "flex", gap: 0.75, flexWrap: "wrap", mt: 1, minHeight: 20 } }, loading ? /* @__PURE__ */ React3.createElement(Skeleton, { variant: "rounded", width: 140, height: 20 }) : teams.map((team) => /* @__PURE__ */ React3.createElement(
947
1006
  TagChip,
948
1007
  {
949
1008
  key: team.team_id,
@@ -951,18 +1010,8 @@ var init_DashboardHeader = __esm({
951
1010
  title: team.team_id
952
1011
  }
953
1012
  )))),
954
- /* @__PURE__ */ React2.createElement(
955
- Button,
956
- {
957
- variant: "contained",
958
- color: "primary",
959
- disableElevation: true,
960
- startIcon: /* @__PURE__ */ React2.createElement(Add, null),
961
- onClick: onGenerateKeyClick
962
- },
963
- "Generate New Key"
964
- )
965
- ), /* @__PURE__ */ React2.createElement(Divider, null), /* @__PURE__ */ React2.createElement(
1013
+ /* @__PURE__ */ React3.createElement(GenerateKeyButton, { onClick: onGenerateKeyClick })
1014
+ ), /* @__PURE__ */ React3.createElement(Divider, null), /* @__PURE__ */ React3.createElement(
966
1015
  Box2,
967
1016
  {
968
1017
  sx: {
@@ -974,18 +1023,18 @@ var init_DashboardHeader = __esm({
974
1023
  py: 1.5
975
1024
  }
976
1025
  },
977
- /* @__PURE__ */ React2.createElement(CountStat, { value: counts.total, label: "keys", tone: "accent" }),
978
- /* @__PURE__ */ React2.createElement(Divider, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
979
- /* @__PURE__ */ React2.createElement(CountStat, { value: counts.expired, label: "expired", tone: "danger" }),
980
- /* @__PURE__ */ React2.createElement(Divider, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
981
- /* @__PURE__ */ React2.createElement(CountStat, { value: counts.expiringSoon, label: "expiring soon", tone: "warning" })
982
- ), tabs && /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Divider, null), /* @__PURE__ */ React2.createElement(Box2, { sx: { px: 1 } }, tabs)));
1026
+ /* @__PURE__ */ React3.createElement(CountStat, { value: counts.total, label: "keys", tone: "accent" }),
1027
+ /* @__PURE__ */ React3.createElement(Divider, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1028
+ /* @__PURE__ */ React3.createElement(CountStat, { value: counts.expired, label: "expired", tone: "danger" }),
1029
+ /* @__PURE__ */ React3.createElement(Divider, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1030
+ /* @__PURE__ */ React3.createElement(CountStat, { value: counts.expiringSoon, label: "expiring soon", tone: "warning" })
1031
+ ), tabs && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(Divider, null), /* @__PURE__ */ React3.createElement(Box2, { sx: { px: 1 } }, tabs)));
983
1032
  };
984
1033
  }
985
1034
  });
986
1035
 
987
1036
  // src/components/KeysTable.tsx
988
- import React3, { useState, useMemo as useMemo2 } from "react";
1037
+ import React4, { useState, useMemo as useMemo2 } from "react";
989
1038
  import Table from "@mui/material/Table";
990
1039
  import TableBody from "@mui/material/TableBody";
991
1040
  import TableCell from "@mui/material/TableCell";
@@ -1006,7 +1055,7 @@ import CircularProgress from "@mui/material/CircularProgress";
1006
1055
  import Skeleton2 from "@mui/material/Skeleton";
1007
1056
  import InputAdornment from "@mui/material/InputAdornment";
1008
1057
  import { alpha as alpha3 } from "@mui/material/styles";
1009
- import { ContentCopy, Delete, Add as Add2, Edit, Autorenew, Search, Lock, LockOpen } from "@mui/icons-material";
1058
+ import { ContentCopy, Delete, Edit, Autorenew, Search, Lock, LockOpen } from "@mui/icons-material";
1010
1059
  function expiryChipLabel(status, expiresAt) {
1011
1060
  if (status === "expired") return "Expired";
1012
1061
  if (status === "soon") return `${Math.ceil((new Date(expiresAt).getTime() - Date.now()) / 864e5)}d left`;
@@ -1020,12 +1069,12 @@ function expiryTone(status) {
1020
1069
  function ExpiryCell({ expiresAt }) {
1021
1070
  const status = expiryStatus(expiresAt);
1022
1071
  if (!status) {
1023
- return /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary" }, "Never");
1072
+ return /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, "Never");
1024
1073
  }
1025
1074
  if (status === "ok") {
1026
- return /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(expiresAt));
1075
+ return /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(expiresAt));
1027
1076
  }
1028
- return /* @__PURE__ */ React3.createElement(
1077
+ return /* @__PURE__ */ React4.createElement(
1029
1078
  StatusPill,
1030
1079
  {
1031
1080
  label: expiryChipLabel(status, expiresAt),
@@ -1040,16 +1089,16 @@ function budgetTone(pct) {
1040
1089
  return "accent";
1041
1090
  }
1042
1091
  function keyBlockIcon(isBlocking, blocked) {
1043
- if (isBlocking) return /* @__PURE__ */ React3.createElement(CircularProgress, { size: 18 });
1044
- if (blocked) return /* @__PURE__ */ React3.createElement(LockOpen, { fontSize: "small" });
1045
- return /* @__PURE__ */ React3.createElement(Lock, { fontSize: "small" });
1092
+ if (isBlocking) return /* @__PURE__ */ React4.createElement(CircularProgress, { size: 18 });
1093
+ if (blocked) return /* @__PURE__ */ React4.createElement(LockOpen, { fontSize: "small" });
1094
+ return /* @__PURE__ */ React4.createElement(Lock, { fontSize: "small" });
1046
1095
  }
1047
1096
  function BudgetCell({ spend, maxBudget }) {
1048
1097
  if (!maxBudget) {
1049
- return /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, "$", spend.toFixed(2), /* @__PURE__ */ React3.createElement(Typography3, { component: "span", variant: "caption", sx: { ml: 0.5, opacity: 0.7 } }, "/ \u221E"));
1098
+ return /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, "$", spend.toFixed(2), /* @__PURE__ */ React4.createElement(Typography3, { component: "span", variant: "caption", sx: { ml: 0.5, opacity: 0.7 } }, "/ \u221E"));
1050
1099
  }
1051
1100
  const pct = Math.min(100, spend / maxBudget * 100);
1052
- return /* @__PURE__ */ React3.createElement(Box3, { minWidth: 104 }, /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums", mb: 0.5 } }, "$", spend.toFixed(2), /* @__PURE__ */ React3.createElement(Typography3, { component: "span", variant: "caption", color: "text.secondary", sx: { ml: 0.5 } }, "/ $", maxBudget)), /* @__PURE__ */ React3.createElement(Meter, { value: pct, tone: budgetTone(pct), height: 4 }));
1101
+ return /* @__PURE__ */ React4.createElement(Box3, { minWidth: 104 }, /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums", mb: 0.5 } }, "$", spend.toFixed(2), /* @__PURE__ */ React4.createElement(Typography3, { component: "span", variant: "caption", color: "text.secondary", sx: { ml: 0.5 } }, "/ $", maxBudget)), /* @__PURE__ */ React4.createElement(Meter, { value: pct, tone: budgetTone(pct), height: 4 }));
1053
1102
  }
1054
1103
  function compareKeys(a, b, sortKey) {
1055
1104
  switch (sortKey) {
@@ -1074,6 +1123,7 @@ var init_KeysTable = __esm({
1074
1123
  "src/components/KeysTable.tsx"() {
1075
1124
  "use strict";
1076
1125
  init_api();
1126
+ init_GenerateKeyButton();
1077
1127
  init_ui();
1078
1128
  shortKeyId = (token) => {
1079
1129
  if (!token) return "-";
@@ -1172,32 +1222,27 @@ var init_KeysTable = __esm({
1172
1222
  };
1173
1223
  const renderTableBody = () => {
1174
1224
  if (loading) {
1175
- return /* @__PURE__ */ React3.createElement(TableRow, null, /* @__PURE__ */ React3.createElement(TableCell, { colSpan: 8, sx: { py: 2 } }, /* @__PURE__ */ React3.createElement(Skeleton2, { variant: "rounded", height: 140 })));
1225
+ return /* @__PURE__ */ React4.createElement(TableRow, null, /* @__PURE__ */ React4.createElement(TableCell, { colSpan: 8, sx: { py: 2 } }, /* @__PURE__ */ React4.createElement(Skeleton2, { variant: "rounded", height: 140 })));
1176
1226
  }
1177
1227
  if (filteredKeys.length === 0) {
1178
- return /* @__PURE__ */ React3.createElement(TableRow, null, /* @__PURE__ */ React3.createElement(TableCell, { colSpan: 8 }, filterText ? /* @__PURE__ */ React3.createElement(
1228
+ return /* @__PURE__ */ React4.createElement(TableRow, null, /* @__PURE__ */ React4.createElement(TableCell, { colSpan: 8 }, filterText ? /* @__PURE__ */ React4.createElement(
1179
1229
  EmptyState,
1180
1230
  {
1181
1231
  message: "No keys match that filter",
1182
1232
  hint: "Try a different alias or model name."
1183
1233
  }
1184
- ) : /* @__PURE__ */ React3.createElement(
1234
+ ) : /* @__PURE__ */ React4.createElement(
1185
1235
  EmptyState,
1186
1236
  {
1187
1237
  message: "No keys yet",
1188
1238
  hint: "Generate your first key to start calling models.",
1189
- action: /* @__PURE__ */ React3.createElement(
1190
- Button2,
1239
+ action: /* @__PURE__ */ React4.createElement(
1240
+ GenerateKeyButton,
1191
1241
  {
1192
- variant: "contained",
1193
- color: "primary",
1194
1242
  size: "small",
1195
- disableElevation: true,
1196
- startIcon: /* @__PURE__ */ React3.createElement(Add2, null),
1197
- onClick: onGenerateKeyClick,
1198
- sx: { mt: 1 }
1199
- },
1200
- "Generate Your First Key"
1243
+ label: "Generate Your First Key",
1244
+ onClick: onGenerateKeyClick
1245
+ }
1201
1246
  )
1202
1247
  }
1203
1248
  )));
@@ -1206,7 +1251,7 @@ var init_KeysTable = __esm({
1206
1251
  const keyId = key.token ?? key.key;
1207
1252
  const isBlocking = blockingKeyId === keyId;
1208
1253
  const keyModels = key.models ?? [];
1209
- return /* @__PURE__ */ React3.createElement(
1254
+ return /* @__PURE__ */ React4.createElement(
1210
1255
  TableRow,
1211
1256
  {
1212
1257
  key: keyId,
@@ -1217,8 +1262,8 @@ var init_KeysTable = __esm({
1217
1262
  "& td": { color: theme.palette.text.secondary }
1218
1263
  }) : void 0
1219
1264
  },
1220
- /* @__PURE__ */ React3.createElement(TableCell, null, /* @__PURE__ */ React3.createElement(Box3, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2" }, key.key_alias || "\u2014"), key.blocked && /* @__PURE__ */ React3.createElement(StatusPill, { label: "Blocked", tone: "danger" }))),
1221
- /* @__PURE__ */ React3.createElement(TableCell, null, /* @__PURE__ */ React3.createElement(Box3, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React3.createElement(
1265
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(Box3, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2" }, key.key_alias || "\u2014"), key.blocked && /* @__PURE__ */ React4.createElement(StatusPill, { label: "Blocked", tone: "danger" }))),
1266
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(Box3, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React4.createElement(
1222
1267
  Typography3,
1223
1268
  {
1224
1269
  variant: "body2",
@@ -1235,7 +1280,7 @@ var init_KeysTable = __esm({
1235
1280
  })
1236
1281
  },
1237
1282
  shortKeyId(keyId)
1238
- ), /* @__PURE__ */ React3.createElement(
1283
+ ), /* @__PURE__ */ React4.createElement(
1239
1284
  IconButton,
1240
1285
  {
1241
1286
  size: "small",
@@ -1243,13 +1288,13 @@ var init_KeysTable = __esm({
1243
1288
  title: "Copy Key ID",
1244
1289
  sx: quietIconButtonSx("accent")
1245
1290
  },
1246
- /* @__PURE__ */ React3.createElement(ContentCopy, { sx: { fontSize: 15 } })
1291
+ /* @__PURE__ */ React4.createElement(ContentCopy, { sx: { fontSize: 15 } })
1247
1292
  ))),
1248
- /* @__PURE__ */ React3.createElement(TableCell, null, /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(key.created_at))),
1249
- /* @__PURE__ */ React3.createElement(TableCell, null, /* @__PURE__ */ React3.createElement(ExpiryCell, { expiresAt: key.expires_at })),
1250
- /* @__PURE__ */ React3.createElement(TableCell, null, /* @__PURE__ */ React3.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })),
1251
- /* @__PURE__ */ React3.createElement(TableCell, null, /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, key.tpm_limit ?? "\u221E", " / ", key.rpm_limit ?? "\u221E")),
1252
- /* @__PURE__ */ React3.createElement(TableCell, null, keyModels.length === 0 ? /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary" }, "All models") : /* @__PURE__ */ React3.createElement(Box3, { display: "flex", gap: 0.5, flexWrap: "wrap" }, keyModels.slice(0, 2).map((model) => /* @__PURE__ */ React3.createElement(TagChip, { key: model, label: model, title: model })), keyModels.length > 2 && /* @__PURE__ */ React3.createElement(
1293
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(key.created_at))),
1294
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(ExpiryCell, { expiresAt: key.expires_at })),
1295
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })),
1296
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, key.tpm_limit ?? "\u221E", " / ", key.rpm_limit ?? "\u221E")),
1297
+ /* @__PURE__ */ React4.createElement(TableCell, null, keyModels.length === 0 ? /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, "All models") : /* @__PURE__ */ React4.createElement(Box3, { display: "flex", gap: 0.5, flexWrap: "wrap" }, keyModels.slice(0, 2).map((model) => /* @__PURE__ */ React4.createElement(TagChip, { key: model, label: model, title: model })), keyModels.length > 2 && /* @__PURE__ */ React4.createElement(
1253
1298
  TagChip,
1254
1299
  {
1255
1300
  label: `+${keyModels.length - 2}`,
@@ -1257,7 +1302,7 @@ var init_KeysTable = __esm({
1257
1302
  title: keyModels.slice(2).join(", ")
1258
1303
  }
1259
1304
  ))),
1260
- /* @__PURE__ */ React3.createElement(TableCell, { align: "right" }, /* @__PURE__ */ React3.createElement(Box3, { display: "flex", justifyContent: "flex-end", gap: 0.25 }, /* @__PURE__ */ React3.createElement(
1305
+ /* @__PURE__ */ React4.createElement(TableCell, { align: "right" }, /* @__PURE__ */ React4.createElement(Box3, { display: "flex", justifyContent: "flex-end", gap: 0.25 }, /* @__PURE__ */ React4.createElement(
1261
1306
  IconButton,
1262
1307
  {
1263
1308
  size: "small",
@@ -1265,8 +1310,8 @@ var init_KeysTable = __esm({
1265
1310
  title: "Edit key",
1266
1311
  sx: quietIconButtonSx("accent")
1267
1312
  },
1268
- /* @__PURE__ */ React3.createElement(Edit, { fontSize: "small" })
1269
- ), /* @__PURE__ */ React3.createElement(
1313
+ /* @__PURE__ */ React4.createElement(Edit, { fontSize: "small" })
1314
+ ), /* @__PURE__ */ React4.createElement(
1270
1315
  IconButton,
1271
1316
  {
1272
1317
  size: "small",
@@ -1276,7 +1321,7 @@ var init_KeysTable = __esm({
1276
1321
  sx: quietIconButtonSx("warning")
1277
1322
  },
1278
1323
  keyBlockIcon(isBlocking, key.blocked)
1279
- ), /* @__PURE__ */ React3.createElement(
1324
+ ), /* @__PURE__ */ React4.createElement(
1280
1325
  IconButton,
1281
1326
  {
1282
1327
  size: "small",
@@ -1284,18 +1329,18 @@ var init_KeysTable = __esm({
1284
1329
  title: "Revoke key",
1285
1330
  sx: quietIconButtonSx("danger")
1286
1331
  },
1287
- /* @__PURE__ */ React3.createElement(Delete, { fontSize: "small" })
1332
+ /* @__PURE__ */ React4.createElement(Delete, { fontSize: "small" })
1288
1333
  )))
1289
1334
  );
1290
1335
  });
1291
1336
  };
1292
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
1337
+ return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
1293
1338
  SectionCard,
1294
1339
  {
1295
1340
  title: "Virtual Keys",
1296
1341
  subtitle: loading ? "Loading\u2026" : `${filteredKeys.length}${filterText ? ` of ${keys.length}` : ""} key${filteredKeys.length === 1 ? "" : "s"}`,
1297
1342
  flush: true,
1298
- actions: /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
1343
+ actions: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
1299
1344
  TextField,
1300
1345
  {
1301
1346
  size: "small",
@@ -1305,15 +1350,15 @@ var init_KeysTable = __esm({
1305
1350
  onChange: (e) => setFilterText(e.target.value),
1306
1351
  sx: { minWidth: 240 },
1307
1352
  InputProps: {
1308
- startAdornment: /* @__PURE__ */ React3.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React3.createElement(Search, { fontSize: "small", color: "disabled" }))
1353
+ startAdornment: /* @__PURE__ */ React4.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React4.createElement(Search, { fontSize: "small", color: "disabled" }))
1309
1354
  }
1310
1355
  }
1311
- ), expiredKeys.length > 0 && /* @__PURE__ */ React3.createElement(
1356
+ ), expiredKeys.length > 0 && /* @__PURE__ */ React4.createElement(
1312
1357
  Button2,
1313
1358
  {
1314
1359
  variant: "outlined",
1315
1360
  color: "inherit",
1316
- startIcon: /* @__PURE__ */ React3.createElement(Autorenew, null),
1361
+ startIcon: /* @__PURE__ */ React4.createElement(Autorenew, null),
1317
1362
  onClick: () => setPruneConfirmCount(expiredKeys.length),
1318
1363
  sx: (theme) => ({
1319
1364
  color: theme.palette.text.secondary,
@@ -1328,20 +1373,10 @@ var init_KeysTable = __esm({
1328
1373
  "Prune expired (",
1329
1374
  expiredKeys.length,
1330
1375
  ")"
1331
- ), /* @__PURE__ */ React3.createElement(
1332
- Button2,
1333
- {
1334
- variant: "contained",
1335
- color: "primary",
1336
- disableElevation: true,
1337
- startIcon: /* @__PURE__ */ React3.createElement(Add2, null),
1338
- onClick: onGenerateKeyClick
1339
- },
1340
- "Generate New Key"
1341
- ))
1376
+ ), /* @__PURE__ */ React4.createElement(GenerateKeyButton, { onClick: onGenerateKeyClick }))
1342
1377
  },
1343
- /* @__PURE__ */ React3.createElement(TableContainer, null, /* @__PURE__ */ React3.createElement(Table, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React3.createElement(TableHead, null, /* @__PURE__ */ React3.createElement(TableRow, null, /* @__PURE__ */ React3.createElement(TableCell, { sortDirection: sortKey === "alias" ? sortDirection : false }, /* @__PURE__ */ React3.createElement(TableSortLabel, { active: sortKey === "alias", direction: sortKey === "alias" ? sortDirection : "asc", onClick: () => handleSort("alias") }, "Alias")), /* @__PURE__ */ React3.createElement(TableCell, null, "Key ID"), /* @__PURE__ */ React3.createElement(TableCell, { sortDirection: sortKey === "created" ? sortDirection : false }, /* @__PURE__ */ React3.createElement(TableSortLabel, { active: sortKey === "created", direction: sortKey === "created" ? sortDirection : "asc", onClick: () => handleSort("created") }, "Created")), /* @__PURE__ */ React3.createElement(TableCell, { sortDirection: sortKey === "expires" ? sortDirection : false }, /* @__PURE__ */ React3.createElement(TableSortLabel, { active: sortKey === "expires", direction: sortKey === "expires" ? sortDirection : "asc", onClick: () => handleSort("expires") }, "Expires")), /* @__PURE__ */ React3.createElement(TableCell, { sortDirection: sortKey === "budget" ? sortDirection : false }, /* @__PURE__ */ React3.createElement(TableSortLabel, { active: sortKey === "budget", direction: sortKey === "budget" ? sortDirection : "asc", onClick: () => handleSort("budget") }, "Budget")), /* @__PURE__ */ React3.createElement(TableCell, { sortDirection: sortKey === "limits" ? sortDirection : false }, /* @__PURE__ */ React3.createElement(TableSortLabel, { active: sortKey === "limits", direction: sortKey === "limits" ? sortDirection : "asc", onClick: () => handleSort("limits") }, "TPM / RPM")), /* @__PURE__ */ React3.createElement(TableCell, { sortDirection: sortKey === "models" ? sortDirection : false }, /* @__PURE__ */ React3.createElement(TableSortLabel, { active: sortKey === "models", direction: sortKey === "models" ? sortDirection : "asc", onClick: () => handleSort("models") }, "Models")), /* @__PURE__ */ React3.createElement(TableCell, { align: "right" }, "Actions"))), /* @__PURE__ */ React3.createElement(TableBody, null, renderTableBody())))
1344
- ), /* @__PURE__ */ React3.createElement(Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React3.createElement(DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ React3.createElement(DialogContent, null, /* @__PURE__ */ React3.createElement(Typography3, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ React3.createElement(DialogActions, null, /* @__PURE__ */ React3.createElement(Button2, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ React3.createElement(
1378
+ /* @__PURE__ */ React4.createElement(TableContainer, null, /* @__PURE__ */ React4.createElement(Table, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React4.createElement(TableHead, null, /* @__PURE__ */ React4.createElement(TableRow, null, /* @__PURE__ */ React4.createElement(TableCell, { sortDirection: sortKey === "alias" ? sortDirection : false }, /* @__PURE__ */ React4.createElement(TableSortLabel, { active: sortKey === "alias", direction: sortKey === "alias" ? sortDirection : "asc", onClick: () => handleSort("alias") }, "Alias")), /* @__PURE__ */ React4.createElement(TableCell, null, "Key ID"), /* @__PURE__ */ React4.createElement(TableCell, { sortDirection: sortKey === "created" ? sortDirection : false }, /* @__PURE__ */ React4.createElement(TableSortLabel, { active: sortKey === "created", direction: sortKey === "created" ? sortDirection : "asc", onClick: () => handleSort("created") }, "Created")), /* @__PURE__ */ React4.createElement(TableCell, { sortDirection: sortKey === "expires" ? sortDirection : false }, /* @__PURE__ */ React4.createElement(TableSortLabel, { active: sortKey === "expires", direction: sortKey === "expires" ? sortDirection : "asc", onClick: () => handleSort("expires") }, "Expires")), /* @__PURE__ */ React4.createElement(TableCell, { sortDirection: sortKey === "budget" ? sortDirection : false }, /* @__PURE__ */ React4.createElement(TableSortLabel, { active: sortKey === "budget", direction: sortKey === "budget" ? sortDirection : "asc", onClick: () => handleSort("budget") }, "Budget")), /* @__PURE__ */ React4.createElement(TableCell, { sortDirection: sortKey === "limits" ? sortDirection : false }, /* @__PURE__ */ React4.createElement(TableSortLabel, { active: sortKey === "limits", direction: sortKey === "limits" ? sortDirection : "asc", onClick: () => handleSort("limits") }, "TPM / RPM")), /* @__PURE__ */ React4.createElement(TableCell, { sortDirection: sortKey === "models" ? sortDirection : false }, /* @__PURE__ */ React4.createElement(TableSortLabel, { active: sortKey === "models", direction: sortKey === "models" ? sortDirection : "asc", onClick: () => handleSort("models") }, "Models")), /* @__PURE__ */ React4.createElement(TableCell, { align: "right" }, "Actions"))), /* @__PURE__ */ React4.createElement(TableBody, null, renderTableBody())))
1379
+ ), /* @__PURE__ */ React4.createElement(Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React4.createElement(DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ React4.createElement(DialogContent, null, /* @__PURE__ */ React4.createElement(Typography3, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ React4.createElement(DialogActions, null, /* @__PURE__ */ React4.createElement(Button2, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ React4.createElement(
1345
1380
  Button2,
1346
1381
  {
1347
1382
  onClick: handleConfirmDelete,
@@ -1349,8 +1384,8 @@ var init_KeysTable = __esm({
1349
1384
  color: "error",
1350
1385
  disabled: deleteSubmitting
1351
1386
  },
1352
- deleteSubmitting ? /* @__PURE__ */ React3.createElement(CircularProgress, { size: 20 }) : "Revoke"
1353
- ))), /* @__PURE__ */ React3.createElement(Dialog, { open: pruneConfirmCount !== null, onClose: () => setPruneConfirmCount(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React3.createElement(DialogTitle, null, "Prune Expired Keys?"), /* @__PURE__ */ React3.createElement(DialogContent, null, /* @__PURE__ */ React3.createElement(Typography3, null, "This will permanently delete ", pruneConfirmCount, " expired key", pruneConfirmCount !== 1 ? "s" : "", " from LiteLLM. Any integrations using them will stop working immediately.")), /* @__PURE__ */ React3.createElement(DialogActions, null, /* @__PURE__ */ React3.createElement(Button2, { onClick: () => setPruneConfirmCount(null), disabled: pruneSubmitting }, "Cancel"), /* @__PURE__ */ React3.createElement(
1387
+ deleteSubmitting ? /* @__PURE__ */ React4.createElement(CircularProgress, { size: 20 }) : "Revoke"
1388
+ ))), /* @__PURE__ */ React4.createElement(Dialog, { open: pruneConfirmCount !== null, onClose: () => setPruneConfirmCount(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React4.createElement(DialogTitle, null, "Prune Expired Keys?"), /* @__PURE__ */ React4.createElement(DialogContent, null, /* @__PURE__ */ React4.createElement(Typography3, null, "This will permanently delete ", pruneConfirmCount, " expired key", pruneConfirmCount !== 1 ? "s" : "", " from LiteLLM. Any integrations using them will stop working immediately.")), /* @__PURE__ */ React4.createElement(DialogActions, null, /* @__PURE__ */ React4.createElement(Button2, { onClick: () => setPruneConfirmCount(null), disabled: pruneSubmitting }, "Cancel"), /* @__PURE__ */ React4.createElement(
1354
1389
  Button2,
1355
1390
  {
1356
1391
  onClick: handlePruneExpired,
@@ -1358,7 +1393,7 @@ var init_KeysTable = __esm({
1358
1393
  color: "error",
1359
1394
  disabled: pruneSubmitting
1360
1395
  },
1361
- pruneSubmitting ? /* @__PURE__ */ React3.createElement(CircularProgress, { size: 20 }) : "Prune"
1396
+ pruneSubmitting ? /* @__PURE__ */ React4.createElement(CircularProgress, { size: 20 }) : "Prune"
1362
1397
  ))));
1363
1398
  };
1364
1399
  }
@@ -1379,7 +1414,7 @@ var init_format = __esm({
1379
1414
  });
1380
1415
 
1381
1416
  // src/components/KeyFormDialog.tsx
1382
- import React4, { useState as useState2, useEffect, useMemo as useMemo3 } from "react";
1417
+ import React5, { useState as useState2, useEffect, useMemo as useMemo3 } from "react";
1383
1418
  import Box4 from "@mui/material/Box";
1384
1419
  import Typography4 from "@mui/material/Typography";
1385
1420
  import Dialog2 from "@mui/material/Dialog";
@@ -1556,14 +1591,14 @@ var init_KeyFormDialog = __esm({
1556
1591
  const snippetKey = tab === "claude-code" ? "claudeCode" : tab;
1557
1592
  const code = snippets[snippetKey];
1558
1593
  const fileHint = SNIPPET_FILE_HINTS[tab];
1559
- return /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Tabs, { value: tab, onChange: (_, v) => setTab(v), sx: { mb: 1 }, variant: "scrollable" }, /* @__PURE__ */ React4.createElement(Tab, { label: "curl", value: "curl" }), /* @__PURE__ */ React4.createElement(Tab, { label: "OpenAI SDK", value: "openai" }), /* @__PURE__ */ React4.createElement(Tab, { label: "opencode", value: "opencode" }), /* @__PURE__ */ React4.createElement(Tab, { label: "pi", value: "pi" }), /* @__PURE__ */ React4.createElement(Tab, { label: "Claude Code", value: "claude-code" })), fileHint && /* @__PURE__ */ React4.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", mb: 0.5 }, fileHint), /* @__PURE__ */ React4.createElement(
1594
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Tabs, { value: tab, onChange: (_, v) => setTab(v), sx: { mb: 1 }, variant: "scrollable" }, /* @__PURE__ */ React5.createElement(Tab, { label: "curl", value: "curl" }), /* @__PURE__ */ React5.createElement(Tab, { label: "OpenAI SDK", value: "openai" }), /* @__PURE__ */ React5.createElement(Tab, { label: "opencode", value: "opencode" }), /* @__PURE__ */ React5.createElement(Tab, { label: "pi", value: "pi" }), /* @__PURE__ */ React5.createElement(Tab, { label: "Claude Code", value: "claude-code" })), fileHint && /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", mb: 0.5 }, fileHint), /* @__PURE__ */ React5.createElement(
1560
1595
  Box4,
1561
1596
  {
1562
1597
  position: "relative",
1563
1598
  p: 1.5,
1564
1599
  sx: { backgroundColor: "action.hover", border: "1px solid", borderColor: "divider", borderRadius: 1 }
1565
1600
  },
1566
- /* @__PURE__ */ React4.createElement(
1601
+ /* @__PURE__ */ React5.createElement(
1567
1602
  IconButton2,
1568
1603
  {
1569
1604
  size: "small",
@@ -1571,9 +1606,9 @@ var init_KeyFormDialog = __esm({
1571
1606
  title: "Copy snippet",
1572
1607
  sx: { position: "absolute", top: 4, right: 4 }
1573
1608
  },
1574
- /* @__PURE__ */ React4.createElement(ContentCopy2, { fontSize: "small" })
1609
+ /* @__PURE__ */ React5.createElement(ContentCopy2, { fontSize: "small" })
1575
1610
  ),
1576
- /* @__PURE__ */ React4.createElement(
1611
+ /* @__PURE__ */ React5.createElement(
1577
1612
  Typography4,
1578
1613
  {
1579
1614
  component: "pre",
@@ -1588,7 +1623,7 @@ var init_KeyFormDialog = __esm({
1588
1623
  },
1589
1624
  code
1590
1625
  ),
1591
- model && /* @__PURE__ */ React4.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", mt: 1 }, "Using model \u201C", model, "\u201D \u2014 swap it for any model you have access to.")
1626
+ model && /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", mt: 1 }, "Using model \u201C", model, "\u201D \u2014 swap it for any model you have access to.")
1592
1627
  ));
1593
1628
  };
1594
1629
  KeyFormDialog = ({
@@ -1743,11 +1778,11 @@ var init_KeyFormDialog = __esm({
1743
1778
  const inCost = fmtCost(m.input_cost_per_token);
1744
1779
  const outCost = fmtCost(m.output_cost_per_token);
1745
1780
  const ctx = formatContextWindow(m.max_input_tokens, m.max_output_tokens);
1746
- return /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement("span", null, m.model_name), m.supports_function_calling && " \u{1F527}", m.supports_vision && " \u{1F441}\uFE0F", ctx && /* @__PURE__ */ React4.createElement(Typography4, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, ctx), (inCost || outCost) && /* @__PURE__ */ React4.createElement(Typography4, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, inCost, " in \xB7 ", outCost, " out"));
1781
+ return /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement("span", null, m.model_name), m.supports_function_calling && " \u{1F527}", m.supports_vision && " \u{1F441}\uFE0F", ctx && /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, ctx), (inCost || outCost) && /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, inCost, " in \xB7 ", outCost, " out"));
1747
1782
  };
1748
1783
  const renderTeamField = () => {
1749
1784
  if (teams.length > 0) {
1750
- return /* @__PURE__ */ React4.createElement(
1785
+ return /* @__PURE__ */ React5.createElement(
1751
1786
  Autocomplete,
1752
1787
  {
1753
1788
  options: teams,
@@ -1761,7 +1796,7 @@ var init_KeyFormDialog = __esm({
1761
1796
  setFormData({ team_id: team?.team_id, models: restrictedModels });
1762
1797
  },
1763
1798
  disabled: !isCreate,
1764
- renderInput: (params) => /* @__PURE__ */ React4.createElement(
1799
+ renderInput: (params) => /* @__PURE__ */ React5.createElement(
1765
1800
  TextField2,
1766
1801
  {
1767
1802
  ...params,
@@ -1776,14 +1811,14 @@ var init_KeyFormDialog = __esm({
1776
1811
  );
1777
1812
  }
1778
1813
  if (teamRequired && isCreate) {
1779
- return /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", color: "error" }, "Team selection is required, but you don't belong to any team yet \u2014 contact your administrator.");
1814
+ return /* @__PURE__ */ React5.createElement(Typography4, { variant: "body2", color: "error" }, "Team selection is required, but you don't belong to any team yet \u2014 contact your administrator.");
1780
1815
  }
1781
1816
  return null;
1782
1817
  };
1783
1818
  const editKeyId = keyToEdit?.token ?? keyToEdit?.key ?? "";
1784
1819
  const renderDangerZone = () => {
1785
1820
  if (isCreate || !onResetKeySpend) return null;
1786
- return /* @__PURE__ */ React4.createElement(Box4, { mt: 1, pt: 2, borderTop: "1px solid", sx: { borderColor: "divider" } }, /* @__PURE__ */ React4.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", mb: 1 }, "Danger Zone"), !resetSpendConfirm ? /* @__PURE__ */ React4.createElement(
1821
+ return /* @__PURE__ */ React5.createElement(Box4, { mt: 1, pt: 2, borderTop: "1px solid", sx: { borderColor: "divider" } }, /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", mb: 1 }, "Danger Zone"), !resetSpendConfirm ? /* @__PURE__ */ React5.createElement(
1787
1822
  Button3,
1788
1823
  {
1789
1824
  size: "small",
@@ -1792,7 +1827,7 @@ var init_KeyFormDialog = __esm({
1792
1827
  onClick: () => setResetSpendConfirm(true)
1793
1828
  },
1794
1829
  "Reset Spend to $0"
1795
- ) : /* @__PURE__ */ React4.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", color: "warning.main" }, "Zero out spend counter?"), /* @__PURE__ */ React4.createElement(
1830
+ ) : /* @__PURE__ */ React5.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ React5.createElement(Typography4, { variant: "body2", color: "warning.main" }, "Zero out spend counter?"), /* @__PURE__ */ React5.createElement(
1796
1831
  Button3,
1797
1832
  {
1798
1833
  size: "small",
@@ -1801,8 +1836,8 @@ var init_KeyFormDialog = __esm({
1801
1836
  disabled: resetSpendSubmitting,
1802
1837
  onClick: handleResetSpend
1803
1838
  },
1804
- resetSpendSubmitting ? /* @__PURE__ */ React4.createElement(CircularProgress2, { size: 16 }) : "Confirm"
1805
- ), /* @__PURE__ */ React4.createElement(Button3, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel")));
1839
+ resetSpendSubmitting ? /* @__PURE__ */ React5.createElement(CircularProgress2, { size: 16 }) : "Confirm"
1840
+ ), /* @__PURE__ */ React5.createElement(Button3, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel")));
1806
1841
  };
1807
1842
  const maskKey = (key) => {
1808
1843
  if (key.length <= 8) return "***";
@@ -1812,7 +1847,7 @@ var init_KeyFormDialog = __esm({
1812
1847
  if (newKeyValue) dialogTitle = "Key Generated";
1813
1848
  else if (isCreate) dialogTitle = "Generate New Key";
1814
1849
  const submitLabel = isCreate ? "Generate" : "Save";
1815
- return /* @__PURE__ */ React4.createElement(Dialog2, { open, onClose: handleClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React4.createElement(DialogTitle2, null, dialogTitle), /* @__PURE__ */ React4.createElement(DialogContent2, null, newKeyValue ? /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", color: "text.secondary", gutterBottom: true }, "Copy this key now. You won't be able to see it again."), /* @__PURE__ */ React4.createElement(
1850
+ return /* @__PURE__ */ React5.createElement(Dialog2, { open, onClose: handleClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React5.createElement(DialogTitle2, null, dialogTitle), /* @__PURE__ */ React5.createElement(DialogContent2, null, newKeyValue ? /* @__PURE__ */ React5.createElement(Box4, null, /* @__PURE__ */ React5.createElement(Typography4, { variant: "body2", color: "text.secondary", gutterBottom: true }, "Copy this key now. You won't be able to see it again."), /* @__PURE__ */ React5.createElement(
1816
1851
  Box4,
1817
1852
  {
1818
1853
  display: "flex",
@@ -1827,7 +1862,7 @@ var init_KeyFormDialog = __esm({
1827
1862
  borderRadius: 1
1828
1863
  }
1829
1864
  },
1830
- /* @__PURE__ */ React4.createElement(
1865
+ /* @__PURE__ */ React5.createElement(
1831
1866
  Typography4,
1832
1867
  {
1833
1868
  component: "code",
@@ -1836,8 +1871,8 @@ var init_KeyFormDialog = __esm({
1836
1871
  },
1837
1872
  newKeyValue
1838
1873
  ),
1839
- /* @__PURE__ */ React4.createElement(IconButton2, { onClick: () => copyToClipboard(newKeyValue) }, /* @__PURE__ */ React4.createElement(ContentCopy2, null))
1840
- ), newKeySnippets && /* @__PURE__ */ React4.createElement(Box4, { mt: 2 }, /* @__PURE__ */ React4.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "Public endpoint \u2014 paste into any tool's base URL / API base field"), /* @__PURE__ */ React4.createElement(
1874
+ /* @__PURE__ */ React5.createElement(IconButton2, { onClick: () => copyToClipboard(newKeyValue) }, /* @__PURE__ */ React5.createElement(ContentCopy2, null))
1875
+ ), newKeySnippets && /* @__PURE__ */ React5.createElement(Box4, { mt: 2 }, /* @__PURE__ */ React5.createElement(Typography4, { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "Public endpoint \u2014 paste into any tool's base URL / API base field"), /* @__PURE__ */ React5.createElement(
1841
1876
  Box4,
1842
1877
  {
1843
1878
  display: "flex",
@@ -1851,7 +1886,7 @@ var init_KeyFormDialog = __esm({
1851
1886
  borderRadius: 1
1852
1887
  }
1853
1888
  },
1854
- /* @__PURE__ */ React4.createElement(
1889
+ /* @__PURE__ */ React5.createElement(
1855
1890
  Typography4,
1856
1891
  {
1857
1892
  component: "code",
@@ -1860,8 +1895,8 @@ var init_KeyFormDialog = __esm({
1860
1895
  },
1861
1896
  newKeySnippets.publicEndpoint
1862
1897
  ),
1863
- /* @__PURE__ */ React4.createElement(IconButton2, { size: "small", onClick: () => copyToClipboard(newKeySnippets.publicEndpoint) }, /* @__PURE__ */ React4.createElement(ContentCopy2, { fontSize: "small" }))
1864
- )), newKeySnippets && /* @__PURE__ */ React4.createElement(Box4, { mt: 3 }, /* @__PURE__ */ React4.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ React4.createElement(Code, { fontSize: "small", color: "action" }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2" }, "Start calling the proxy \u2014 paste and run")), /* @__PURE__ */ React4.createElement(SnippetTabs, { snippets: newKeySnippets, model: newKeyModel, onCopy: copyToClipboard }))) : /* @__PURE__ */ React4.createElement(Box4, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, !isCreate && /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ React4.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editKeyId))), generateError && /* @__PURE__ */ React4.createElement(Alert, { severity: "error", onClose: () => setGenerateError(null) }, generateError), editError && /* @__PURE__ */ React4.createElement(Alert, { severity: "error", onClose: () => setEditError(null) }, editError), /* @__PURE__ */ React4.createElement(
1898
+ /* @__PURE__ */ React5.createElement(IconButton2, { size: "small", onClick: () => copyToClipboard(newKeySnippets.publicEndpoint) }, /* @__PURE__ */ React5.createElement(ContentCopy2, { fontSize: "small" }))
1899
+ )), newKeySnippets && /* @__PURE__ */ React5.createElement(Box4, { mt: 3 }, /* @__PURE__ */ React5.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ React5.createElement(Code, { fontSize: "small", color: "action" }), /* @__PURE__ */ React5.createElement(Typography4, { variant: "subtitle2" }, "Start calling the proxy \u2014 paste and run")), /* @__PURE__ */ React5.createElement(SnippetTabs, { snippets: newKeySnippets, model: newKeyModel, onCopy: copyToClipboard }))) : /* @__PURE__ */ React5.createElement(Box4, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, !isCreate && /* @__PURE__ */ React5.createElement(Typography4, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ React5.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editKeyId))), generateError && /* @__PURE__ */ React5.createElement(Alert, { severity: "error", onClose: () => setGenerateError(null) }, generateError), editError && /* @__PURE__ */ React5.createElement(Alert, { severity: "error", onClose: () => setEditError(null) }, editError), /* @__PURE__ */ React5.createElement(
1865
1900
  TextField2,
1866
1901
  {
1867
1902
  label: "Alias",
@@ -1877,7 +1912,7 @@ var init_KeyFormDialog = __esm({
1877
1912
  required: true,
1878
1913
  fullWidth: true
1879
1914
  }
1880
- ), !isCreate ? null : /* @__PURE__ */ React4.createElement(
1915
+ ), !isCreate ? null : /* @__PURE__ */ React5.createElement(
1881
1916
  TextField2,
1882
1917
  {
1883
1918
  select: true,
@@ -1886,12 +1921,12 @@ var init_KeyFormDialog = __esm({
1886
1921
  onChange: (e) => setFormData({ duration: e.target.value }),
1887
1922
  fullWidth: true
1888
1923
  },
1889
- /* @__PURE__ */ React4.createElement(MenuItem, { value: "1d" }, "1 Day"),
1890
- /* @__PURE__ */ React4.createElement(MenuItem, { value: "7d" }, "7 Days"),
1891
- /* @__PURE__ */ React4.createElement(MenuItem, { value: "30d" }, "30 Days"),
1892
- /* @__PURE__ */ React4.createElement(MenuItem, { value: "90d" }, "90 Days"),
1893
- /* @__PURE__ */ React4.createElement(MenuItem, { value: "1y" }, "1 Year")
1894
- ), renderTeamField(), availableModels.length > 0 && /* @__PURE__ */ React4.createElement(
1924
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "1d" }, "1 Day"),
1925
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "7d" }, "7 Days"),
1926
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "30d" }, "30 Days"),
1927
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "90d" }, "90 Days"),
1928
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "1y" }, "1 Year")
1929
+ ), renderTeamField(), availableModels.length > 0 && /* @__PURE__ */ React5.createElement(
1895
1930
  Autocomplete,
1896
1931
  {
1897
1932
  multiple: true,
@@ -1900,8 +1935,8 @@ var init_KeyFormDialog = __esm({
1900
1935
  getOptionLabel: (m) => m.model_name,
1901
1936
  value: selectedModels,
1902
1937
  onChange: (_e, selected) => setFormData({ models: selected.map((m) => m.model_name) }),
1903
- renderOption: (props, m) => /* @__PURE__ */ React4.createElement("li", { ...props }, modelOption(m)),
1904
- renderInput: (params) => /* @__PURE__ */ React4.createElement(
1938
+ renderOption: (props, m) => /* @__PURE__ */ React5.createElement("li", { ...props }, modelOption(m)),
1939
+ renderInput: (params) => /* @__PURE__ */ React5.createElement(
1905
1940
  TextField2,
1906
1941
  {
1907
1942
  ...params,
@@ -1911,10 +1946,10 @@ var init_KeyFormDialog = __esm({
1911
1946
  }
1912
1947
  )
1913
1948
  }
1914
- ), allowUnlimitedBudget && /* @__PURE__ */ React4.createElement(
1949
+ ), allowUnlimitedBudget && /* @__PURE__ */ React5.createElement(
1915
1950
  FormControlLabel,
1916
1951
  {
1917
- control: /* @__PURE__ */ React4.createElement(
1952
+ control: /* @__PURE__ */ React5.createElement(
1918
1953
  Checkbox,
1919
1954
  {
1920
1955
  checked: unlimitedBudget,
@@ -1930,7 +1965,7 @@ var init_KeyFormDialog = __esm({
1930
1965
  ),
1931
1966
  label: "Unlimited budget"
1932
1967
  }
1933
- ), /* @__PURE__ */ React4.createElement(
1968
+ ), /* @__PURE__ */ React5.createElement(
1934
1969
  TextField2,
1935
1970
  {
1936
1971
  label: "Max Budget (USD)",
@@ -1943,7 +1978,7 @@ var init_KeyFormDialog = __esm({
1943
1978
  required: true,
1944
1979
  fullWidth: true
1945
1980
  }
1946
- ), /* @__PURE__ */ React4.createElement(Accordion, { disableGutters: true, elevation: 0, sx: { border: "1px solid", borderColor: "divider", "&:before": { display: "none" } } }, /* @__PURE__ */ React4.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React4.createElement(ExpandMore, null) }, /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", fontWeight: 600 }, "Advanced")), /* @__PURE__ */ React4.createElement(AccordionDetails, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React4.createElement(
1981
+ ), /* @__PURE__ */ React5.createElement(Accordion, { disableGutters: true, elevation: 0, sx: { border: "1px solid", borderColor: "divider", "&:before": { display: "none" } } }, /* @__PURE__ */ React5.createElement(AccordionSummary, { expandIcon: /* @__PURE__ */ React5.createElement(ExpandMore, null) }, /* @__PURE__ */ React5.createElement(Typography4, { variant: "body2", fontWeight: 600 }, "Advanced")), /* @__PURE__ */ React5.createElement(AccordionDetails, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React5.createElement(
1947
1982
  TextField2,
1948
1983
  {
1949
1984
  label: "TPM Limit",
@@ -1953,7 +1988,7 @@ var init_KeyFormDialog = __esm({
1953
1988
  helperText: "Max tokens per minute this key can consume across all models. Leave blank for no limit.",
1954
1989
  fullWidth: true
1955
1990
  }
1956
- ), /* @__PURE__ */ React4.createElement(
1991
+ ), /* @__PURE__ */ React5.createElement(
1957
1992
  TextField2,
1958
1993
  {
1959
1994
  label: "RPM Limit",
@@ -1963,7 +1998,7 @@ var init_KeyFormDialog = __esm({
1963
1998
  helperText: "Max requests per minute this key can make across all models. Leave blank for no limit.",
1964
1999
  fullWidth: true
1965
2000
  }
1966
- ))), renderDangerZone())), /* @__PURE__ */ React4.createElement(DialogActions2, null, newKeyValue ? /* @__PURE__ */ React4.createElement(Button3, { onClick: handleClose, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(Button3, { onClick: handleClose }, "Cancel"), /* @__PURE__ */ React4.createElement(
2001
+ ))), renderDangerZone())), /* @__PURE__ */ React5.createElement(DialogActions2, null, newKeyValue ? /* @__PURE__ */ React5.createElement(Button3, { onClick: handleClose, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Button3, { onClick: handleClose }, "Cancel"), /* @__PURE__ */ React5.createElement(
1967
2002
  Button3,
1968
2003
  {
1969
2004
  onClick: isCreate ? handleGenerate : handleUpdate,
@@ -1971,14 +2006,14 @@ var init_KeyFormDialog = __esm({
1971
2006
  color: "primary",
1972
2007
  disabled: !canSubmit
1973
2008
  },
1974
- submitting ? /* @__PURE__ */ React4.createElement(CircularProgress2, { size: 24 }) : submitLabel
2009
+ submitting ? /* @__PURE__ */ React5.createElement(CircularProgress2, { size: 24 }) : submitLabel
1975
2010
  ))));
1976
2011
  };
1977
2012
  }
1978
2013
  });
1979
2014
 
1980
2015
  // src/components/ManageTeamDialog.tsx
1981
- import React5, { useState as useState3, useEffect as useEffect2, useMemo as useMemo4 } from "react";
2016
+ import React6, { useState as useState3, useEffect as useEffect2, useMemo as useMemo4 } from "react";
1982
2017
  import Dialog3 from "@mui/material/Dialog";
1983
2018
  import DialogTitle3 from "@mui/material/DialogTitle";
1984
2019
  import DialogContent3 from "@mui/material/DialogContent";
@@ -2247,7 +2282,7 @@ var init_ManageTeamDialog = __esm({
2247
2282
  const showMcpServers = mode === "edit" && !!canManageMcpServers;
2248
2283
  const mcpOptions = (mcpServers ?? []).map((s) => s.id);
2249
2284
  const mcpLabel = (id) => (mcpServers ?? []).find((s) => s.id === id)?.name ?? id;
2250
- return /* @__PURE__ */ React5.createElement(Dialog3, { open, onClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React5.createElement(DialogTitle3, null, mode === "create" ? "Create Team" : "Edit Team"), /* @__PURE__ */ React5.createElement(DialogContent3, { sx: { pt: 2, display: "flex", flexDirection: "column", gap: 2 } }, error && /* @__PURE__ */ React5.createElement(Alert2, { severity: "error" }, error), /* @__PURE__ */ React5.createElement(
2285
+ return /* @__PURE__ */ React6.createElement(Dialog3, { open, onClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React6.createElement(DialogTitle3, null, mode === "create" ? "Create Team" : "Edit Team"), /* @__PURE__ */ React6.createElement(DialogContent3, { sx: { pt: 2, display: "flex", flexDirection: "column", gap: 2 } }, error && /* @__PURE__ */ React6.createElement(Alert2, { severity: "error" }, error), /* @__PURE__ */ React6.createElement(
2251
2286
  TextField3,
2252
2287
  {
2253
2288
  label: "Team Alias",
@@ -2256,7 +2291,7 @@ var init_ManageTeamDialog = __esm({
2256
2291
  disabled: submitting,
2257
2292
  fullWidth: true
2258
2293
  }
2259
- ), /* @__PURE__ */ React5.createElement(
2294
+ ), /* @__PURE__ */ React6.createElement(
2260
2295
  Autocomplete2,
2261
2296
  {
2262
2297
  multiple: true,
@@ -2264,7 +2299,7 @@ var init_ManageTeamDialog = __esm({
2264
2299
  value: models,
2265
2300
  onChange: (_, newValue) => setModels(newValue),
2266
2301
  disabled: submitting,
2267
- renderInput: (params) => /* @__PURE__ */ React5.createElement(
2302
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(
2268
2303
  TextField3,
2269
2304
  {
2270
2305
  ...params,
@@ -2274,7 +2309,7 @@ var init_ManageTeamDialog = __esm({
2274
2309
  }
2275
2310
  )
2276
2311
  }
2277
- ), /* @__PURE__ */ React5.createElement(
2312
+ ), /* @__PURE__ */ React6.createElement(
2278
2313
  TextField3,
2279
2314
  {
2280
2315
  label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
@@ -2286,13 +2321,13 @@ var init_ManageTeamDialog = __esm({
2286
2321
  helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
2287
2322
  fullWidth: true
2288
2323
  }
2289
- ), allowUnlimitedBudget && /* @__PURE__ */ React5.createElement(
2324
+ ), allowUnlimitedBudget && /* @__PURE__ */ React6.createElement(
2290
2325
  FormControlLabel2,
2291
2326
  {
2292
- control: /* @__PURE__ */ React5.createElement(Checkbox2, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
2327
+ control: /* @__PURE__ */ React6.createElement(Checkbox2, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
2293
2328
  label: "Unlimited Budget"
2294
2329
  }
2295
- ), /* @__PURE__ */ React5.createElement(
2330
+ ), /* @__PURE__ */ React6.createElement(
2296
2331
  TextField3,
2297
2332
  {
2298
2333
  select: true,
@@ -2303,8 +2338,8 @@ var init_ManageTeamDialog = __esm({
2303
2338
  helperText: "Spend-reset period for the team budget",
2304
2339
  fullWidth: true
2305
2340
  },
2306
- durationOptions.map((o) => /* @__PURE__ */ React5.createElement(MenuItem2, { key: o.value, value: o.value }, o.label))
2307
- ), showMembers && /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Divider2, { sx: { my: 1 } }), /* @__PURE__ */ React5.createElement(Typography5, { variant: "subtitle2", sx: { mb: 1 } }, "Members"), memberError && /* @__PURE__ */ React5.createElement(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null) }, memberError), members.length === 0 ? /* @__PURE__ */ React5.createElement(Typography5, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "No members yet.") : /* @__PURE__ */ React5.createElement(TableContainer2, { component: Paper3, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 } }, /* @__PURE__ */ React5.createElement(Table2, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React5.createElement(TableHead2, null, /* @__PURE__ */ React5.createElement(TableRow2, null, /* @__PURE__ */ React5.createElement(TableCell2, null, "User"), /* @__PURE__ */ React5.createElement(TableCell2, { align: "right" }, "Role"), /* @__PURE__ */ React5.createElement(TableCell2, { align: "right", sx: { width: 40 } }))), /* @__PURE__ */ React5.createElement(TableBody2, null, members.map((m) => /* @__PURE__ */ React5.createElement(TableRow2, { key: m.user_id }, /* @__PURE__ */ React5.createElement(TableCell2, null, m.user_email ? /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(Typography5, { variant: "body2" }, m.user_email), /* @__PURE__ */ React5.createElement(
2341
+ durationOptions.map((o) => /* @__PURE__ */ React6.createElement(MenuItem2, { key: o.value, value: o.value }, o.label))
2342
+ ), showMembers && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Divider2, { sx: { my: 1 } }), /* @__PURE__ */ React6.createElement(Typography5, { variant: "subtitle2", sx: { mb: 1 } }, "Members"), memberError && /* @__PURE__ */ React6.createElement(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null) }, memberError), members.length === 0 ? /* @__PURE__ */ React6.createElement(Typography5, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "No members yet.") : /* @__PURE__ */ React6.createElement(TableContainer2, { component: Paper3, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 } }, /* @__PURE__ */ React6.createElement(Table2, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React6.createElement(TableHead2, null, /* @__PURE__ */ React6.createElement(TableRow2, null, /* @__PURE__ */ React6.createElement(TableCell2, null, "User"), /* @__PURE__ */ React6.createElement(TableCell2, { align: "right" }, "Role"), /* @__PURE__ */ React6.createElement(TableCell2, { align: "right", sx: { width: 40 } }))), /* @__PURE__ */ React6.createElement(TableBody2, null, members.map((m) => /* @__PURE__ */ React6.createElement(TableRow2, { key: m.user_id }, /* @__PURE__ */ React6.createElement(TableCell2, null, m.user_email ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Typography5, { variant: "body2" }, m.user_email), /* @__PURE__ */ React6.createElement(
2308
2343
  Typography5,
2309
2344
  {
2310
2345
  variant: "caption",
@@ -2312,14 +2347,14 @@ var init_ManageTeamDialog = __esm({
2312
2347
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
2313
2348
  },
2314
2349
  m.user_id
2315
- )) : /* @__PURE__ */ React5.createElement(
2350
+ )) : /* @__PURE__ */ React6.createElement(
2316
2351
  Typography5,
2317
2352
  {
2318
2353
  variant: "body2",
2319
2354
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
2320
2355
  },
2321
2356
  m.user_id
2322
- )), /* @__PURE__ */ React5.createElement(TableCell2, { align: "right" }, /* @__PURE__ */ React5.createElement(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false })), /* @__PURE__ */ React5.createElement(TableCell2, { align: "right" }, /* @__PURE__ */ React5.createElement(
2357
+ )), /* @__PURE__ */ React6.createElement(TableCell2, { align: "right" }, /* @__PURE__ */ React6.createElement(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false })), /* @__PURE__ */ React6.createElement(TableCell2, { align: "right" }, /* @__PURE__ */ React6.createElement(
2323
2358
  IconButton3,
2324
2359
  {
2325
2360
  edge: "end",
@@ -2328,8 +2363,8 @@ var init_ManageTeamDialog = __esm({
2328
2363
  disabled: memberBusy,
2329
2364
  onClick: () => handleRemoveMember(m.user_id)
2330
2365
  },
2331
- /* @__PURE__ */ React5.createElement(DeleteIcon, { fontSize: "small" })
2332
- ))))))), /* @__PURE__ */ React5.createElement(Box5, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" } }, /* @__PURE__ */ React5.createElement(
2366
+ /* @__PURE__ */ React6.createElement(DeleteIcon, { fontSize: "small" })
2367
+ ))))))), /* @__PURE__ */ React6.createElement(Box5, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" } }, /* @__PURE__ */ React6.createElement(
2333
2368
  Autocomplete2,
2334
2369
  {
2335
2370
  freeSolo: true,
@@ -2353,7 +2388,7 @@ var init_ManageTeamDialog = __esm({
2353
2388
  isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
2354
2389
  disabled: memberBusy,
2355
2390
  sx: { flex: 1, minWidth: 260 },
2356
- renderInput: (params) => /* @__PURE__ */ React5.createElement(
2391
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(
2357
2392
  TextField3,
2358
2393
  {
2359
2394
  ...params,
@@ -2363,12 +2398,12 @@ var init_ManageTeamDialog = __esm({
2363
2398
  helperText: "Pick a catalog user, or paste a user entity ref",
2364
2399
  InputProps: {
2365
2400
  ...params.InputProps,
2366
- endAdornment: /* @__PURE__ */ React5.createElement(React5.Fragment, null, usersLoading ? /* @__PURE__ */ React5.createElement(CircularProgress3, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2401
+ endAdornment: /* @__PURE__ */ React6.createElement(React6.Fragment, null, usersLoading ? /* @__PURE__ */ React6.createElement(CircularProgress3, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2367
2402
  }
2368
2403
  }
2369
2404
  )
2370
2405
  }
2371
- ), /* @__PURE__ */ React5.createElement(
2406
+ ), /* @__PURE__ */ React6.createElement(
2372
2407
  TextField3,
2373
2408
  {
2374
2409
  label: "Max budget in team ($)",
@@ -2379,7 +2414,7 @@ var init_ManageTeamDialog = __esm({
2379
2414
  size: "small",
2380
2415
  sx: { width: 160 }
2381
2416
  }
2382
- ), /* @__PURE__ */ React5.createElement(
2417
+ ), /* @__PURE__ */ React6.createElement(
2383
2418
  Button4,
2384
2419
  {
2385
2420
  onClick: handleAddMember,
@@ -2388,7 +2423,7 @@ var init_ManageTeamDialog = __esm({
2388
2423
  sx: { mt: 0.5 }
2389
2424
  },
2390
2425
  "Add"
2391
- ))), showKnowledgeBases && /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Divider2, { sx: { my: 1 } }), /* @__PURE__ */ React5.createElement(Typography5, { variant: "subtitle2", sx: { mb: 1 } }, "Knowledge Bases"), /* @__PURE__ */ React5.createElement(Typography5, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "Attaching a knowledge base exposes its documents to every key in this team."), kbError && /* @__PURE__ */ React5.createElement(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setKbError(null) }, kbError), /* @__PURE__ */ React5.createElement(
2426
+ ))), showKnowledgeBases && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Divider2, { sx: { my: 1 } }), /* @__PURE__ */ React6.createElement(Typography5, { variant: "subtitle2", sx: { mb: 1 } }, "Knowledge Bases"), /* @__PURE__ */ React6.createElement(Typography5, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "Attaching a knowledge base exposes its documents to every key in this team."), kbError && /* @__PURE__ */ React6.createElement(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setKbError(null) }, kbError), /* @__PURE__ */ React6.createElement(
2392
2427
  Autocomplete2,
2393
2428
  {
2394
2429
  multiple: true,
@@ -2397,9 +2432,9 @@ var init_ManageTeamDialog = __esm({
2397
2432
  getOptionLabel: kbLabel,
2398
2433
  onChange: (_, v) => setKbIds(v),
2399
2434
  disabled: kbBusy,
2400
- renderInput: (params) => /* @__PURE__ */ React5.createElement(TextField3, { ...params, label: "Attached knowledge bases" })
2435
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(TextField3, { ...params, label: "Attached knowledge bases" })
2401
2436
  }
2402
- ), /* @__PURE__ */ React5.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React5.createElement(
2437
+ ), /* @__PURE__ */ React6.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React6.createElement(
2403
2438
  Button4,
2404
2439
  {
2405
2440
  onClick: handleSaveKnowledgeBases,
@@ -2407,7 +2442,7 @@ var init_ManageTeamDialog = __esm({
2407
2442
  variant: "outlined"
2408
2443
  },
2409
2444
  kbBusy ? "Saving\u2026" : "Save knowledge bases"
2410
- ))), showMcpServers && /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Divider2, { sx: { my: 1 } }), /* @__PURE__ */ React5.createElement(Typography5, { variant: "subtitle2", sx: { mb: 1 } }, "MCP Servers"), /* @__PURE__ */ React5.createElement(Typography5, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "Attaching an MCP server lets every key in this team invoke that server's tools through the model \u2014 including any side effects those tools have."), mcpError && /* @__PURE__ */ React5.createElement(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setMcpError(null) }, mcpError), /* @__PURE__ */ React5.createElement(
2445
+ ))), showMcpServers && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Divider2, { sx: { my: 1 } }), /* @__PURE__ */ React6.createElement(Typography5, { variant: "subtitle2", sx: { mb: 1 } }, "MCP Servers"), /* @__PURE__ */ React6.createElement(Typography5, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "Attaching an MCP server lets every key in this team invoke that server's tools through the model \u2014 including any side effects those tools have."), mcpError && /* @__PURE__ */ React6.createElement(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setMcpError(null) }, mcpError), /* @__PURE__ */ React6.createElement(
2411
2446
  Autocomplete2,
2412
2447
  {
2413
2448
  multiple: true,
@@ -2416,9 +2451,9 @@ var init_ManageTeamDialog = __esm({
2416
2451
  getOptionLabel: mcpLabel,
2417
2452
  onChange: (_, v) => setMcpIds(v),
2418
2453
  disabled: mcpBusy,
2419
- renderInput: (params) => /* @__PURE__ */ React5.createElement(TextField3, { ...params, label: "Attached MCP servers" })
2454
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(TextField3, { ...params, label: "Attached MCP servers" })
2420
2455
  }
2421
- ), /* @__PURE__ */ React5.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React5.createElement(
2456
+ ), /* @__PURE__ */ React6.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React6.createElement(
2422
2457
  Button4,
2423
2458
  {
2424
2459
  onClick: handleSaveMcpServers,
@@ -2426,13 +2461,13 @@ var init_ManageTeamDialog = __esm({
2426
2461
  variant: "outlined"
2427
2462
  },
2428
2463
  mcpBusy ? "Saving\u2026" : "Save MCP servers"
2429
- )))), /* @__PURE__ */ React5.createElement(DialogActions3, null, /* @__PURE__ */ React5.createElement(Button4, { onClick: onClose, disabled: submitting }, "Cancel"), /* @__PURE__ */ React5.createElement(Button4, { onClick: handleSubmit, disabled: submitting, variant: "contained" }, submitting ? "Saving..." : "Save")));
2464
+ )))), /* @__PURE__ */ React6.createElement(DialogActions3, null, /* @__PURE__ */ React6.createElement(Button4, { onClick: onClose, disabled: submitting }, "Cancel"), /* @__PURE__ */ React6.createElement(Button4, { onClick: handleSubmit, disabled: submitting, variant: "contained" }, submitting ? "Saving..." : "Save")));
2430
2465
  };
2431
2466
  }
2432
2467
  });
2433
2468
 
2434
2469
  // src/components/UsageStats.tsx
2435
- import React6, { useMemo as useMemo5, useState as useState4 } from "react";
2470
+ import React7, { useMemo as useMemo5, useState as useState4 } from "react";
2436
2471
  import Paper4 from "@mui/material/Paper";
2437
2472
  import Box6 from "@mui/material/Box";
2438
2473
  import Typography6 from "@mui/material/Typography";
@@ -2482,16 +2517,16 @@ var init_UsageStats = __esm({
2482
2517
  "30d": "Last 30 days"
2483
2518
  };
2484
2519
  fmtPct = (n) => `${(n * 100).toFixed(1)}%`;
2485
- ChartSkeleton = ({ height = 240 }) => /* @__PURE__ */ React6.createElement(Skeleton3, { variant: "rounded", height });
2520
+ ChartSkeleton = ({ height = 240 }) => /* @__PURE__ */ React7.createElement(Skeleton3, { variant: "rounded", height });
2486
2521
  ChartOrFallback = ({ loading, empty, height = 240, children }) => {
2487
- if (loading) return /* @__PURE__ */ React6.createElement(ChartSkeleton, { height });
2488
- if (empty) return /* @__PURE__ */ React6.createElement(EmptyState, { message: "No data for this period", height });
2489
- return /* @__PURE__ */ React6.createElement(React6.Fragment, null, children);
2522
+ if (loading) return /* @__PURE__ */ React7.createElement(ChartSkeleton, { height });
2523
+ if (empty) return /* @__PURE__ */ React7.createElement(EmptyState, { message: "No data for this period", height });
2524
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, children);
2490
2525
  };
2491
2526
  SuccessRateCell = ({ rate, requests }) => {
2492
- if (requests === 0) return /* @__PURE__ */ React6.createElement(Typography6, { variant: "body2", color: "text.secondary" }, "\u2014");
2527
+ if (requests === 0) return /* @__PURE__ */ React7.createElement(Typography6, { variant: "body2", color: "text.secondary" }, "\u2014");
2493
2528
  const tone = rateTone(rate);
2494
- return /* @__PURE__ */ React6.createElement(Box6, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React6.createElement(Box6, { width: 72, flexShrink: 0 }, /* @__PURE__ */ React6.createElement(Meter, { value: rate * 100, tone, height: 4 })), /* @__PURE__ */ React6.createElement(
2529
+ return /* @__PURE__ */ React7.createElement(Box6, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React7.createElement(Box6, { width: 72, flexShrink: 0 }, /* @__PURE__ */ React7.createElement(Meter, { value: rate * 100, tone, height: 4 })), /* @__PURE__ */ React7.createElement(
2495
2530
  Typography6,
2496
2531
  {
2497
2532
  variant: "caption",
@@ -2640,23 +2675,23 @@ var init_UsageStats = __esm({
2640
2675
  ];
2641
2676
  const renderKeyRows = () => {
2642
2677
  if (loading) {
2643
- return /* @__PURE__ */ React6.createElement(TableRow3, null, /* @__PURE__ */ React6.createElement(TableCell3, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ React6.createElement(Skeleton3, { variant: "rounded", height: 80 })));
2678
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ React7.createElement(Skeleton3, { variant: "rounded", height: 80 })));
2644
2679
  }
2645
2680
  if (keyRows.length === 0) {
2646
- return /* @__PURE__ */ React6.createElement(TableRow3, null, /* @__PURE__ */ React6.createElement(TableCell3, { colSpan: 7 }, /* @__PURE__ */ React6.createElement(EmptyState, { message: "No key activity in this period" })));
2681
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 7 }, /* @__PURE__ */ React7.createElement(EmptyState, { message: "No key activity in this period" })));
2647
2682
  }
2648
- return [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ React6.createElement(TableRow3, { key: r.keyHash }, /* @__PURE__ */ React6.createElement(TableCell3, null, /* @__PURE__ */ React6.createElement(Typography6, { variant: "body2", sx: { fontWeight: 600 } }, r.keyAlias), r.teamId ? /* @__PURE__ */ React6.createElement(Typography6, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ React6.createElement(TableCell3, null, /* @__PURE__ */ React6.createElement(Box6, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.slice(0, 3).map((m) => /* @__PURE__ */ React6.createElement(TagChip, { key: m, label: m, title: m })), r.models.length > 3 && /* @__PURE__ */ React6.createElement(TagChip, { label: `+${r.models.length - 3}`, mono: false }))), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtCompact(r.totalTokens)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ React6.createElement(TableCell3, null, /* @__PURE__ */ React6.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2683
+ return [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ React7.createElement(TableRow3, { key: r.keyHash }, /* @__PURE__ */ React7.createElement(TableCell3, null, /* @__PURE__ */ React7.createElement(Typography6, { variant: "body2", sx: { fontWeight: 600 } }, r.keyAlias), r.teamId ? /* @__PURE__ */ React7.createElement(Typography6, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ React7.createElement(TableCell3, null, /* @__PURE__ */ React7.createElement(Box6, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.slice(0, 3).map((m) => /* @__PURE__ */ React7.createElement(TagChip, { key: m, label: m, title: m })), r.models.length > 3 && /* @__PURE__ */ React7.createElement(TagChip, { label: `+${r.models.length - 3}`, mono: false }))), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtCompact(r.totalTokens)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ React7.createElement(TableCell3, null, /* @__PURE__ */ React7.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2649
2684
  };
2650
2685
  const renderModelRows = () => {
2651
2686
  if (loading) {
2652
- return /* @__PURE__ */ React6.createElement(TableRow3, null, /* @__PURE__ */ React6.createElement(TableCell3, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ React6.createElement(Skeleton3, { variant: "rounded", height: 80 })));
2687
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ React7.createElement(Skeleton3, { variant: "rounded", height: 80 })));
2653
2688
  }
2654
2689
  if (modelRows.length === 0) {
2655
- return /* @__PURE__ */ React6.createElement(TableRow3, null, /* @__PURE__ */ React6.createElement(TableCell3, { colSpan: 8 }, /* @__PURE__ */ React6.createElement(EmptyState, { message: "No model activity in this period" })));
2690
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 8 }, /* @__PURE__ */ React7.createElement(EmptyState, { message: "No model activity in this period" })));
2656
2691
  }
2657
- return [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ React6.createElement(TableRow3, { key: r.model }, /* @__PURE__ */ React6.createElement(TableCell3, null, /* @__PURE__ */ React6.createElement(Box6, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React6.createElement(Box6, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: chartColor(r.model), flexShrink: 0 } }), /* @__PURE__ */ React6.createElement(Typography6, { variant: "body2", sx: { fontWeight: 600 } }, r.model))), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtCompact(r.promptTokens)), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, fmtCompact(r.completionTokens)), /* @__PURE__ */ React6.createElement(TableCell3, null, /* @__PURE__ */ React6.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2692
+ return [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ React7.createElement(TableRow3, { key: r.model }, /* @__PURE__ */ React7.createElement(TableCell3, null, /* @__PURE__ */ React7.createElement(Box6, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ React7.createElement(Box6, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: chartColor(r.model), flexShrink: 0 } }), /* @__PURE__ */ React7.createElement(Typography6, { variant: "body2", sx: { fontWeight: 600 } }, r.model))), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtCompact(r.promptTokens)), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, fmtCompact(r.completionTokens)), /* @__PURE__ */ React7.createElement(TableCell3, null, /* @__PURE__ */ React7.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2658
2693
  };
2659
- const periodSelect = /* @__PURE__ */ React6.createElement(
2694
+ const periodSelect = /* @__PURE__ */ React7.createElement(
2660
2695
  TextField4,
2661
2696
  {
2662
2697
  select: true,
@@ -2666,17 +2701,17 @@ var init_UsageStats = __esm({
2666
2701
  onChange: (e) => handlePresetChange(e.target.value),
2667
2702
  sx: { minWidth: 160 }
2668
2703
  },
2669
- Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ React6.createElement(MenuItem3, { key: p, value: p }, PRESET_LABELS[p]))
2704
+ Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ React7.createElement(MenuItem3, { key: p, value: p }, PRESET_LABELS[p]))
2670
2705
  );
2671
- return /* @__PURE__ */ React6.createElement(
2706
+ return /* @__PURE__ */ React7.createElement(
2672
2707
  SectionCard,
2673
2708
  {
2674
2709
  title: "Usage Analytics",
2675
2710
  subtitle: `${PRESET_LABELS[currentPreset]} \xB7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`,
2676
2711
  actions: periodSelect
2677
2712
  },
2678
- /* @__PURE__ */ React6.createElement(MetricStrip, { metrics }),
2679
- /* @__PURE__ */ React6.createElement(
2713
+ /* @__PURE__ */ React7.createElement(MetricStrip, { metrics }),
2714
+ /* @__PURE__ */ React7.createElement(
2680
2715
  Box6,
2681
2716
  {
2682
2717
  sx: {
@@ -2689,7 +2724,7 @@ var init_UsageStats = __esm({
2689
2724
  mb: 2
2690
2725
  }
2691
2726
  },
2692
- /* @__PURE__ */ React6.createElement(
2727
+ /* @__PURE__ */ React7.createElement(
2693
2728
  SegmentedControl,
2694
2729
  {
2695
2730
  value: tab,
@@ -2701,7 +2736,7 @@ var init_UsageStats = __esm({
2701
2736
  ]
2702
2737
  }
2703
2738
  ),
2704
- tab === "models" && /* @__PURE__ */ React6.createElement(
2739
+ tab === "models" && /* @__PURE__ */ React7.createElement(
2705
2740
  TextField4,
2706
2741
  {
2707
2742
  select: true,
@@ -2711,17 +2746,17 @@ var init_UsageStats = __esm({
2711
2746
  onChange: (e) => setSelectedModel(e.target.value),
2712
2747
  sx: { minWidth: 220 }
2713
2748
  },
2714
- /* @__PURE__ */ React6.createElement(MenuItem3, { value: "all" }, "All models"),
2715
- models.map((m) => /* @__PURE__ */ React6.createElement(MenuItem3, { key: m.model_name, value: m.model_name }, m.model_name))
2749
+ /* @__PURE__ */ React7.createElement(MenuItem3, { value: "all" }, "All models"),
2750
+ models.map((m) => /* @__PURE__ */ React7.createElement(MenuItem3, { key: m.model_name, value: m.model_name }, m.model_name))
2716
2751
  )
2717
2752
  ),
2718
- tab === "costs" && /* @__PURE__ */ React6.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Daily spend by model", height: 260 }, /* @__PURE__ */ React6.createElement(ChartOrFallback, { loading, empty: modelSpendByDate.length === 0, height: 260 }, /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(AreaChart, { data: modelSpendByDate, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React6.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { tickFormatter: fmtUsdCompact, width: 56, ...chart.axis }), /* @__PURE__ */ React6.createElement(
2753
+ tab === "costs" && /* @__PURE__ */ React7.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Daily spend by model", height: 260 }, /* @__PURE__ */ React7.createElement(ChartOrFallback, { loading, empty: modelSpendByDate.length === 0, height: 260 }, /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(AreaChart, { data: modelSpendByDate, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React7.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { tickFormatter: fmtUsdCompact, width: 56, ...chart.axis }), /* @__PURE__ */ React7.createElement(
2719
2754
  Tooltip,
2720
2755
  {
2721
2756
  cursor: chart.cursor,
2722
- content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtUsd, hideZero: true })
2757
+ content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtUsd, hideZero: true })
2723
2758
  }
2724
- ), topSpendModels.map((m) => /* @__PURE__ */ React6.createElement(
2759
+ ), topSpendModels.map((m) => /* @__PURE__ */ React7.createElement(
2725
2760
  Area,
2726
2761
  {
2727
2762
  key: m,
@@ -2733,13 +2768,13 @@ var init_UsageStats = __esm({
2733
2768
  fill: chartColor(m),
2734
2769
  fillOpacity: 0.28
2735
2770
  }
2736
- ))))), !loading && topSpendModels.length > 0 && /* @__PURE__ */ React6.createElement(SeriesLegend, { series: topSpendModels.map((m) => ({ name: m, color: chartColor(m) })) }))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Daily token usage" }, /* @__PURE__ */ React6.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(AreaChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React6.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ React6.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ React6.createElement(Legend, { ...chart.legend }), /* @__PURE__ */ React6.createElement(Area, { type: "monotone", dataKey: "promptTokens", name: "Input", stackId: "tok", stroke: SERIES.input, strokeWidth: 1.5, fill: SERIES.input, fillOpacity: 0.25 }), /* @__PURE__ */ React6.createElement(Area, { type: "monotone", dataKey: "completionTokens", name: "Output", stackId: "tok", stroke: SERIES.output, strokeWidth: 1.5, fill: SERIES.output, fillOpacity: 0.25 })))))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Daily requests" }, /* @__PURE__ */ React6.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(BarChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 }, barCategoryGap: "30%" }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React6.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ React6.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ React6.createElement(Legend, { ...chart.legend }), /* @__PURE__ */ React6.createElement(Bar, { dataKey: "successfulRequests", name: "Successful", fill: SERIES.success, stackId: "r" }), /* @__PURE__ */ React6.createElement(Bar, { dataKey: "failedRequests", name: "Failed", fill: SERIES.failure, stackId: "r", radius: [3, 3, 0, 0] })))))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Daily success rate" }, /* @__PURE__ */ React6.createElement(ChartOrFallback, { loading, empty: successRateData.length === 0 }, /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(LineChart, { data: successRateData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React6.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { domain: [0, 100], tickFormatter: (v) => `${v}%`, width: 44, ...chart.axis }), /* @__PURE__ */ React6.createElement(
2771
+ ))))), !loading && topSpendModels.length > 0 && /* @__PURE__ */ React7.createElement(SeriesLegend, { series: topSpendModels.map((m) => ({ name: m, color: chartColor(m) })) }))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Daily token usage" }, /* @__PURE__ */ React7.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(AreaChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React7.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ React7.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ React7.createElement(Legend, { ...chart.legend }), /* @__PURE__ */ React7.createElement(Area, { type: "monotone", dataKey: "promptTokens", name: "Input", stackId: "tok", stroke: SERIES.input, strokeWidth: 1.5, fill: SERIES.input, fillOpacity: 0.25 }), /* @__PURE__ */ React7.createElement(Area, { type: "monotone", dataKey: "completionTokens", name: "Output", stackId: "tok", stroke: SERIES.output, strokeWidth: 1.5, fill: SERIES.output, fillOpacity: 0.25 })))))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Daily requests" }, /* @__PURE__ */ React7.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(BarChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 }, barCategoryGap: "30%" }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React7.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ React7.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ React7.createElement(Legend, { ...chart.legend }), /* @__PURE__ */ React7.createElement(Bar, { dataKey: "successfulRequests", name: "Successful", fill: SERIES.success, stackId: "r" }), /* @__PURE__ */ React7.createElement(Bar, { dataKey: "failedRequests", name: "Failed", fill: SERIES.failure, stackId: "r", radius: [3, 3, 0, 0] })))))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Daily success rate" }, /* @__PURE__ */ React7.createElement(ChartOrFallback, { loading, empty: successRateData.length === 0 }, /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(LineChart, { data: successRateData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React7.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { domain: [0, 100], tickFormatter: (v) => `${v}%`, width: 44, ...chart.axis }), /* @__PURE__ */ React7.createElement(
2737
2772
  Tooltip,
2738
2773
  {
2739
2774
  cursor: chart.cursor,
2740
- content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: (v) => `${v}%` })
2775
+ content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: (v) => `${v}%` })
2741
2776
  }
2742
- ), /* @__PURE__ */ React6.createElement(ReferenceLine, { y: 100, stroke: SERIES.success, strokeDasharray: "4 4", strokeOpacity: 0.5 }), /* @__PURE__ */ React6.createElement(
2777
+ ), /* @__PURE__ */ React7.createElement(ReferenceLine, { y: 100, stroke: SERIES.success, strokeDasharray: "4 4", strokeOpacity: 0.5 }), /* @__PURE__ */ React7.createElement(
2743
2778
  Line,
2744
2779
  {
2745
2780
  type: "monotone",
@@ -2750,13 +2785,13 @@ var init_UsageStats = __esm({
2750
2785
  dot: { r: 2.5, strokeWidth: 0, fill: SERIES.input },
2751
2786
  activeDot: { r: 4 }
2752
2787
  }
2753
- )))))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(
2788
+ )))))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(
2754
2789
  ChartCard,
2755
2790
  {
2756
2791
  title: maxBudget > 0 ? "Cumulative spend vs budget" : "Cumulative spend",
2757
2792
  meta: maxBudget > 0 ? `${fmtUsd(totalCumSpend)} used \xB7 ${fmtUsd(Math.max(0, maxBudget - totalCumSpend))} left` : void 0
2758
2793
  },
2759
- /* @__PURE__ */ React6.createElement(ChartOrFallback, { loading, empty: cumulativeData.length === 0 }, /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(AreaChart, { data: cumulativeData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React6.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React6.createElement(
2794
+ /* @__PURE__ */ React7.createElement(ChartOrFallback, { loading, empty: cumulativeData.length === 0 }, /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(AreaChart, { data: cumulativeData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid }), /* @__PURE__ */ React7.createElement(XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React7.createElement(
2760
2795
  YAxis,
2761
2796
  {
2762
2797
  tickFormatter: fmtUsdCompact,
@@ -2764,13 +2799,13 @@ var init_UsageStats = __esm({
2764
2799
  domain: cumulativeDomain,
2765
2800
  ...chart.axis
2766
2801
  }
2767
- ), /* @__PURE__ */ React6.createElement(
2802
+ ), /* @__PURE__ */ React7.createElement(
2768
2803
  Tooltip,
2769
2804
  {
2770
2805
  cursor: chart.cursor,
2771
- content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtUsd })
2806
+ content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtUsd })
2772
2807
  }
2773
- ), maxBudget > 0 && /* @__PURE__ */ React6.createElement(
2808
+ ), maxBudget > 0 && /* @__PURE__ */ React7.createElement(
2774
2809
  ReferenceLine,
2775
2810
  {
2776
2811
  y: maxBudget,
@@ -2778,7 +2813,7 @@ var init_UsageStats = __esm({
2778
2813
  strokeDasharray: "5 4",
2779
2814
  label: { value: `Budget ${fmtUsd(maxBudget)}`, position: "insideTopRight", fontSize: 10, fill: SERIES.budget }
2780
2815
  }
2781
- ), /* @__PURE__ */ React6.createElement(
2816
+ ), /* @__PURE__ */ React7.createElement(
2782
2817
  Area,
2783
2818
  {
2784
2819
  type: "monotone",
@@ -2791,32 +2826,32 @@ var init_UsageStats = __esm({
2791
2826
  }
2792
2827
  ))))
2793
2828
  ))),
2794
- tab === "models" && /* @__PURE__ */ React6.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Spend by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ React6.createElement(
2829
+ tab === "models" && /* @__PURE__ */ React7.createElement(Grid, { container: true, spacing: 2 }, /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Spend by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ React7.createElement(
2795
2830
  ChartOrFallback,
2796
2831
  {
2797
2832
  loading,
2798
2833
  empty: topModelSpendBars.length === 0,
2799
2834
  height: Math.max(200, topModelSpendBars.length * 34)
2800
2835
  },
2801
- /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ React6.createElement(XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ React6.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ React6.createElement(Bar, { dataKey: "spend", name: "Spend", radius: [0, 3, 3, 0], barSize: 14 }, topModelSpendBars.map((r) => /* @__PURE__ */ React6.createElement(Cell, { key: r.model, fill: chartColor(r.model) })))))
2802
- ))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Tokens by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ React6.createElement(
2836
+ /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ React7.createElement(XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ React7.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ React7.createElement(Bar, { dataKey: "spend", name: "Spend", radius: [0, 3, 3, 0], barSize: 14 }, topModelSpendBars.map((r) => /* @__PURE__ */ React7.createElement(Cell, { key: r.model, fill: chartColor(r.model) })))))
2837
+ ))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Tokens by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ React7.createElement(
2803
2838
  ChartOrFallback,
2804
2839
  {
2805
2840
  loading,
2806
2841
  empty: modelRows.length === 0,
2807
2842
  height: Math.max(200, topModelSpendBars.length * 34)
2808
2843
  },
2809
- /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ React6.createElement(XAxis, { type: "number", tickFormatter: fmtCompact, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ React6.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtInt, labelFormatter: (l) => l }) }), /* @__PURE__ */ React6.createElement(Legend, { ...chart.legend }), /* @__PURE__ */ React6.createElement(Bar, { dataKey: "promptTokens", name: "Input", fill: SERIES.input, stackId: "t", barSize: 14 }), /* @__PURE__ */ React6.createElement(Bar, { dataKey: "completionTokens", name: "Output", fill: SERIES.output, stackId: "t", barSize: 14, radius: [0, 3, 3, 0] })))
2810
- ))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React6.createElement(TableContainer3, { component: Paper4, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ React6.createElement(Table3, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React6.createElement(TableHead3, null, /* @__PURE__ */ React6.createElement(TableRow3, null, /* @__PURE__ */ React6.createElement(TableCell3, null, "Model"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Spend"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Requests"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Success"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Failed"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Input"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Output"), /* @__PURE__ */ React6.createElement(TableCell3, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ React6.createElement(TableBody3, null, renderModelRows()))))),
2811
- tab === "keys" && /* @__PURE__ */ React6.createElement(Grid, { container: true, spacing: 2 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React6.createElement(ChartCard, { title: "Spend by key", height: Math.max(160, topKeySpendBars.length * 32) }, /* @__PURE__ */ React6.createElement(
2844
+ /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ React7.createElement(XAxis, { type: "number", tickFormatter: fmtCompact, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ React7.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtInt, labelFormatter: (l) => l }) }), /* @__PURE__ */ React7.createElement(Legend, { ...chart.legend }), /* @__PURE__ */ React7.createElement(Bar, { dataKey: "promptTokens", name: "Input", fill: SERIES.input, stackId: "t", barSize: 14 }), /* @__PURE__ */ React7.createElement(Bar, { dataKey: "completionTokens", name: "Output", fill: SERIES.output, stackId: "t", barSize: 14, radius: [0, 3, 3, 0] })))
2845
+ ))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React7.createElement(TableContainer3, { component: Paper4, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ React7.createElement(Table3, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React7.createElement(TableHead3, null, /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, null, "Model"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Spend"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Requests"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Success"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Failed"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Input"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Output"), /* @__PURE__ */ React7.createElement(TableCell3, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ React7.createElement(TableBody3, null, renderModelRows()))))),
2846
+ tab === "keys" && /* @__PURE__ */ React7.createElement(Grid, { container: true, spacing: 2 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React7.createElement(ChartCard, { title: "Spend by key", height: Math.max(160, topKeySpendBars.length * 32) }, /* @__PURE__ */ React7.createElement(
2812
2847
  ChartOrFallback,
2813
2848
  {
2814
2849
  loading,
2815
2850
  empty: topKeySpendBars.length === 0,
2816
2851
  height: Math.max(160, topKeySpendBars.length * 32)
2817
2852
  },
2818
- /* @__PURE__ */ React6.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React6.createElement(BarChart, { data: topKeySpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ React6.createElement(CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ React6.createElement(XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ React6.createElement(YAxis, { type: "category", dataKey: "keyAlias", width: 160, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ React6.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ React6.createElement(Bar, { dataKey: "spend", name: "Spend", fill: SERIES.input, radius: [0, 3, 3, 0], barSize: 14 })))
2819
- ))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React6.createElement(TableContainer3, { component: Paper4, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ React6.createElement(Table3, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React6.createElement(TableHead3, null, /* @__PURE__ */ React6.createElement(TableRow3, null, /* @__PURE__ */ React6.createElement(TableCell3, null, "Key"), /* @__PURE__ */ React6.createElement(TableCell3, null, "Models"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Spend"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Requests"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Tokens"), /* @__PURE__ */ React6.createElement(TableCell3, { align: "right" }, "Failed"), /* @__PURE__ */ React6.createElement(TableCell3, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ React6.createElement(TableBody3, null, renderKeyRows())))))
2853
+ /* @__PURE__ */ React7.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React7.createElement(BarChart, { data: topKeySpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ React7.createElement(CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ React7.createElement(XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ React7.createElement(YAxis, { type: "category", dataKey: "keyAlias", width: 160, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ React7.createElement(Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ React7.createElement(Bar, { dataKey: "spend", name: "Spend", fill: SERIES.input, radius: [0, 3, 3, 0], barSize: 14 })))
2854
+ ))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12 }, /* @__PURE__ */ React7.createElement(TableContainer3, { component: Paper4, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ React7.createElement(Table3, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React7.createElement(TableHead3, null, /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, null, "Key"), /* @__PURE__ */ React7.createElement(TableCell3, null, "Models"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Spend"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Requests"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Tokens"), /* @__PURE__ */ React7.createElement(TableCell3, { align: "right" }, "Failed"), /* @__PURE__ */ React7.createElement(TableCell3, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ React7.createElement(TableBody3, null, renderKeyRows())))))
2820
2855
  );
2821
2856
  };
2822
2857
  }
@@ -2944,12 +2979,12 @@ var init_budget = __esm({
2944
2979
  });
2945
2980
 
2946
2981
  // src/components/BudgetLimitList.tsx
2947
- import React7 from "react";
2982
+ import React8 from "react";
2948
2983
  import Box7 from "@mui/material/Box";
2949
2984
  import Paper5 from "@mui/material/Paper";
2950
2985
  import Typography7 from "@mui/material/Typography";
2951
2986
  import { alpha as alpha4, useTheme as useTheme2 } from "@mui/material/styles";
2952
- import { Link } from "@backstage/core-components";
2987
+ import { Link as Link2 } from "@backstage/core-components";
2953
2988
  function levelToneColor(tone, theme) {
2954
2989
  switch (tone) {
2955
2990
  case "success":
@@ -2975,7 +3010,7 @@ var init_BudgetLimitList = __esm({
2975
3010
  const tone = budgetTone2(limit.pct);
2976
3011
  const pct = Math.round(limit.pct);
2977
3012
  const closeTo = limit.softLimit !== void 0 && limit.spend >= limit.softLimit;
2978
- return /* @__PURE__ */ React7.createElement(Paper5, { variant: "outlined", sx: { px: 1.5, py: 1.25, borderRadius: 1.5 } }, /* @__PURE__ */ React7.createElement(Box7, { sx: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 1.5 } }, /* @__PURE__ */ React7.createElement(Box7, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ React7.createElement(
3013
+ return /* @__PURE__ */ React8.createElement(Paper5, { variant: "outlined", sx: { px: 1.5, py: 1.25, borderRadius: 1.5 } }, /* @__PURE__ */ React8.createElement(Box7, { sx: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 1.5 } }, /* @__PURE__ */ React8.createElement(Box7, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ React8.createElement(
2979
3014
  Typography7,
2980
3015
  {
2981
3016
  variant: "body2",
@@ -2983,7 +3018,7 @@ var init_BudgetLimitList = __esm({
2983
3018
  title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label
2984
3019
  },
2985
3020
  limit.label
2986
- ), limit.sublabel && /* @__PURE__ */ React7.createElement(
3021
+ ), limit.sublabel && /* @__PURE__ */ React8.createElement(
2987
3022
  Typography7,
2988
3023
  {
2989
3024
  variant: "caption",
@@ -2998,7 +3033,7 @@ var init_BudgetLimitList = __esm({
2998
3033
  }
2999
3034
  },
3000
3035
  limit.sublabel
3001
- )), limit.hidden ? /* @__PURE__ */ React7.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, pct, "% used") : /* @__PURE__ */ React7.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, fmtUsd(limit.spend), /* @__PURE__ */ React7.createElement(Box7, { component: "span", color: "text.secondary", sx: { fontWeight: 400 } }, " / ", fmtUsd(limit.budget)))), /* @__PURE__ */ React7.createElement(Box7, { sx: { mt: 1 } }, /* @__PURE__ */ React7.createElement(Meter, { value: limit.pct, tone, height: 6 })), /* @__PURE__ */ React7.createElement(
3036
+ )), limit.hidden ? /* @__PURE__ */ React8.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, pct, "% used") : /* @__PURE__ */ React8.createElement(Typography7, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, fmtUsd(limit.spend), /* @__PURE__ */ React8.createElement(Box7, { component: "span", color: "text.secondary", sx: { fontWeight: 400 } }, " / ", fmtUsd(limit.budget)))), /* @__PURE__ */ React8.createElement(Box7, { sx: { mt: 1 } }, /* @__PURE__ */ React8.createElement(Meter, { value: limit.pct, tone, height: 6 })), /* @__PURE__ */ React8.createElement(
3002
3037
  Box7,
3003
3038
  {
3004
3039
  sx: {
@@ -3009,14 +3044,14 @@ var init_BudgetLimitList = __esm({
3009
3044
  mt: 0.75
3010
3045
  }
3011
3046
  },
3012
- /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, limit.hidden ? /* @__PURE__ */ React7.createElement(React7.Fragment, null, "Hidden by admin") : /* @__PURE__ */ React7.createElement(React7.Fragment, null, pct, "% of budget", closeTo && ` \xB7 soft-limit warning`)),
3013
- /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary" }, fmtBudgetDuration(limit.budgetDuration) ? `resets ${fmtBudgetDuration(limit.budgetDuration)}` : "never resets")
3047
+ /* @__PURE__ */ React8.createElement(Typography7, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, limit.hidden ? /* @__PURE__ */ React8.createElement(React8.Fragment, null, "Hidden by admin") : /* @__PURE__ */ React8.createElement(React8.Fragment, null, pct, "% of budget", closeTo && ` \xB7 soft-limit warning`)),
3048
+ /* @__PURE__ */ React8.createElement(Typography7, { variant: "caption", color: "text.secondary" }, fmtBudgetDuration(limit.budgetDuration) ? `resets ${fmtBudgetDuration(limit.budgetDuration)}` : "never resets")
3014
3049
  ));
3015
3050
  };
3016
3051
  TaggedLimit = ({ limit }) => {
3017
3052
  const theme = useTheme2();
3018
3053
  const tone = budgetTone2(limit.pct);
3019
- return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(
3054
+ return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(
3020
3055
  Typography7,
3021
3056
  {
3022
3057
  sx: {
@@ -3029,7 +3064,7 @@ var init_BudgetLimitList = __esm({
3029
3064
  }
3030
3065
  },
3031
3066
  limit.kind
3032
- ), /* @__PURE__ */ React7.createElement(LimitCard, { limit }));
3067
+ ), /* @__PURE__ */ React8.createElement(LimitCard, { limit }));
3033
3068
  };
3034
3069
  MoreKeysNote = ({
3035
3070
  count,
@@ -3038,12 +3073,12 @@ var init_BudgetLimitList = __esm({
3038
3073
  }) => {
3039
3074
  const text = label ?? `+${count} more budgeted key${count > 1 ? "s" : ""} further from the cap`;
3040
3075
  if (!href) {
3041
- return /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary" }, text);
3076
+ return /* @__PURE__ */ React8.createElement(Typography7, { variant: "caption", color: "text.secondary" }, text);
3042
3077
  }
3043
- return /* @__PURE__ */ React7.createElement(Link, { to: href, variant: "caption" }, text, " \u2192");
3078
+ return /* @__PURE__ */ React8.createElement(Link2, { to: href, variant: "caption" }, text, " \u2192");
3044
3079
  };
3045
- BudgetLimitList = ({ limits, hiddenKeyCount = 0, keysHref }) => /* @__PURE__ */ React7.createElement(Box7, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, limits.map((limit) => /* @__PURE__ */ React7.createElement(TaggedLimit, { key: `${limit.kind}:${limit.sublabel ?? limit.label}`, limit })), hiddenKeyCount > 0 && /* @__PURE__ */ React7.createElement(MoreKeysNote, { count: hiddenKeyCount, href: keysHref }));
3046
- LimitListPanel = ({ children }) => /* @__PURE__ */ React7.createElement(
3080
+ BudgetLimitList = ({ limits, hiddenKeyCount = 0, keysHref }) => /* @__PURE__ */ React8.createElement(Box7, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, limits.map((limit) => /* @__PURE__ */ React8.createElement(TaggedLimit, { key: `${limit.kind}:${limit.sublabel ?? limit.label}`, limit })), hiddenKeyCount > 0 && /* @__PURE__ */ React8.createElement(MoreKeysNote, { count: hiddenKeyCount, href: keysHref }));
3081
+ LimitListPanel = ({ children }) => /* @__PURE__ */ React8.createElement(
3047
3082
  Box7,
3048
3083
  {
3049
3084
  sx: (theme) => ({
@@ -3059,7 +3094,7 @@ var init_BudgetLimitList = __esm({
3059
3094
  });
3060
3095
 
3061
3096
  // src/components/LiteLLMBudgetWidget.tsx
3062
- import React8, { useEffect as useEffect3, useMemo as useMemo6, useState as useState5 } from "react";
3097
+ import React9, { useEffect as useEffect3, useMemo as useMemo6, useState as useState5 } from "react";
3063
3098
  import Paper6 from "@mui/material/Paper";
3064
3099
  import Box8 from "@mui/material/Box";
3065
3100
  import Typography8 from "@mui/material/Typography";
@@ -3086,7 +3121,7 @@ var init_LiteLLMBudgetWidget = __esm({
3086
3121
  tone,
3087
3122
  isLast,
3088
3123
  children
3089
- }) => /* @__PURE__ */ React8.createElement(Box8, { sx: { display: "flex", gap: 1.5 } }, /* @__PURE__ */ React8.createElement(Box8, { sx: { display: "flex", flexDirection: "column", alignItems: "center", width: 26, flexShrink: 0 } }, /* @__PURE__ */ React8.createElement(
3124
+ }) => /* @__PURE__ */ React9.createElement(Box8, { sx: { display: "flex", gap: 1.5 } }, /* @__PURE__ */ React9.createElement(Box8, { sx: { display: "flex", flexDirection: "column", alignItems: "center", width: 26, flexShrink: 0 } }, /* @__PURE__ */ React9.createElement(
3090
3125
  Box8,
3091
3126
  {
3092
3127
  sx: (theme) => ({
@@ -3104,7 +3139,7 @@ var init_LiteLLMBudgetWidget = __esm({
3104
3139
  })
3105
3140
  },
3106
3141
  rank
3107
- ), /* @__PURE__ */ React8.createElement(
3142
+ ), /* @__PURE__ */ React9.createElement(
3108
3143
  Box8,
3109
3144
  {
3110
3145
  sx: (theme) => ({
@@ -3114,7 +3149,7 @@ var init_LiteLLMBudgetWidget = __esm({
3114
3149
  bgcolor: isLast ? "transparent" : alpha5(theme.palette.text.primary, 0.12)
3115
3150
  })
3116
3151
  }
3117
- )), /* @__PURE__ */ React8.createElement(Box8, { sx: { flex: 1, minWidth: 0, pb: isLast ? 0 : 2 } }, /* @__PURE__ */ React8.createElement(Box8, { sx: { display: "flex", alignItems: "baseline", gap: 1, flexWrap: "wrap", mb: 0.75 } }, /* @__PURE__ */ React8.createElement(
3152
+ )), /* @__PURE__ */ React9.createElement(Box8, { sx: { flex: 1, minWidth: 0, pb: isLast ? 0 : 2 } }, /* @__PURE__ */ React9.createElement(Box8, { sx: { display: "flex", alignItems: "baseline", gap: 1, flexWrap: "wrap", mb: 0.75 } }, /* @__PURE__ */ React9.createElement(
3118
3153
  Typography8,
3119
3154
  {
3120
3155
  sx: (theme) => ({
@@ -3126,8 +3161,8 @@ var init_LiteLLMBudgetWidget = __esm({
3126
3161
  })
3127
3162
  },
3128
3163
  name
3129
- ), /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontSize: 11.5 } }, tagline), note && /* @__PURE__ */ React8.createElement(StatusPill, { label: note, tone: "neutral", dot: false, sx: { ml: "auto" } })), /* @__PURE__ */ React8.createElement(Box8, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, children)));
3130
- EmptyLimitCard = ({ children }) => /* @__PURE__ */ React8.createElement(
3164
+ ), /* @__PURE__ */ React9.createElement(Typography8, { variant: "caption", color: "text.secondary", sx: { fontSize: 11.5 } }, tagline), note && /* @__PURE__ */ React9.createElement(StatusPill, { label: note, tone: "neutral", dot: false, sx: { ml: "auto" } })), /* @__PURE__ */ React9.createElement(Box8, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, children)));
3165
+ EmptyLimitCard = ({ children }) => /* @__PURE__ */ React9.createElement(
3131
3166
  Paper6,
3132
3167
  {
3133
3168
  variant: "outlined",
@@ -3138,7 +3173,7 @@ var init_LiteLLMBudgetWidget = __esm({
3138
3173
  bgcolor: alpha5(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.03 : 0.015)
3139
3174
  })
3140
3175
  },
3141
- /* @__PURE__ */ React8.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, children)
3176
+ /* @__PURE__ */ React9.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, children)
3142
3177
  );
3143
3178
  CLOSEST_LEVEL_LABEL = {
3144
3179
  key: "key",
@@ -3146,7 +3181,7 @@ var init_LiteLLMBudgetWidget = __esm({
3146
3181
  team: "team"
3147
3182
  };
3148
3183
  KEYS_PATH = "/litellm?tab=keys";
3149
- HierarchyNote = ({ withReset }) => /* @__PURE__ */ React8.createElement(
3184
+ HierarchyNote = ({ withReset }) => /* @__PURE__ */ React9.createElement(
3150
3185
  Box8,
3151
3186
  {
3152
3187
  sx: (theme) => ({
@@ -3157,11 +3192,11 @@ var init_LiteLLMBudgetWidget = __esm({
3157
3192
  borderColor: alpha5(theme.palette.text.primary, 0.18)
3158
3193
  })
3159
3194
  },
3160
- /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary", display: "block" }, /* @__PURE__ */ React8.createElement("b", null, "Order:"), " key \u2192 personal \u2192 team \u2192 global. The first cap you reach blocks the request; a key that belongs to a team uses the team's cap, not your personal one.", withReset && " A cap with a reset window drops to $0 when the window closes; without one it never resets.")
3195
+ /* @__PURE__ */ React9.createElement(Typography8, { variant: "caption", color: "text.secondary", display: "block" }, /* @__PURE__ */ React9.createElement("b", null, "Order:"), " key \u2192 personal \u2192 team \u2192 global. The first cap you reach blocks the request; a key that belongs to a team uses the team's cap, not your personal one.", withReset && " A cap with a reset window drops to $0 when the window closes; without one it never resets.")
3161
3196
  );
3162
3197
  FullBody = ({ summary }) => {
3163
3198
  const hasBudgetedKeys = summary.keys.length + summary.hiddenBudgetedKeys > 0;
3164
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(
3199
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
3165
3200
  LevelFrame,
3166
3201
  {
3167
3202
  rank: 1,
@@ -3169,10 +3204,10 @@ var init_LiteLLMBudgetWidget = __esm({
3169
3204
  tagline: "per-key cap \xB7 highest priority",
3170
3205
  note: hasBudgetedKeys ? void 0 : "no key budgets set"
3171
3206
  },
3172
- !hasBudgetedKeys && /* @__PURE__ */ React8.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3173
- summary.keys.map((k) => /* @__PURE__ */ React8.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3174
- summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ React8.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH })
3175
- ), /* @__PURE__ */ React8.createElement(
3207
+ !hasBudgetedKeys && /* @__PURE__ */ React9.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3208
+ summary.keys.map((k) => /* @__PURE__ */ React9.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3209
+ summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ React9.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH })
3210
+ ), /* @__PURE__ */ React9.createElement(
3176
3211
  LevelFrame,
3177
3212
  {
3178
3213
  rank: 2,
@@ -3180,15 +3215,15 @@ var init_LiteLLMBudgetWidget = __esm({
3180
3215
  tagline: "cap on everything you spend with your own keys",
3181
3216
  note: "skipped for team-bound keys"
3182
3217
  },
3183
- summary.user ? /* @__PURE__ */ React8.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ React8.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3184
- ), /* @__PURE__ */ React8.createElement(LevelFrame, { rank: 3, name: "Team", tagline: "shared cap for all keys in a team (if any)" }, summary.teams.length > 0 ? summary.teams.map((t) => /* @__PURE__ */ React8.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ React8.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ React8.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ React8.createElement(EmptyLimitCard, null, "Configured by your admin in the proxy config \u2014 it isn't visible from this page. When set, it limits spend across every request on the proxy.")), /* @__PURE__ */ React8.createElement(Box8, { sx: { mt: 2 } }, /* @__PURE__ */ React8.createElement(HierarchyNote, { withReset: true })));
3218
+ summary.user ? /* @__PURE__ */ React9.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ React9.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3219
+ ), /* @__PURE__ */ React9.createElement(LevelFrame, { rank: 3, name: "Team", tagline: "shared cap for all keys in a team (if any)" }, summary.teams.length > 0 ? summary.teams.map((t) => /* @__PURE__ */ React9.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ React9.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ React9.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ React9.createElement(EmptyLimitCard, null, "Configured by your admin in the proxy config \u2014 it isn't visible from this page. When set, it limits spend across every request on the proxy.")), /* @__PURE__ */ React9.createElement(Box8, { sx: { mt: 2 } }, /* @__PURE__ */ React9.createElement(HierarchyNote, { withReset: true })));
3185
3220
  };
3186
3221
  CompactBody = ({ summary }) => {
3187
3222
  const { count } = budgetHeadline(summary);
3188
3223
  if (count === 0) {
3189
- return /* @__PURE__ */ React8.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3224
+ return /* @__PURE__ */ React9.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3190
3225
  }
3191
- return /* @__PURE__ */ React8.createElement(Box8, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, /* @__PURE__ */ React8.createElement(HierarchyNote, null), summary.keys.map((k) => /* @__PURE__ */ React8.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ React8.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH }), summary.user && /* @__PURE__ */ React8.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ React8.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3226
+ return /* @__PURE__ */ React9.createElement(Box8, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, /* @__PURE__ */ React9.createElement(HierarchyNote, null), summary.keys.map((k) => /* @__PURE__ */ React9.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ React9.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH }), summary.user && /* @__PURE__ */ React9.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ React9.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3192
3227
  };
3193
3228
  LiteLLMBudgetWidget = ({
3194
3229
  title = "Budget Policy",
@@ -3239,8 +3274,8 @@ var init_LiteLLMBudgetWidget = __esm({
3239
3274
  headline.closest.pct
3240
3275
  )}%`;
3241
3276
  const summaryText = headline.count === 0 ? "no limits apply" : `${limitsWord}${closestWord}`;
3242
- const body = /* @__PURE__ */ React8.createElement(React8.Fragment, null, loading && /* @__PURE__ */ React8.createElement(Box8, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 140 }, /* @__PURE__ */ React8.createElement(CircularProgress4, { size: 32 })), !loading && error && /* @__PURE__ */ React8.createElement(Alert3, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && (compact ? /* @__PURE__ */ React8.createElement(CompactBody, { summary }) : /* @__PURE__ */ React8.createElement(FullBody, { summary })));
3243
- return /* @__PURE__ */ React8.createElement(Paper6, { sx: { p: 2 } }, collapsible ? /* @__PURE__ */ React8.createElement(
3277
+ const body = /* @__PURE__ */ React9.createElement(React9.Fragment, null, loading && /* @__PURE__ */ React9.createElement(Box8, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 140 }, /* @__PURE__ */ React9.createElement(CircularProgress4, { size: 32 })), !loading && error && /* @__PURE__ */ React9.createElement(Alert3, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && (compact ? /* @__PURE__ */ React9.createElement(CompactBody, { summary }) : /* @__PURE__ */ React9.createElement(FullBody, { summary })));
3278
+ return /* @__PURE__ */ React9.createElement(Paper6, { sx: { p: 2 } }, collapsible ? /* @__PURE__ */ React9.createElement(
3244
3279
  Box8,
3245
3280
  {
3246
3281
  onClick: () => setExpanded((e) => !e),
@@ -3253,14 +3288,14 @@ var init_LiteLLMBudgetWidget = __esm({
3253
3288
  mb: expanded ? 1.5 : 0
3254
3289
  }
3255
3290
  },
3256
- /* @__PURE__ */ React8.createElement(Box8, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ React8.createElement(Typography8, { variant: "h6", lineHeight: 1.2 }, title), !loading && !error && /* @__PURE__ */ React8.createElement(Box8, { sx: { mt: 0.5 } }, /* @__PURE__ */ React8.createElement(
3291
+ /* @__PURE__ */ React9.createElement(Box8, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ React9.createElement(Typography8, { variant: "h6", lineHeight: 1.2 }, title), !loading && !error && /* @__PURE__ */ React9.createElement(Box8, { sx: { mt: 0.5 } }, /* @__PURE__ */ React9.createElement(
3257
3292
  StatusPill,
3258
3293
  {
3259
3294
  label: summaryText,
3260
3295
  tone: budgetTone2(headline.closest?.pct ?? 0)
3261
3296
  }
3262
3297
  ))),
3263
- /* @__PURE__ */ React8.createElement(
3298
+ /* @__PURE__ */ React9.createElement(
3264
3299
  IconButton4,
3265
3300
  {
3266
3301
  size: "small",
@@ -3276,9 +3311,9 @@ var init_LiteLLMBudgetWidget = __esm({
3276
3311
  transition: theme.transitions.create("transform")
3277
3312
  })
3278
3313
  },
3279
- /* @__PURE__ */ React8.createElement(ExpandMore2, null)
3314
+ /* @__PURE__ */ React9.createElement(ExpandMore2, null)
3280
3315
  )
3281
- ) : /* @__PURE__ */ React8.createElement(Box8, { sx: { mb: 1.5 } }, /* @__PURE__ */ React8.createElement(Typography8, { variant: "h6", lineHeight: 1.2 }, title), /* @__PURE__ */ React8.createElement(Typography8, { variant: "caption", color: "text.secondary" }, "How LiteLLM caps spend \u2014 and where you stand right now")), collapsible ? /* @__PURE__ */ React8.createElement(Collapse, { in: expanded, unmountOnExit: true }, body) : body, action && /* @__PURE__ */ React8.createElement(
3316
+ ) : /* @__PURE__ */ React9.createElement(Box8, { sx: { mb: 1.5 } }, /* @__PURE__ */ React9.createElement(Typography8, { variant: "h6", lineHeight: 1.2 }, title), /* @__PURE__ */ React9.createElement(Typography8, { variant: "caption", color: "text.secondary" }, "How LiteLLM caps spend \u2014 and where you stand right now")), collapsible ? /* @__PURE__ */ React9.createElement(Collapse, { in: expanded, unmountOnExit: true }, body) : body, action && /* @__PURE__ */ React9.createElement(
3282
3317
  Box8,
3283
3318
  {
3284
3319
  sx: (theme) => ({
@@ -3294,7 +3329,7 @@ var init_LiteLLMBudgetWidget = __esm({
3294
3329
  });
3295
3330
 
3296
3331
  // src/components/TeamUsage.tsx
3297
- import React9, { useState as useState6 } from "react";
3332
+ import React10, { useState as useState6 } from "react";
3298
3333
  import Paper7 from "@mui/material/Paper";
3299
3334
  import Box9 from "@mui/material/Box";
3300
3335
  import Typography9 from "@mui/material/Typography";
@@ -3311,7 +3346,7 @@ import IconButton5 from "@mui/material/IconButton";
3311
3346
  import Button5 from "@mui/material/Button";
3312
3347
  import CircularProgress5 from "@mui/material/CircularProgress";
3313
3348
  import { alpha as alpha6 } from "@mui/material/styles";
3314
- import { ExpandMore as ExpandMore3, Group, Add as Add3 } from "@mui/icons-material";
3349
+ import { ExpandMore as ExpandMore3, Group, Add as Add2 } from "@mui/icons-material";
3315
3350
  import {
3316
3351
  AreaChart as AreaChart2,
3317
3352
  Area as Area2,
@@ -3354,10 +3389,10 @@ var init_TeamUsage = __esm({
3354
3389
  const renderDailySpendSection = () => {
3355
3390
  if (hidden) return null;
3356
3391
  if (usageLoading) {
3357
- return /* @__PURE__ */ React9.createElement(Box9, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ React9.createElement(CircularProgress5, { size: 22 }));
3392
+ return /* @__PURE__ */ React10.createElement(Box9, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ React10.createElement(CircularProgress5, { size: 22 }));
3358
3393
  }
3359
3394
  if (dailyData.length === 0) return null;
3360
- return /* @__PURE__ */ React9.createElement(Box9, { mb: 2.5 }, /* @__PURE__ */ React9.createElement(
3395
+ return /* @__PURE__ */ React10.createElement(Box9, { mb: 2.5 }, /* @__PURE__ */ React10.createElement(
3361
3396
  Typography9,
3362
3397
  {
3363
3398
  variant: "caption",
@@ -3365,13 +3400,13 @@ var init_TeamUsage = __esm({
3365
3400
  sx: { display: "block", fontSize: 11, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase", mb: 1 }
3366
3401
  },
3367
3402
  "Daily spend"
3368
- ), /* @__PURE__ */ React9.createElement(Box9, { height: 150 }, /* @__PURE__ */ React9.createElement(ResponsiveContainer2, { width: "100%", height: "100%" }, /* @__PURE__ */ React9.createElement(AreaChart2, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React9.createElement(CartesianGrid2, { ...chart.grid }), /* @__PURE__ */ React9.createElement(XAxis2, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React9.createElement(YAxis2, { tickFormatter: fmtUsdCompact, width: 52, ...chart.axis }), /* @__PURE__ */ React9.createElement(
3403
+ ), /* @__PURE__ */ React10.createElement(Box9, { height: 150 }, /* @__PURE__ */ React10.createElement(ResponsiveContainer2, { width: "100%", height: "100%" }, /* @__PURE__ */ React10.createElement(AreaChart2, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ React10.createElement(CartesianGrid2, { ...chart.grid }), /* @__PURE__ */ React10.createElement(XAxis2, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ React10.createElement(YAxis2, { tickFormatter: fmtUsdCompact, width: 52, ...chart.axis }), /* @__PURE__ */ React10.createElement(
3369
3404
  Tooltip2,
3370
3405
  {
3371
3406
  cursor: chart.cursor,
3372
- content: /* @__PURE__ */ React9.createElement(ChartTooltip, { valueFormatter: (v) => `$${v.toFixed(4)}` })
3407
+ content: /* @__PURE__ */ React10.createElement(ChartTooltip, { valueFormatter: (v) => `$${v.toFixed(4)}` })
3373
3408
  }
3374
- ), /* @__PURE__ */ React9.createElement(
3409
+ ), /* @__PURE__ */ React10.createElement(
3375
3410
  Area2,
3376
3411
  {
3377
3412
  type: "monotone",
@@ -3384,7 +3419,7 @@ var init_TeamUsage = __esm({
3384
3419
  }
3385
3420
  )))));
3386
3421
  };
3387
- const sectionLabel = (label) => /* @__PURE__ */ React9.createElement(
3422
+ const sectionLabel = (label) => /* @__PURE__ */ React10.createElement(
3388
3423
  Typography9,
3389
3424
  {
3390
3425
  variant: "caption",
@@ -3393,7 +3428,7 @@ var init_TeamUsage = __esm({
3393
3428
  },
3394
3429
  label
3395
3430
  );
3396
- return /* @__PURE__ */ React9.createElement(Paper7, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 } }, /* @__PURE__ */ React9.createElement(Box9, { display: "flex", alignItems: "center", gap: 1.5 }, /* @__PURE__ */ React9.createElement(
3431
+ return /* @__PURE__ */ React10.createElement(Paper7, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 } }, /* @__PURE__ */ React10.createElement(Box9, { display: "flex", alignItems: "center", gap: 1.5 }, /* @__PURE__ */ React10.createElement(
3397
3432
  Box9,
3398
3433
  {
3399
3434
  sx: (theme) => ({
@@ -3408,8 +3443,8 @@ var init_TeamUsage = __esm({
3408
3443
  color: theme.palette.primary.main
3409
3444
  })
3410
3445
  },
3411
- /* @__PURE__ */ React9.createElement(Group, { fontSize: "small" })
3412
- ), /* @__PURE__ */ React9.createElement(Box9, { flexGrow: 1, minWidth: 0 }, /* @__PURE__ */ React9.createElement(Typography9, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.3 } }, team.team_alias || "Untitled team"), /* @__PURE__ */ React9.createElement(
3446
+ /* @__PURE__ */ React10.createElement(Group, { fontSize: "small" })
3447
+ ), /* @__PURE__ */ React10.createElement(Box9, { flexGrow: 1, minWidth: 0 }, /* @__PURE__ */ React10.createElement(Typography9, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.3 } }, team.team_alias || "Untitled team"), /* @__PURE__ */ React10.createElement(
3413
3448
  Typography9,
3414
3449
  {
3415
3450
  variant: "caption",
@@ -3417,7 +3452,7 @@ var init_TeamUsage = __esm({
3417
3452
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
3418
3453
  },
3419
3454
  team.team_id
3420
- )), isOver && /* @__PURE__ */ React9.createElement(StatusPill, { label: "Over budget", tone: "danger" }), isNear && /* @__PURE__ */ React9.createElement(StatusPill, { label: "Near limit", tone: "warning" }), canManage && onEditTeam && /* @__PURE__ */ React9.createElement(
3455
+ )), isOver && /* @__PURE__ */ React10.createElement(StatusPill, { label: "Over budget", tone: "danger" }), isNear && /* @__PURE__ */ React10.createElement(StatusPill, { label: "Near limit", tone: "warning" }), canManage && onEditTeam && /* @__PURE__ */ React10.createElement(
3421
3456
  Button5,
3422
3457
  {
3423
3458
  size: "small",
@@ -3426,7 +3461,7 @@ var init_TeamUsage = __esm({
3426
3461
  sx: { textTransform: "none" }
3427
3462
  },
3428
3463
  "Edit"
3429
- ), /* @__PURE__ */ React9.createElement(
3464
+ ), /* @__PURE__ */ React10.createElement(
3430
3465
  IconButton5,
3431
3466
  {
3432
3467
  size: "small",
@@ -3439,8 +3474,8 @@ var init_TeamUsage = __esm({
3439
3474
  transition: theme.transitions.create("transform")
3440
3475
  })
3441
3476
  },
3442
- /* @__PURE__ */ React9.createElement(ExpandMore3, null)
3443
- )), /* @__PURE__ */ React9.createElement(
3477
+ /* @__PURE__ */ React10.createElement(ExpandMore3, null)
3478
+ )), /* @__PURE__ */ React10.createElement(
3444
3479
  Box9,
3445
3480
  {
3446
3481
  sx: {
@@ -3451,20 +3486,20 @@ var init_TeamUsage = __esm({
3451
3486
  maxWidth: 640
3452
3487
  }
3453
3488
  },
3454
- /* @__PURE__ */ React9.createElement(Stat, { label: "Members", value: team.members_with_roles?.length ?? "\u2014" }),
3455
- /* @__PURE__ */ React9.createElement(Stat, { label: "Models", value: team.models?.length ? team.models.length : "All" }),
3456
- /* @__PURE__ */ React9.createElement(Stat, { label: "Budget", value: budgetStatValue(hidden, budget) }),
3457
- /* @__PURE__ */ React9.createElement(Stat, { label: "Spend", value: hidden ? "\u2014" : fmtUsd2(spend) }),
3458
- /* @__PURE__ */ React9.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
3459
- /* @__PURE__ */ React9.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
3460
- ), hidden && /* @__PURE__ */ React9.createElement(Box9, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React9.createElement(Box9, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React9.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "% used"), /* @__PURE__ */ React9.createElement(Typography9, { variant: "caption", color: "text.secondary" }, "Hidden by admin")), /* @__PURE__ */ React9.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 }), /* @__PURE__ */ React9.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { display: "block", mt: 0.75 } }, "Team budget is hidden \u2014 showing usage level only", team.budget_duration ? ` \xB7 resets every ${team.budget_duration}` : "", ".")), !hidden && budget > 0 && /* @__PURE__ */ React9.createElement(Box9, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React9.createElement(Box9, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React9.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ React9.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ React9.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 })), /* @__PURE__ */ React9.createElement(Collapse2, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ React9.createElement(Divider3, { sx: { my: 2.5 } }), /* @__PURE__ */ React9.createElement(Box9, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ React9.createElement(Box9, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ React9.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ React9.createElement(Typography9, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ React9.createElement(Box9, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ React9.createElement(
3489
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Members", value: team.members_with_roles?.length ?? "\u2014" }),
3490
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Models", value: team.models?.length ? team.models.length : "All" }),
3491
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Budget", value: budgetStatValue(hidden, budget) }),
3492
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Spend", value: hidden ? "\u2014" : fmtUsd2(spend) }),
3493
+ /* @__PURE__ */ React10.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
3494
+ /* @__PURE__ */ React10.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
3495
+ ), hidden && /* @__PURE__ */ React10.createElement(Box9, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React10.createElement(Box9, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React10.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "% used"), /* @__PURE__ */ React10.createElement(Typography9, { variant: "caption", color: "text.secondary" }, "Hidden by admin")), /* @__PURE__ */ React10.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 }), /* @__PURE__ */ React10.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { display: "block", mt: 0.75 } }, "Team budget is hidden \u2014 showing usage level only", team.budget_duration ? ` \xB7 resets every ${team.budget_duration}` : "", ".")), !hidden && budget > 0 && /* @__PURE__ */ React10.createElement(Box9, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ React10.createElement(Box9, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ React10.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ React10.createElement(Typography9, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ React10.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 })), /* @__PURE__ */ React10.createElement(Collapse2, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ React10.createElement(Divider3, { sx: { my: 2.5 } }), /* @__PURE__ */ React10.createElement(Box9, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ React10.createElement(Box9, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ React10.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ React10.createElement(Typography9, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ React10.createElement(Box9, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ React10.createElement(
3461
3496
  TableContainer4,
3462
3497
  {
3463
3498
  component: Paper7,
3464
3499
  variant: "outlined",
3465
3500
  sx: { borderRadius: 1.5 }
3466
3501
  },
3467
- /* @__PURE__ */ React9.createElement(Table4, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React9.createElement(TableHead4, null, /* @__PURE__ */ React9.createElement(TableRow4, null, /* @__PURE__ */ React9.createElement(TableCell4, null, "User"), /* @__PURE__ */ React9.createElement(TableCell4, { align: "right" }, "Role"))), /* @__PURE__ */ React9.createElement(TableBody4, null, team.members_with_roles.map((m) => /* @__PURE__ */ React9.createElement(TableRow4, { key: m.user_id }, /* @__PURE__ */ React9.createElement(TableCell4, null, m.user_email ? /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Typography9, { variant: "body2" }, m.user_email), /* @__PURE__ */ React9.createElement(
3502
+ /* @__PURE__ */ React10.createElement(Table4, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React10.createElement(TableHead4, null, /* @__PURE__ */ React10.createElement(TableRow4, null, /* @__PURE__ */ React10.createElement(TableCell4, null, "User"), /* @__PURE__ */ React10.createElement(TableCell4, { align: "right" }, "Role"))), /* @__PURE__ */ React10.createElement(TableBody4, null, team.members_with_roles.map((m) => /* @__PURE__ */ React10.createElement(TableRow4, { key: m.user_id }, /* @__PURE__ */ React10.createElement(TableCell4, null, m.user_email ? /* @__PURE__ */ React10.createElement(React10.Fragment, null, /* @__PURE__ */ React10.createElement(Typography9, { variant: "body2" }, m.user_email), /* @__PURE__ */ React10.createElement(
3468
3503
  Typography9,
3469
3504
  {
3470
3505
  variant: "caption",
@@ -3472,14 +3507,14 @@ var init_TeamUsage = __esm({
3472
3507
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
3473
3508
  },
3474
3509
  m.user_id
3475
- )) : /* @__PURE__ */ React9.createElement(
3510
+ )) : /* @__PURE__ */ React10.createElement(
3476
3511
  Typography9,
3477
3512
  {
3478
3513
  variant: "body2",
3479
3514
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
3480
3515
  },
3481
3516
  m.user_id
3482
- )), /* @__PURE__ */ React9.createElement(TableCell4, { align: "right" }, /* @__PURE__ */ React9.createElement(
3517
+ )), /* @__PURE__ */ React10.createElement(TableCell4, { align: "right" }, /* @__PURE__ */ React10.createElement(
3483
3518
  StatusPill,
3484
3519
  {
3485
3520
  label: m.role,
@@ -3487,7 +3522,7 @@ var init_TeamUsage = __esm({
3487
3522
  dot: false
3488
3523
  }
3489
3524
  ))))))
3490
- ) : /* @__PURE__ */ React9.createElement(Typography9, { variant: "body2", color: "text.secondary" }, "No members assigned."))));
3525
+ ) : /* @__PURE__ */ React10.createElement(Typography9, { variant: "body2", color: "text.secondary" }, "No members assigned."))));
3491
3526
  };
3492
3527
  TeamUsage = ({
3493
3528
  teams,
@@ -3499,22 +3534,22 @@ var init_TeamUsage = __esm({
3499
3534
  canCreate,
3500
3535
  onCreateTeam
3501
3536
  }) => {
3502
- const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ React9.createElement(
3537
+ const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ React10.createElement(
3503
3538
  Button5,
3504
3539
  {
3505
3540
  variant: "contained",
3506
3541
  color: "primary",
3507
3542
  disableElevation: true,
3508
- startIcon: /* @__PURE__ */ React9.createElement(Add3, null),
3543
+ startIcon: /* @__PURE__ */ React10.createElement(Add2, null),
3509
3544
  onClick: onCreateTeam
3510
3545
  },
3511
3546
  "Create Team"
3512
3547
  ) : void 0;
3513
3548
  if (loading) {
3514
- return /* @__PURE__ */ React9.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ React9.createElement(Skeleton4, { variant: "rounded", height: 120, sx: { mb: 2 } }), /* @__PURE__ */ React9.createElement(Skeleton4, { variant: "rounded", height: 120 }));
3549
+ return /* @__PURE__ */ React10.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ React10.createElement(Skeleton4, { variant: "rounded", height: 120, sx: { mb: 2 } }), /* @__PURE__ */ React10.createElement(Skeleton4, { variant: "rounded", height: 120 }));
3515
3550
  }
3516
3551
  if (!teams.length) {
3517
- return /* @__PURE__ */ React9.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ React9.createElement(
3552
+ return /* @__PURE__ */ React10.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ React10.createElement(
3518
3553
  EmptyState,
3519
3554
  {
3520
3555
  message: "You're not a member of any LiteLLM team yet.",
@@ -3522,14 +3557,14 @@ var init_TeamUsage = __esm({
3522
3557
  }
3523
3558
  ));
3524
3559
  }
3525
- return /* @__PURE__ */ React9.createElement(
3560
+ return /* @__PURE__ */ React10.createElement(
3526
3561
  SectionCard,
3527
3562
  {
3528
3563
  title: "Teams",
3529
3564
  subtitle: `${teams.length} team${teams.length === 1 ? "" : "s"}`,
3530
3565
  actions: createAction
3531
3566
  },
3532
- /* @__PURE__ */ React9.createElement(Box9, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ React9.createElement(
3567
+ /* @__PURE__ */ React10.createElement(Box9, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ React10.createElement(
3533
3568
  TeamCard,
3534
3569
  {
3535
3570
  key: team.team_id,
@@ -3546,7 +3581,7 @@ var init_TeamUsage = __esm({
3546
3581
  });
3547
3582
 
3548
3583
  // src/components/ModelsTable.tsx
3549
- import React10, { useState as useState7, useMemo as useMemo7, useCallback } from "react";
3584
+ import React11, { useState as useState7, useMemo as useMemo7, useCallback } from "react";
3550
3585
  import Box10 from "@mui/material/Box";
3551
3586
  import Table5 from "@mui/material/Table";
3552
3587
  import TableBody5 from "@mui/material/TableBody";
@@ -3678,13 +3713,13 @@ var init_ModelsTable = __esm({
3678
3713
  return theme.palette.info.main;
3679
3714
  }
3680
3715
  };
3681
- return /* @__PURE__ */ React10.createElement(
3716
+ return /* @__PURE__ */ React11.createElement(
3682
3717
  SectionCard,
3683
3718
  {
3684
3719
  title: "Available Models",
3685
3720
  subtitle: selectedTeam ? `${filteredModels.length}${filterText.trim() ? ` of ${teamModels.length}` : ""} model${filteredModels.length === 1 ? "" : "s"}` : "Select a team to view its models"
3686
3721
  },
3687
- /* @__PURE__ */ React10.createElement(Box10, { sx: { px: 2.5, pb: 2.5, pt: 1, display: "flex", gap: 2, flexWrap: "wrap" } }, /* @__PURE__ */ React10.createElement(FormControl, { size: "small", sx: { minWidth: 240, mb: 2 } }, /* @__PURE__ */ React10.createElement(InputLabel, { id: "team-select-label" }, "Team"), /* @__PURE__ */ React10.createElement(
3722
+ /* @__PURE__ */ React11.createElement(Box10, { sx: { px: 2.5, pb: 2.5, pt: 1, display: "flex", gap: 2, flexWrap: "wrap" } }, /* @__PURE__ */ React11.createElement(FormControl, { size: "small", sx: { minWidth: 240, mb: 2 } }, /* @__PURE__ */ React11.createElement(InputLabel, { id: "team-select-label" }, "Team"), /* @__PURE__ */ React11.createElement(
3688
3723
  Select,
3689
3724
  {
3690
3725
  labelId: "team-select-label",
@@ -3692,8 +3727,8 @@ var init_ModelsTable = __esm({
3692
3727
  label: "Team",
3693
3728
  onChange: (e) => setSelectedTeamId(e.target.value)
3694
3729
  },
3695
- teams.map((t) => /* @__PURE__ */ React10.createElement(MenuItem4, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
3696
- )), /* @__PURE__ */ React10.createElement(
3730
+ teams.map((t) => /* @__PURE__ */ React11.createElement(MenuItem4, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
3731
+ )), /* @__PURE__ */ React11.createElement(
3697
3732
  TextField5,
3698
3733
  {
3699
3734
  label: "Filter Models",
@@ -3703,33 +3738,33 @@ var init_ModelsTable = __esm({
3703
3738
  disabled: !selectedTeamId,
3704
3739
  sx: { minWidth: 240, mb: 2 },
3705
3740
  InputProps: {
3706
- startAdornment: /* @__PURE__ */ React10.createElement(InputAdornment2, { position: "start" }, /* @__PURE__ */ React10.createElement(Search2, { fontSize: "small" }))
3741
+ startAdornment: /* @__PURE__ */ React11.createElement(InputAdornment2, { position: "start" }, /* @__PURE__ */ React11.createElement(Search2, { fontSize: "small" }))
3707
3742
  }
3708
3743
  }
3709
3744
  )),
3710
- loading && /* @__PURE__ */ React10.createElement(EmptyState, { message: "Loading models\u2026" }),
3711
- !loading && !selectedTeamId && /* @__PURE__ */ React10.createElement(
3745
+ loading && /* @__PURE__ */ React11.createElement(EmptyState, { message: "Loading models\u2026" }),
3746
+ !loading && !selectedTeamId && /* @__PURE__ */ React11.createElement(
3712
3747
  EmptyState,
3713
3748
  {
3714
3749
  message: "Select a team to see available models",
3715
3750
  hint: "Each team may have a different set of models assigned"
3716
3751
  }
3717
3752
  ),
3718
- !loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ React10.createElement(
3753
+ !loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ React11.createElement(
3719
3754
  EmptyState,
3720
3755
  {
3721
3756
  message: "No models available for this team",
3722
3757
  hint: allModels.length === 0 ? "No models are configured in the system" : "None of the team's assigned models were found in the catalog"
3723
3758
  }
3724
3759
  ),
3725
- !loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ React10.createElement(
3760
+ !loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ React11.createElement(
3726
3761
  EmptyState,
3727
3762
  {
3728
3763
  message: "No models match your search",
3729
3764
  hint: "Try a different search term"
3730
3765
  }
3731
3766
  ),
3732
- !loading && filteredModels.length > 0 && /* @__PURE__ */ React10.createElement(TableContainer5, null, /* @__PURE__ */ React10.createElement(Table5, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React10.createElement(TableHead5, null, /* @__PURE__ */ React10.createElement(TableRow5, null, /* @__PURE__ */ React10.createElement(TableCell5, { sortDirection: sortKey === "model_name" ? sortDirection : false }, /* @__PURE__ */ React10.createElement(TableSortLabel2, { active: sortKey === "model_name", direction: sortKey === "model_name" ? sortDirection : "asc", onClick: () => handleSort("model_name") }, "Model ID")), /* @__PURE__ */ React10.createElement(TableCell5, { sortDirection: sortKey === "mode" ? sortDirection : false }, /* @__PURE__ */ React10.createElement(TableSortLabel2, { active: sortKey === "mode", direction: sortKey === "mode" ? sortDirection : "asc", onClick: () => handleSort("mode") }, "Mode")), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right", sortDirection: sortKey === "input_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ React10.createElement(TableSortLabel2, { active: sortKey === "input_cost_per_token", direction: sortKey === "input_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("input_cost_per_token") }, "Input Cost")), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right", sortDirection: sortKey === "output_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ React10.createElement(TableSortLabel2, { active: sortKey === "output_cost_per_token", direction: sortKey === "output_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("output_cost_per_token") }, "Output Cost")), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right", sortDirection: sortKey === "max_input_tokens" ? sortDirection : false }, /* @__PURE__ */ React10.createElement(TableSortLabel2, { active: sortKey === "max_input_tokens", direction: sortKey === "max_input_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_input_tokens") }, "Max Input")), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right", sortDirection: sortKey === "max_output_tokens" ? sortDirection : false }, /* @__PURE__ */ React10.createElement(TableSortLabel2, { active: sortKey === "max_output_tokens", direction: sortKey === "max_output_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_output_tokens") }, "Max Output")), /* @__PURE__ */ React10.createElement(TableCell5, null, "Capabilities"))), /* @__PURE__ */ React10.createElement(TableBody5, null, filteredModels.map((m) => /* @__PURE__ */ React10.createElement(TableRow5, { key: m.model_name, hover: true }, /* @__PURE__ */ React10.createElement(TableCell5, null, /* @__PURE__ */ React10.createElement(Box10, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React10.createElement(Tooltip3, { title: m.model_name, placement: "top" }, /* @__PURE__ */ React10.createElement(
3767
+ !loading && filteredModels.length > 0 && /* @__PURE__ */ React11.createElement(TableContainer5, null, /* @__PURE__ */ React11.createElement(Table5, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React11.createElement(TableHead5, null, /* @__PURE__ */ React11.createElement(TableRow5, null, /* @__PURE__ */ React11.createElement(TableCell5, { sortDirection: sortKey === "model_name" ? sortDirection : false }, /* @__PURE__ */ React11.createElement(TableSortLabel2, { active: sortKey === "model_name", direction: sortKey === "model_name" ? sortDirection : "asc", onClick: () => handleSort("model_name") }, "Model ID")), /* @__PURE__ */ React11.createElement(TableCell5, { sortDirection: sortKey === "mode" ? sortDirection : false }, /* @__PURE__ */ React11.createElement(TableSortLabel2, { active: sortKey === "mode", direction: sortKey === "mode" ? sortDirection : "asc", onClick: () => handleSort("mode") }, "Mode")), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right", sortDirection: sortKey === "input_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ React11.createElement(TableSortLabel2, { active: sortKey === "input_cost_per_token", direction: sortKey === "input_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("input_cost_per_token") }, "Input Cost")), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right", sortDirection: sortKey === "output_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ React11.createElement(TableSortLabel2, { active: sortKey === "output_cost_per_token", direction: sortKey === "output_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("output_cost_per_token") }, "Output Cost")), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right", sortDirection: sortKey === "max_input_tokens" ? sortDirection : false }, /* @__PURE__ */ React11.createElement(TableSortLabel2, { active: sortKey === "max_input_tokens", direction: sortKey === "max_input_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_input_tokens") }, "Max Input")), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right", sortDirection: sortKey === "max_output_tokens" ? sortDirection : false }, /* @__PURE__ */ React11.createElement(TableSortLabel2, { active: sortKey === "max_output_tokens", direction: sortKey === "max_output_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_output_tokens") }, "Max Output")), /* @__PURE__ */ React11.createElement(TableCell5, null, "Capabilities"))), /* @__PURE__ */ React11.createElement(TableBody5, null, filteredModels.map((m) => /* @__PURE__ */ React11.createElement(TableRow5, { key: m.model_name, hover: true }, /* @__PURE__ */ React11.createElement(TableCell5, null, /* @__PURE__ */ React11.createElement(Box10, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React11.createElement(Tooltip3, { title: m.model_name, placement: "top" }, /* @__PURE__ */ React11.createElement(
3733
3768
  "span",
3734
3769
  {
3735
3770
  role: "button",
@@ -3739,8 +3774,8 @@ var init_ModelsTable = __esm({
3739
3774
  onKeyDown: (e) => e.key === "Enter" && handleCopyModelId(m.model_name),
3740
3775
  style: { cursor: "pointer", display: "inline-flex" }
3741
3776
  },
3742
- /* @__PURE__ */ React10.createElement(TagChip, { label: m.model_name, title: "Copy model ID" })
3743
- )), /* @__PURE__ */ React10.createElement(Tooltip3, { title: "Copy model ID" }, /* @__PURE__ */ React10.createElement(
3777
+ /* @__PURE__ */ React11.createElement(TagChip, { label: m.model_name, title: "Copy model ID" })
3778
+ )), /* @__PURE__ */ React11.createElement(Tooltip3, { title: "Copy model ID" }, /* @__PURE__ */ React11.createElement(
3744
3779
  Box10,
3745
3780
  {
3746
3781
  component: "span",
@@ -3751,8 +3786,8 @@ var init_ModelsTable = __esm({
3751
3786
  sx: quietIconButtonSx("accent"),
3752
3787
  style: { cursor: "pointer", display: "inline-flex" }
3753
3788
  },
3754
- /* @__PURE__ */ React10.createElement(ContentCopyIcon, { sx: { fontSize: 14 } })
3755
- )))), /* @__PURE__ */ React10.createElement(TableCell5, null, /* @__PURE__ */ React10.createElement(
3789
+ /* @__PURE__ */ React11.createElement(ContentCopyIcon, { sx: { fontSize: 14 } })
3790
+ )))), /* @__PURE__ */ React11.createElement(TableCell5, null, /* @__PURE__ */ React11.createElement(
3756
3791
  Box10,
3757
3792
  {
3758
3793
  component: "span",
@@ -3769,8 +3804,8 @@ var init_ModelsTable = __esm({
3769
3804
  }
3770
3805
  },
3771
3806
  m.mode
3772
- )), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React10.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.input_cost_per_token))), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React10.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.output_cost_per_token))), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React10.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_input_tokens))), /* @__PURE__ */ React10.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React10.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_output_tokens))), /* @__PURE__ */ React10.createElement(TableCell5, null, /* @__PURE__ */ React10.createElement(Box10, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" } }, m.supports_function_calling && /* @__PURE__ */ React10.createElement(TagChip, { label: "Fn", title: "Function calling" }), m.supports_vision && /* @__PURE__ */ React10.createElement(TagChip, { label: "\u{1F441}", title: "Vision" })))))))),
3773
- /* @__PURE__ */ React10.createElement(
3807
+ )), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React11.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.input_cost_per_token))), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React11.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.output_cost_per_token))), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React11.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_input_tokens))), /* @__PURE__ */ React11.createElement(TableCell5, { align: "right" }, /* @__PURE__ */ React11.createElement(Typography10, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_output_tokens))), /* @__PURE__ */ React11.createElement(TableCell5, null, /* @__PURE__ */ React11.createElement(Box10, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" } }, m.supports_function_calling && /* @__PURE__ */ React11.createElement(TagChip, { label: "Fn", title: "Function calling" }), m.supports_vision && /* @__PURE__ */ React11.createElement(TagChip, { label: "\u{1F441}", title: "Vision" })))))))),
3808
+ /* @__PURE__ */ React11.createElement(
3774
3809
  Snackbar,
3775
3810
  {
3776
3811
  open: copiedSnackbar,
@@ -3778,7 +3813,7 @@ var init_ModelsTable = __esm({
3778
3813
  onClose: () => setCopiedSnackbar(false),
3779
3814
  anchorOrigin: { vertical: "bottom", horizontal: "center" }
3780
3815
  },
3781
- /* @__PURE__ */ React10.createElement(Alert4, { severity: "success", variant: "filled", sx: { fontSize: 13 } }, "Model ID copied to clipboard")
3816
+ /* @__PURE__ */ React11.createElement(Alert4, { severity: "success", variant: "filled", sx: { fontSize: 13 } }, "Model ID copied to clipboard")
3782
3817
  )
3783
3818
  );
3784
3819
  };
@@ -3786,7 +3821,7 @@ var init_ModelsTable = __esm({
3786
3821
  });
3787
3822
 
3788
3823
  // src/components/AuditLog.tsx
3789
- import React11, { useState as useState8, useMemo as useMemo8 } from "react";
3824
+ import React12, { useState as useState8, useMemo as useMemo8 } from "react";
3790
3825
  import Box11 from "@mui/material/Box";
3791
3826
  import Typography11 from "@mui/material/Typography";
3792
3827
  import Table6 from "@mui/material/Table";
@@ -3825,10 +3860,10 @@ function formatDateTime(iso) {
3825
3860
  }
3826
3861
  function renderAuditLogBody(loading, entries) {
3827
3862
  if (loading) {
3828
- return /* @__PURE__ */ React11.createElement(TableRow6, null, /* @__PURE__ */ React11.createElement(TableCell6, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ React11.createElement(Skeleton5, { variant: "rounded", height: 160 })));
3863
+ return /* @__PURE__ */ React12.createElement(TableRow6, null, /* @__PURE__ */ React12.createElement(TableCell6, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ React12.createElement(Skeleton5, { variant: "rounded", height: 160 })));
3829
3864
  }
3830
3865
  if (entries.length === 0) {
3831
- return /* @__PURE__ */ React11.createElement(TableRow6, null, /* @__PURE__ */ React11.createElement(TableCell6, { colSpan: 6 }, /* @__PURE__ */ React11.createElement(
3866
+ return /* @__PURE__ */ React12.createElement(TableRow6, null, /* @__PURE__ */ React12.createElement(TableCell6, { colSpan: 6 }, /* @__PURE__ */ React12.createElement(
3832
3867
  EmptyState,
3833
3868
  {
3834
3869
  message: "No audit events found",
@@ -3836,7 +3871,7 @@ function renderAuditLogBody(loading, entries) {
3836
3871
  }
3837
3872
  )));
3838
3873
  }
3839
- return entries.map((entry) => /* @__PURE__ */ React11.createElement(DetailRow, { key: entry.id, entry }));
3874
+ return entries.map((entry) => /* @__PURE__ */ React12.createElement(DetailRow, { key: entry.id, entry }));
3840
3875
  }
3841
3876
  var ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3842
3877
  var init_AuditLog = __esm({
@@ -3860,7 +3895,7 @@ var init_AuditLog = __esm({
3860
3895
  DetailRow = ({ entry }) => {
3861
3896
  const [open, setOpen] = useState8(false);
3862
3897
  const hasDetail = entry.before_value || entry.updated_values;
3863
- return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(TableRow6, null, /* @__PURE__ */ React11.createElement(TableCell6, { sx: { width: 40, pr: 0 } }, hasDetail && /* @__PURE__ */ React11.createElement(
3898
+ return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(TableRow6, null, /* @__PURE__ */ React12.createElement(TableCell6, { sx: { width: 40, pr: 0 } }, hasDetail && /* @__PURE__ */ React12.createElement(
3864
3899
  IconButton6,
3865
3900
  {
3866
3901
  size: "small",
@@ -3873,8 +3908,8 @@ var init_AuditLog = __esm({
3873
3908
  transition: theme.transitions.create("transform")
3874
3909
  })
3875
3910
  },
3876
- /* @__PURE__ */ React11.createElement(KeyboardArrowDown, { fontSize: "small" })
3877
- )), /* @__PURE__ */ React11.createElement(TableCell6, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ React11.createElement(Typography11, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ React11.createElement(TableCell6, null, entry.action && /* @__PURE__ */ React11.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ React11.createElement(TableCell6, null, /* @__PURE__ */ React11.createElement(Typography11, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ React11.createElement(TableCell6, null, /* @__PURE__ */ React11.createElement(
3911
+ /* @__PURE__ */ React12.createElement(KeyboardArrowDown, { fontSize: "small" })
3912
+ )), /* @__PURE__ */ React12.createElement(TableCell6, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ React12.createElement(Typography11, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ React12.createElement(TableCell6, null, entry.action && /* @__PURE__ */ React12.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ React12.createElement(TableCell6, null, /* @__PURE__ */ React12.createElement(Typography11, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ React12.createElement(TableCell6, null, /* @__PURE__ */ React12.createElement(
3878
3913
  Typography11,
3879
3914
  {
3880
3915
  variant: "body2",
@@ -3884,7 +3919,7 @@ var init_AuditLog = __esm({
3884
3919
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 12 }
3885
3920
  },
3886
3921
  entry.object_id ? entry.object_id.slice(0, 20) + (entry.object_id.length > 20 ? "\u2026" : "") : "\u2014"
3887
- )), /* @__PURE__ */ React11.createElement(TableCell6, null, entry.changed_by ?? "\u2014")), hasDetail && /* @__PURE__ */ React11.createElement(TableRow6, { sx: { "&&:hover": { bgcolor: "transparent" } } }, /* @__PURE__ */ React11.createElement(TableCell6, { colSpan: 6, sx: { "&&": { py: 0, border: 0 } } }, /* @__PURE__ */ React11.createElement(Collapse3, { in: open, unmountOnExit: true }, /* @__PURE__ */ React11.createElement(
3922
+ )), /* @__PURE__ */ React12.createElement(TableCell6, null, entry.changed_by ?? "\u2014")), hasDetail && /* @__PURE__ */ React12.createElement(TableRow6, { sx: { "&&:hover": { bgcolor: "transparent" } } }, /* @__PURE__ */ React12.createElement(TableCell6, { colSpan: 6, sx: { "&&": { py: 0, border: 0 } } }, /* @__PURE__ */ React12.createElement(Collapse3, { in: open, unmountOnExit: true }, /* @__PURE__ */ React12.createElement(
3888
3923
  Box11,
3889
3924
  {
3890
3925
  display: "flex",
@@ -3897,7 +3932,7 @@ var init_AuditLog = __esm({
3897
3932
  bgcolor: alpha8(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.05 : 0.03)
3898
3933
  })
3899
3934
  },
3900
- entry.before_value && /* @__PURE__ */ React11.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React11.createElement(
3935
+ entry.before_value && /* @__PURE__ */ React12.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React12.createElement(
3901
3936
  Typography11,
3902
3937
  {
3903
3938
  variant: "caption",
@@ -3907,8 +3942,8 @@ var init_AuditLog = __esm({
3907
3942
  sx: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase" }
3908
3943
  },
3909
3944
  "Before"
3910
- ), /* @__PURE__ */ React11.createElement(Typography11, { component: "pre", variant: "caption", sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", whiteSpace: "pre-wrap", wordBreak: "break-all", m: 0 } }, JSON.stringify(entry.before_value, null, 2))),
3911
- entry.updated_values && /* @__PURE__ */ React11.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React11.createElement(
3945
+ ), /* @__PURE__ */ React12.createElement(Typography11, { component: "pre", variant: "caption", sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", whiteSpace: "pre-wrap", wordBreak: "break-all", m: 0 } }, JSON.stringify(entry.before_value, null, 2))),
3946
+ entry.updated_values && /* @__PURE__ */ React12.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React12.createElement(
3912
3947
  Typography11,
3913
3948
  {
3914
3949
  variant: "caption",
@@ -3918,7 +3953,7 @@ var init_AuditLog = __esm({
3918
3953
  sx: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase" }
3919
3954
  },
3920
3955
  "After"
3921
- ), /* @__PURE__ */ React11.createElement(Typography11, { component: "pre", variant: "caption", sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", whiteSpace: "pre-wrap", wordBreak: "break-all", m: 0 } }, JSON.stringify(entry.updated_values, null, 2)))
3956
+ ), /* @__PURE__ */ React12.createElement(Typography11, { component: "pre", variant: "caption", sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", whiteSpace: "pre-wrap", wordBreak: "break-all", m: 0 } }, JSON.stringify(entry.updated_values, null, 2)))
3922
3957
  )))));
3923
3958
  };
3924
3959
  AuditLog = ({ api }) => {
@@ -3935,13 +3970,13 @@ var init_AuditLog = __esm({
3935
3970
  );
3936
3971
  const entries = value?.audit_logs ?? [];
3937
3972
  const total = value?.total ?? 0;
3938
- return /* @__PURE__ */ React11.createElement(
3973
+ return /* @__PURE__ */ React12.createElement(
3939
3974
  SectionCard,
3940
3975
  {
3941
3976
  title: "Audit Log",
3942
3977
  subtitle: loading ? "Loading\u2026" : `${total.toLocaleString()} event${total === 1 ? "" : "s"}`,
3943
3978
  flush: true,
3944
- actions: /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
3979
+ actions: /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
3945
3980
  TextField6,
3946
3981
  {
3947
3982
  size: "small",
@@ -3954,12 +3989,12 @@ var init_AuditLog = __esm({
3954
3989
  },
3955
3990
  sx: { minWidth: 150 }
3956
3991
  },
3957
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "" }, "All actions"),
3958
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "created" }, "Created"),
3959
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "updated" }, "Updated"),
3960
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "deleted" }, "Deleted"),
3961
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "blocked" }, "Blocked")
3962
- ), /* @__PURE__ */ React11.createElement(
3992
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "" }, "All actions"),
3993
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "created" }, "Created"),
3994
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "updated" }, "Updated"),
3995
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "deleted" }, "Deleted"),
3996
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "blocked" }, "Blocked")
3997
+ ), /* @__PURE__ */ React12.createElement(
3963
3998
  TextField6,
3964
3999
  {
3965
4000
  size: "small",
@@ -3972,13 +4007,13 @@ var init_AuditLog = __esm({
3972
4007
  },
3973
4008
  sx: { minWidth: 150 }
3974
4009
  },
3975
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "" }, "All tables"),
3976
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "LiteLLM_VerificationToken" }, "Key"),
3977
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "LiteLLM_TeamTable" }, "Team"),
3978
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "LiteLLM_TeamMembership" }, "Team member"),
3979
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
3980
- /* @__PURE__ */ React11.createElement(MenuItem5, { value: "LiteLLM_UserTable" }, "User")
3981
- ), /* @__PURE__ */ React11.createElement(
4010
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "" }, "All tables"),
4011
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_VerificationToken" }, "Key"),
4012
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_TeamTable" }, "Team"),
4013
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_TeamMembership" }, "Team member"),
4014
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
4015
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_UserTable" }, "User")
4016
+ ), /* @__PURE__ */ React12.createElement(
3982
4017
  TextField6,
3983
4018
  {
3984
4019
  size: "small",
@@ -3992,9 +4027,9 @@ var init_AuditLog = __esm({
3992
4027
  }
3993
4028
  ))
3994
4029
  },
3995
- error && /* @__PURE__ */ React11.createElement(Box11, { px: 2.5, pb: 2 }, /* @__PURE__ */ React11.createElement(Alert5, { severity: "error" }, error.message)),
3996
- /* @__PURE__ */ React11.createElement(TableContainer6, null, /* @__PURE__ */ React11.createElement(Table6, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React11.createElement(TableHead6, null, /* @__PURE__ */ React11.createElement(TableRow6, null, /* @__PURE__ */ React11.createElement(TableCell6, { sx: { width: 40 } }), /* @__PURE__ */ React11.createElement(TableCell6, null, "Time"), /* @__PURE__ */ React11.createElement(TableCell6, null, "Action"), /* @__PURE__ */ React11.createElement(TableCell6, null, "Table"), /* @__PURE__ */ React11.createElement(TableCell6, null, "Object ID"), /* @__PURE__ */ React11.createElement(TableCell6, null, "Changed By"))), /* @__PURE__ */ React11.createElement(TableBody6, null, renderAuditLogBody(loading, entries)))),
3997
- /* @__PURE__ */ React11.createElement(
4030
+ error && /* @__PURE__ */ React12.createElement(Box11, { px: 2.5, pb: 2 }, /* @__PURE__ */ React12.createElement(Alert5, { severity: "error" }, error.message)),
4031
+ /* @__PURE__ */ React12.createElement(TableContainer6, null, /* @__PURE__ */ React12.createElement(Table6, { size: "small", sx: dataTableSx }, /* @__PURE__ */ React12.createElement(TableHead6, null, /* @__PURE__ */ React12.createElement(TableRow6, null, /* @__PURE__ */ React12.createElement(TableCell6, { sx: { width: 40 } }), /* @__PURE__ */ React12.createElement(TableCell6, null, "Time"), /* @__PURE__ */ React12.createElement(TableCell6, null, "Action"), /* @__PURE__ */ React12.createElement(TableCell6, null, "Table"), /* @__PURE__ */ React12.createElement(TableCell6, null, "Object ID"), /* @__PURE__ */ React12.createElement(TableCell6, null, "Changed By"))), /* @__PURE__ */ React12.createElement(TableBody6, null, renderAuditLogBody(loading, entries)))),
4032
+ /* @__PURE__ */ React12.createElement(
3998
4033
  TablePagination,
3999
4034
  {
4000
4035
  component: "div",
@@ -4049,7 +4084,7 @@ var LiteLLMPage_exports = {};
4049
4084
  __export(LiteLLMPage_exports, {
4050
4085
  LiteLLMPage: () => LiteLLMPage
4051
4086
  });
4052
- import React12, { useState as useState9, useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo9 } from "react";
4087
+ import React13, { useState as useState9, useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo9 } from "react";
4053
4088
  import Box12 from "@mui/material/Box";
4054
4089
  import Snackbar2 from "@mui/material/Snackbar";
4055
4090
  import Alert6 from "@mui/material/Alert";
@@ -4335,14 +4370,14 @@ var init_LiteLLMPage = __esm({
4335
4370
  );
4336
4371
  const isInitialLoading = userLoading && !userInfo;
4337
4372
  if (isInitialLoading) {
4338
- return /* @__PURE__ */ React12.createElement(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ React12.createElement(CircularProgress6, null));
4373
+ return /* @__PURE__ */ React13.createElement(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ React13.createElement(CircularProgress6, null));
4339
4374
  }
4340
4375
  if (userError || !userInfo) {
4341
4376
  const isProvisioningEnabled = userError?.body?.provisioning === true;
4342
4377
  const hint = userError?.body?.hint;
4343
- return /* @__PURE__ */ React12.createElement(Box12, { p: 3 }, /* @__PURE__ */ React12.createElement(Paper8, { sx: { p: 3 } }, /* @__PURE__ */ React12.createElement(Typography12, { variant: "h6", gutterBottom: true }, "Account not provisioned"), /* @__PURE__ */ React12.createElement(Typography12, { color: "text.secondary", paragraph: true }, "Your Backstage account is not linked to a LiteLLM user."), hint ? /* @__PURE__ */ React12.createElement(Typography12, { variant: "body2", color: "text.secondary" }, hint) : /* @__PURE__ */ React12.createElement(Typography12, { 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.")));
4378
+ return /* @__PURE__ */ React13.createElement(Box12, { p: 3 }, /* @__PURE__ */ React13.createElement(Paper8, { sx: { p: 3 } }, /* @__PURE__ */ React13.createElement(Typography12, { variant: "h6", gutterBottom: true }, "Account not provisioned"), /* @__PURE__ */ React13.createElement(Typography12, { color: "text.secondary", paragraph: true }, "Your Backstage account is not linked to a LiteLLM user."), hint ? /* @__PURE__ */ React13.createElement(Typography12, { variant: "body2", color: "text.secondary" }, hint) : /* @__PURE__ */ React13.createElement(Typography12, { 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.")));
4344
4379
  }
4345
- const pageTabs = /* @__PURE__ */ React12.createElement(
4380
+ const pageTabs = /* @__PURE__ */ React13.createElement(
4346
4381
  Tabs2,
4347
4382
  {
4348
4383
  value: activeTab,
@@ -4355,13 +4390,13 @@ var init_LiteLLMPage = __esm({
4355
4390
  '& [class*="MuiTab-root"]': { minHeight: 44, textTransform: "none", fontSize: 14 }
4356
4391
  }
4357
4392
  },
4358
- /* @__PURE__ */ React12.createElement(Tab2, { label: "Overview", value: "overview" }),
4359
- /* @__PURE__ */ React12.createElement(Tab2, { label: "Keys", value: "keys" }),
4360
- /* @__PURE__ */ React12.createElement(Tab2, { label: "Teams", value: "teams" }),
4361
- /* @__PURE__ */ React12.createElement(Tab2, { label: "Models", value: "models" }),
4362
- userInfo.can_view_audit && /* @__PURE__ */ React12.createElement(Tab2, { label: "Audit Log", value: "audit" })
4393
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Overview", value: "overview" }),
4394
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Keys", value: "keys" }),
4395
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Teams", value: "teams" }),
4396
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Models", value: "models" }),
4397
+ userInfo.can_view_audit && /* @__PURE__ */ React13.createElement(Tab2, { label: "Audit Log", value: "audit" })
4363
4398
  );
4364
- return /* @__PURE__ */ React12.createElement(Box12, { sx: { p: 3, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React12.createElement(
4399
+ return /* @__PURE__ */ React13.createElement(Box12, { sx: { p: 3, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React13.createElement(
4365
4400
  DashboardHeader,
4366
4401
  {
4367
4402
  userInfo,
@@ -4371,7 +4406,7 @@ var init_LiteLLMPage = __esm({
4371
4406
  onGenerateKeyClick: () => setGenerateDialogOpen(true),
4372
4407
  tabs: pageTabs
4373
4408
  }
4374
- ), activeTab === "overview" && /* @__PURE__ */ React12.createElement(Grid2, { container: true, spacing: 2, alignItems: "flex-start" }, /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12, lg: 8 }, /* @__PURE__ */ React12.createElement(
4409
+ ), activeTab === "overview" && /* @__PURE__ */ React13.createElement(Grid2, { container: true, spacing: 2, alignItems: "flex-start" }, /* @__PURE__ */ React13.createElement(Grid2, { item: true, xs: 12, lg: 8 }, /* @__PURE__ */ React13.createElement(
4375
4410
  UsageStats,
4376
4411
  {
4377
4412
  usage: usage ?? null,
@@ -4382,7 +4417,7 @@ var init_LiteLLMPage = __esm({
4382
4417
  loading: usageLoading,
4383
4418
  userInfo
4384
4419
  }
4385
- )), /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12, lg: 4 }, /* @__PURE__ */ React12.createElement(LiteLLMBudgetWidget, { compact: true, collapsible: true }))), activeTab === "keys" && /* @__PURE__ */ React12.createElement(
4420
+ )), /* @__PURE__ */ React13.createElement(Grid2, { item: true, xs: 12, lg: 4 }, /* @__PURE__ */ React13.createElement(LiteLLMBudgetWidget, { compact: true, collapsible: true }))), activeTab === "keys" && /* @__PURE__ */ React13.createElement(
4386
4421
  KeysTable,
4387
4422
  {
4388
4423
  keys: keys ?? [],
@@ -4399,7 +4434,7 @@ var init_LiteLLMPage = __esm({
4399
4434
  for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);
4400
4435
  for (const t of teams ?? []) teamsById.set(t.team_id, t);
4401
4436
  const visibleTeams = Array.from(teamsById.values());
4402
- return /* @__PURE__ */ React12.createElement(
4437
+ return /* @__PURE__ */ React13.createElement(
4403
4438
  TeamUsage,
4404
4439
  {
4405
4440
  teams: visibleTeams,
@@ -4415,14 +4450,14 @@ var init_LiteLLMPage = __esm({
4415
4450
  onCreateTeam: () => setManageTeam({ mode: "create" })
4416
4451
  }
4417
4452
  );
4418
- })(), activeTab === "models" && /* @__PURE__ */ React12.createElement(
4453
+ })(), activeTab === "models" && /* @__PURE__ */ React13.createElement(
4419
4454
  ModelsTable,
4420
4455
  {
4421
4456
  allModels: allModels ?? [],
4422
4457
  teams: teams ?? [],
4423
4458
  loading: modelsLoading
4424
4459
  }
4425
- ), activeTab === "audit" && userInfo.can_view_audit && /* @__PURE__ */ React12.createElement(AuditLog, { api }), /* @__PURE__ */ React12.createElement(
4460
+ ), activeTab === "audit" && userInfo.can_view_audit && /* @__PURE__ */ React13.createElement(AuditLog, { api }), /* @__PURE__ */ React13.createElement(
4426
4461
  KeyFormDialog,
4427
4462
  {
4428
4463
  open: keyFormOpen,
@@ -4442,7 +4477,7 @@ var init_LiteLLMPage = __esm({
4442
4477
  onResetKeySpend: handleResetKeySpend,
4443
4478
  onGetConfig: () => api.getConfig()
4444
4479
  }
4445
- ), /* @__PURE__ */ React12.createElement(
4480
+ ), /* @__PURE__ */ React13.createElement(
4446
4481
  ManageTeamDialog,
4447
4482
  {
4448
4483
  open: !!manageTeam,
@@ -4504,7 +4539,7 @@ var init_LiteLLMPage = __esm({
4504
4539
  refreshTeams();
4505
4540
  }
4506
4541
  }
4507
- ), /* @__PURE__ */ React12.createElement(
4542
+ ), /* @__PURE__ */ React13.createElement(
4508
4543
  Snackbar2,
4509
4544
  {
4510
4545
  open: !!snackbar,
@@ -4512,7 +4547,7 @@ var init_LiteLLMPage = __esm({
4512
4547
  onClose: () => setSnackbar(null),
4513
4548
  anchorOrigin: { vertical: "bottom", horizontal: "right" }
4514
4549
  },
4515
- snackbar ? /* @__PURE__ */ React12.createElement(Alert6, { severity: snackbar.severity, onClose: () => setSnackbar(null) }, snackbar.message) : void 0
4550
+ snackbar ? /* @__PURE__ */ React13.createElement(Alert6, { severity: snackbar.severity, onClose: () => setSnackbar(null) }, snackbar.message) : void 0
4516
4551
  ));
4517
4552
  };
4518
4553
  }
@@ -4520,7 +4555,7 @@ var init_LiteLLMPage = __esm({
4520
4555
 
4521
4556
  // src/plugin.tsx
4522
4557
  init_api();
4523
- import React13 from "react";
4558
+ import React14 from "react";
4524
4559
  import { TrendingUp as TrendingUpIcon } from "@mui/icons-material";
4525
4560
  import {
4526
4561
  createFrontendPlugin,
@@ -4539,10 +4574,10 @@ var liteLlmPage = PageBlueprint.make({
4539
4574
  params: {
4540
4575
  path: "/litellm",
4541
4576
  title: "LiteLLM",
4542
- icon: /* @__PURE__ */ React13.createElement(TrendingUpIcon, null),
4577
+ icon: /* @__PURE__ */ React14.createElement(TrendingUpIcon, null),
4543
4578
  loader: async () => {
4544
4579
  const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
4545
- return /* @__PURE__ */ React13.createElement(LiteLLMPage2, null);
4580
+ return /* @__PURE__ */ React14.createElement(LiteLLMPage2, null);
4546
4581
  }
4547
4582
  }
4548
4583
  });
@@ -4561,7 +4596,7 @@ init_TeamUsage();
4561
4596
  // src/components/LiteLLMHomeWidget.tsx
4562
4597
  init_api();
4563
4598
  init_format();
4564
- import React14, { useState as useState10, useEffect as useEffect5 } from "react";
4599
+ import React15, { useState as useState10, useEffect as useEffect5 } from "react";
4565
4600
  import Paper9 from "@mui/material/Paper";
4566
4601
  import Box13 from "@mui/material/Box";
4567
4602
  import Typography13 from "@mui/material/Typography";
@@ -4585,7 +4620,7 @@ function presetToDateRange(preset) {
4585
4620
  }
4586
4621
  return { start, end };
4587
4622
  }
4588
- var Kpi = ({ label, value }) => /* @__PURE__ */ React14.createElement(Box13, null, /* @__PURE__ */ React14.createElement(Typography13, { variant: "caption", color: "text.secondary", display: "block" }, label), /* @__PURE__ */ React14.createElement(Typography13, { variant: "subtitle1", fontWeight: 600 }, value));
4623
+ var Kpi = ({ label, value }) => /* @__PURE__ */ React15.createElement(Box13, null, /* @__PURE__ */ React15.createElement(Typography13, { variant: "caption", color: "text.secondary", display: "block" }, label), /* @__PURE__ */ React15.createElement(Typography13, { variant: "subtitle1", fontWeight: 600 }, value));
4589
4624
  var LiteLLMHomeWidget = ({
4590
4625
  defaultPeriod = "7d",
4591
4626
  title = "LiteLLM Usage"
@@ -4634,17 +4669,17 @@ var LiteLLMHomeWidget = ({
4634
4669
  spend: d.spend
4635
4670
  }));
4636
4671
  const hasSparkline = dailyData.length > 0;
4637
- return /* @__PURE__ */ React14.createElement(Paper9, { sx: { p: 2 } }, /* @__PURE__ */ React14.createElement(Box13, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ React14.createElement(Typography13, { variant: "h6" }, title), /* @__PURE__ */ React14.createElement(FormControl2, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ React14.createElement(
4672
+ return /* @__PURE__ */ React15.createElement(Paper9, { sx: { p: 2 } }, /* @__PURE__ */ React15.createElement(Box13, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ React15.createElement(Typography13, { variant: "h6" }, title), /* @__PURE__ */ React15.createElement(FormControl2, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ React15.createElement(
4638
4673
  Select2,
4639
4674
  {
4640
4675
  value: period,
4641
4676
  onChange: (e) => setPeriod(e.target.value),
4642
4677
  displayEmpty: true
4643
4678
  },
4644
- /* @__PURE__ */ React14.createElement(MenuItem6, { value: "today" }, "Today"),
4645
- /* @__PURE__ */ React14.createElement(MenuItem6, { value: "7d" }, "7d"),
4646
- /* @__PURE__ */ React14.createElement(MenuItem6, { value: "30d" }, "30d")
4647
- ))), loading && /* @__PURE__ */ React14.createElement(Box13, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ React14.createElement(CircularProgress7, { size: 32 })), !loading && totalFailure && /* @__PURE__ */ React14.createElement(Alert7, { severity: "error", sx: { mt: 1 } }, usageError ?? "Failed to load usage data"), !loading && !totalFailure && /* @__PURE__ */ React14.createElement(React14.Fragment, null, partialFailure && /* @__PURE__ */ React14.createElement(Alert7, { severity: "warning", sx: { mt: 1, mb: 1 } }, usageError ? `Usage data unavailable (${usageError}).` : "", keysError ? ` Key list unavailable (${keysError}).` : "", " Showing what loaded."), /* @__PURE__ */ React14.createElement(Grid3, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ React14.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React14.createElement(Kpi, { label: "USD Spent", value: fmtUsd(usage?.total_spend ?? 0) })), /* @__PURE__ */ React14.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React14.createElement(Kpi, { label: "Tokens In", value: fmtInt(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ React14.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React14.createElement(Kpi, { label: "Tokens Out", value: fmtInt(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ React14.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React14.createElement(Kpi, { label: "Keys", value: fmtInt(keys.length) }))), hasSparkline && /* @__PURE__ */ React14.createElement(Box13, { height: 120 }, /* @__PURE__ */ React14.createElement(ResponsiveContainer3, { width: "100%", height: "100%" }, /* @__PURE__ */ React14.createElement(AreaChart3, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ React14.createElement(
4679
+ /* @__PURE__ */ React15.createElement(MenuItem6, { value: "today" }, "Today"),
4680
+ /* @__PURE__ */ React15.createElement(MenuItem6, { value: "7d" }, "7d"),
4681
+ /* @__PURE__ */ React15.createElement(MenuItem6, { value: "30d" }, "30d")
4682
+ ))), loading && /* @__PURE__ */ React15.createElement(Box13, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ React15.createElement(CircularProgress7, { size: 32 })), !loading && totalFailure && /* @__PURE__ */ React15.createElement(Alert7, { severity: "error", sx: { mt: 1 } }, usageError ?? "Failed to load usage data"), !loading && !totalFailure && /* @__PURE__ */ React15.createElement(React15.Fragment, null, partialFailure && /* @__PURE__ */ React15.createElement(Alert7, { severity: "warning", sx: { mt: 1, mb: 1 } }, usageError ? `Usage data unavailable (${usageError}).` : "", keysError ? ` Key list unavailable (${keysError}).` : "", " Showing what loaded."), /* @__PURE__ */ React15.createElement(Grid3, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ React15.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React15.createElement(Kpi, { label: "USD Spent", value: fmtUsd(usage?.total_spend ?? 0) })), /* @__PURE__ */ React15.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React15.createElement(Kpi, { label: "Tokens In", value: fmtInt(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ React15.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React15.createElement(Kpi, { label: "Tokens Out", value: fmtInt(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ React15.createElement(Grid3, { item: true, xs: 6 }, /* @__PURE__ */ React15.createElement(Kpi, { label: "Keys", value: fmtInt(keys.length) }))), hasSparkline && /* @__PURE__ */ React15.createElement(Box13, { height: 120 }, /* @__PURE__ */ React15.createElement(ResponsiveContainer3, { width: "100%", height: "100%" }, /* @__PURE__ */ React15.createElement(AreaChart3, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ React15.createElement(
4648
4683
  Area3,
4649
4684
  {
4650
4685
  type: "monotone",
@@ -4665,9 +4700,10 @@ init_LiteLLMBudgetWidget();
4665
4700
  init_api();
4666
4701
  init_format();
4667
4702
  init_ui();
4703
+ init_GenerateKeyButton();
4668
4704
  init_BudgetLimitList();
4669
4705
  init_budget();
4670
- import React15, { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo10, useState as useState11 } from "react";
4706
+ import React16, { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo10, useState as useState11 } from "react";
4671
4707
  import Paper10 from "@mui/material/Paper";
4672
4708
  import Box14 from "@mui/material/Box";
4673
4709
  import Button6 from "@mui/material/Button";
@@ -4676,8 +4712,9 @@ import CircularProgress8 from "@mui/material/CircularProgress";
4676
4712
  import Alert8 from "@mui/material/Alert";
4677
4713
  import Collapse4 from "@mui/material/Collapse";
4678
4714
  import { ExpandMore as ExpandMore4 } from "@mui/icons-material";
4715
+ import { AreaChart as AreaChart4, Area as Area4, ResponsiveContainer as ResponsiveContainer4, Tooltip as Tooltip4 } from "recharts";
4679
4716
  import { useApi as useApi5 } from "@backstage/core-plugin-api";
4680
- import { Link as Link2 } from "@backstage/core-components";
4717
+ import { Link as Link3 } from "@backstage/core-components";
4681
4718
  var MODULE_PATH = "/litellm";
4682
4719
  var LEVEL = {
4683
4720
  key: { name: "Key", none: "No key budget" },
@@ -4686,7 +4723,7 @@ var LEVEL = {
4686
4723
  };
4687
4724
  var DEFAULT_CTAS = ["new-key", "module", "all-limits"];
4688
4725
  var CTA_LABELS = {
4689
- "new-key": "New key",
4726
+ "new-key": "Generate New Key",
4690
4727
  module: "Open module",
4691
4728
  "all-limits": "All limits"
4692
4729
  };
@@ -4712,7 +4749,7 @@ var LevelGauge = ({
4712
4749
  const limit = gauge.limit;
4713
4750
  const tone = limit ? budgetTone2(limit.pct) : "neutral";
4714
4751
  const extra = gauge.kind === "key" ? Math.max(0, gauge.count - 1) : 0;
4715
- return /* @__PURE__ */ React15.createElement(
4752
+ return /* @__PURE__ */ React16.createElement(
4716
4753
  Box14,
4717
4754
  {
4718
4755
  sx: {
@@ -4723,7 +4760,7 @@ var LevelGauge = ({
4723
4760
  flex: 1
4724
4761
  }
4725
4762
  },
4726
- /* @__PURE__ */ React15.createElement(
4763
+ /* @__PURE__ */ React16.createElement(
4727
4764
  Gauge,
4728
4765
  {
4729
4766
  value: limit?.pct ?? 0,
@@ -4732,7 +4769,7 @@ var LevelGauge = ({
4732
4769
  label: limit ? `${Math.round(limit.pct)}%` : "\u2014"
4733
4770
  }
4734
4771
  ),
4735
- /* @__PURE__ */ React15.createElement(
4772
+ /* @__PURE__ */ React16.createElement(
4736
4773
  Typography14,
4737
4774
  {
4738
4775
  sx: (theme) => ({
@@ -4746,7 +4783,7 @@ var LevelGauge = ({
4746
4783
  },
4747
4784
  name
4748
4785
  ),
4749
- limit ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
4786
+ limit ? /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
4750
4787
  Typography14,
4751
4788
  {
4752
4789
  variant: "caption",
@@ -4762,7 +4799,7 @@ var LevelGauge = ({
4762
4799
  }
4763
4800
  },
4764
4801
  limit.label
4765
- ), /* @__PURE__ */ React15.createElement(
4802
+ ), /* @__PURE__ */ React16.createElement(
4766
4803
  Typography14,
4767
4804
  {
4768
4805
  variant: "caption",
@@ -4774,10 +4811,10 @@ var LevelGauge = ({
4774
4811
  }
4775
4812
  },
4776
4813
  spendCaption(limit)
4777
- ), extra > 0 ? /* @__PURE__ */ React15.createElement(
4814
+ ), extra > 0 ? /* @__PURE__ */ React16.createElement(
4778
4815
  Typography14,
4779
4816
  {
4780
- component: Link2,
4817
+ component: Link3,
4781
4818
  to: keysHref,
4782
4819
  variant: "caption",
4783
4820
  sx: {
@@ -4790,7 +4827,7 @@ var LevelGauge = ({
4790
4827
  "+",
4791
4828
  extra,
4792
4829
  " more"
4793
- ) : /* @__PURE__ */ React15.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, resetLabel(limit))) : /* @__PURE__ */ React15.createElement(
4830
+ ) : /* @__PURE__ */ React16.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, resetLabel(limit))) : /* @__PURE__ */ React16.createElement(
4794
4831
  Typography14,
4795
4832
  {
4796
4833
  variant: "caption",
@@ -4801,6 +4838,125 @@ var LevelGauge = ({
4801
4838
  )
4802
4839
  );
4803
4840
  };
4841
+ function monthToDateRange(now = /* @__PURE__ */ new Date()) {
4842
+ const toDay = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(
4843
+ d.getDate()
4844
+ ).padStart(2, "0")}`;
4845
+ const start = new Date(now.getFullYear(), now.getMonth(), 1);
4846
+ return { startDate: toDay(start), endDate: toDay(now) };
4847
+ }
4848
+ var UsageMiniChart = ({ data, totalTokens, loading, height }) => {
4849
+ const renderPlot = () => {
4850
+ if (loading) {
4851
+ return /* @__PURE__ */ React16.createElement(Box14, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%" }, /* @__PURE__ */ React16.createElement(CircularProgress8, { size: 20 }));
4852
+ }
4853
+ if (data.length === 0) {
4854
+ return /* @__PURE__ */ React16.createElement(
4855
+ Box14,
4856
+ {
4857
+ display: "flex",
4858
+ justifyContent: "center",
4859
+ alignItems: "center",
4860
+ height: "100%",
4861
+ sx: (theme) => ({ color: theme.palette.text.secondary, fontSize: 18 })
4862
+ },
4863
+ "\u2014"
4864
+ );
4865
+ }
4866
+ return /* @__PURE__ */ React16.createElement(ResponsiveContainer4, { width: "100%", height: "100%" }, /* @__PURE__ */ React16.createElement(AreaChart4, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ React16.createElement(Tooltip4, { content: /* @__PURE__ */ React16.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ React16.createElement(
4867
+ Area4,
4868
+ {
4869
+ type: "monotone",
4870
+ dataKey: "input",
4871
+ name: "Input",
4872
+ stackId: "tok",
4873
+ stroke: SERIES.input,
4874
+ strokeWidth: 1.5,
4875
+ fill: SERIES.input,
4876
+ fillOpacity: 0.25,
4877
+ dot: false,
4878
+ isAnimationActive: false
4879
+ }
4880
+ ), /* @__PURE__ */ React16.createElement(
4881
+ Area4,
4882
+ {
4883
+ type: "monotone",
4884
+ dataKey: "output",
4885
+ name: "Output",
4886
+ stackId: "tok",
4887
+ stroke: SERIES.output,
4888
+ strokeWidth: 1.5,
4889
+ fill: SERIES.output,
4890
+ fillOpacity: 0.25,
4891
+ dot: false,
4892
+ isAnimationActive: false
4893
+ }
4894
+ )));
4895
+ };
4896
+ const renderCaption = () => {
4897
+ if (loading) {
4898
+ return /* @__PURE__ */ React16.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { mt: 0.25, fontSize: 11 } }, "\u2026");
4899
+ }
4900
+ if (data.length === 0) {
4901
+ return /* @__PURE__ */ React16.createElement(
4902
+ Typography14,
4903
+ {
4904
+ variant: "caption",
4905
+ color: "text.secondary",
4906
+ sx: { mt: 0.25, fontSize: 10.5, textAlign: "center" }
4907
+ },
4908
+ "No usage this month"
4909
+ );
4910
+ }
4911
+ return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
4912
+ Typography14,
4913
+ {
4914
+ variant: "caption",
4915
+ title: `${fmtInt(totalTokens)} tokens month to date`,
4916
+ sx: {
4917
+ mt: 0.25,
4918
+ fontSize: 11,
4919
+ fontWeight: 600,
4920
+ maxWidth: "100%",
4921
+ overflow: "hidden",
4922
+ textOverflow: "ellipsis",
4923
+ whiteSpace: "nowrap",
4924
+ fontVariantNumeric: "tabular-nums"
4925
+ }
4926
+ },
4927
+ fmtCompact(totalTokens),
4928
+ " tokens"
4929
+ ), /* @__PURE__ */ React16.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, "month to date"));
4930
+ };
4931
+ return /* @__PURE__ */ React16.createElement(
4932
+ Box14,
4933
+ {
4934
+ sx: {
4935
+ display: "flex",
4936
+ flexDirection: "column",
4937
+ alignItems: "center",
4938
+ minWidth: 0,
4939
+ flex: 1
4940
+ }
4941
+ },
4942
+ /* @__PURE__ */ React16.createElement(Box14, { sx: { height, width: "100%" } }, renderPlot()),
4943
+ /* @__PURE__ */ React16.createElement(
4944
+ Typography14,
4945
+ {
4946
+ sx: (theme) => ({
4947
+ mt: 0.75,
4948
+ fontSize: 10.5,
4949
+ fontWeight: 700,
4950
+ letterSpacing: "0.08em",
4951
+ textTransform: "uppercase",
4952
+ color: theme.palette.text.secondary
4953
+ })
4954
+ },
4955
+ "Usage"
4956
+ ),
4957
+ renderCaption()
4958
+ );
4959
+ };
4804
4960
  var LiteLLMBudgetGauges = ({
4805
4961
  title = "Budget",
4806
4962
  size = 72,
@@ -4820,6 +4976,9 @@ var LiteLLMBudgetGauges = ({
4820
4976
  const [user, setUser] = useState11(null);
4821
4977
  const [teams, setTeams] = useState11([]);
4822
4978
  const [keys, setKeys] = useState11([]);
4979
+ const [usageLoading, setUsageLoading] = useState11(true);
4980
+ const [dailyTokens, setDailyTokens] = useState11([]);
4981
+ const [mtdTokens, setMtdTokens] = useState11(0);
4823
4982
  const isControlled = expanded !== void 0;
4824
4983
  const [uncontrolledExpanded, setUncontrolledExpanded] = useState11(defaultExpanded);
4825
4984
  const isExpanded = isControlled ? expanded : uncontrolledExpanded;
@@ -4832,23 +4991,43 @@ var LiteLLMBudgetGauges = ({
4832
4991
  useEffect6(() => {
4833
4992
  let cancelled = false;
4834
4993
  setLoading(true);
4994
+ setUsageLoading(true);
4835
4995
  setError(null);
4836
- Promise.allSettled([api.getUserInfo(), api.getTeams(), api.listKeys()]).then(
4837
- ([userResult, teamsResult, keysResult]) => {
4838
- if (cancelled) return;
4839
- if (userResult.status === "fulfilled") {
4840
- setUser(userResult.value);
4841
- } else {
4842
- setUser(null);
4843
- setError(
4844
- userResult.reason?.message ?? "Failed to load your LiteLLM profile"
4845
- );
4846
- }
4847
- setTeams(teamsResult.status === "fulfilled" ? teamsResult.value : []);
4848
- setKeys(keysResult.status === "fulfilled" ? keysResult.value : []);
4849
- setLoading(false);
4996
+ const { startDate, endDate } = monthToDateRange();
4997
+ Promise.allSettled([
4998
+ api.getUserInfo(),
4999
+ api.getTeams(),
5000
+ api.listKeys(),
5001
+ api.getUsage(startDate, endDate)
5002
+ ]).then(([userResult, teamsResult, keysResult, usageResult]) => {
5003
+ if (cancelled) return;
5004
+ if (userResult.status === "fulfilled") {
5005
+ setUser(userResult.value);
5006
+ } else {
5007
+ setUser(null);
5008
+ setError(
5009
+ userResult.reason?.message ?? "Failed to load your LiteLLM profile"
5010
+ );
4850
5011
  }
4851
- );
5012
+ setTeams(teamsResult.status === "fulfilled" ? teamsResult.value : []);
5013
+ setKeys(keysResult.status === "fulfilled" ? keysResult.value : []);
5014
+ setLoading(false);
5015
+ if (usageResult.status === "fulfilled") {
5016
+ const daily = usageResult.value.daily_usage ?? [];
5017
+ setDailyTokens(
5018
+ daily.map((d) => ({
5019
+ date: d.date,
5020
+ input: d.prompt_tokens,
5021
+ output: d.completion_tokens
5022
+ }))
5023
+ );
5024
+ setMtdTokens(usageResult.value.total_tokens ?? 0);
5025
+ } else {
5026
+ setDailyTokens([]);
5027
+ setMtdTokens(0);
5028
+ }
5029
+ setUsageLoading(false);
5030
+ });
4852
5031
  return () => {
4853
5032
  cancelled = true;
4854
5033
  };
@@ -4877,28 +5056,18 @@ var LiteLLMBudgetGauges = ({
4877
5056
  const key = `${cta.kind}-${index}`;
4878
5057
  switch (cta.kind) {
4879
5058
  case "new-key":
4880
- return onCreateKey ? /* @__PURE__ */ React15.createElement(Button6, { key, size: "small", variant: "contained", onClick: onCreateKey }, label) : /* @__PURE__ */ React15.createElement(
4881
- Button6,
4882
- {
4883
- key,
4884
- size: "small",
4885
- variant: "contained",
4886
- component: Link2,
4887
- to: `${moduleHref}?generate=1`
4888
- },
4889
- label
4890
- );
5059
+ return onCreateKey ? /* @__PURE__ */ React16.createElement(GenerateKeyButton, { key, size: "small", label, onClick: onCreateKey }) : /* @__PURE__ */ React16.createElement(GenerateKeyButton, { key, size: "small", label, to: `${moduleHref}?generate=1` });
4891
5060
  case "module":
4892
- return /* @__PURE__ */ React15.createElement(Button6, { key, size: "small", variant: "outlined", component: Link2, to: moduleHref }, label);
5061
+ return /* @__PURE__ */ React16.createElement(Button6, { key, size: "small", variant: "outlined", component: Link3, to: moduleHref }, label);
4893
5062
  case "all-limits":
4894
- return /* @__PURE__ */ React15.createElement(
5063
+ return /* @__PURE__ */ React16.createElement(
4895
5064
  Button6,
4896
5065
  {
4897
5066
  key,
4898
5067
  size: "small",
4899
5068
  variant: "text",
4900
5069
  onClick: toggleExpanded,
4901
- endIcon: /* @__PURE__ */ React15.createElement(
5070
+ endIcon: /* @__PURE__ */ React16.createElement(
4902
5071
  ExpandMore4,
4903
5072
  {
4904
5073
  sx: {
@@ -4916,14 +5085,22 @@ var LiteLLMBudgetGauges = ({
4916
5085
  }
4917
5086
  };
4918
5087
  const hasFooter = resolvedCtas.length > 0 || !!action;
4919
- return /* @__PURE__ */ React15.createElement(Paper10, { sx: { p: 2 } }, /* @__PURE__ */ React15.createElement(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1.5, minWidth: 0 } }, /* @__PURE__ */ React15.createElement(Typography14, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 } }, title), !loading && !error && /* @__PURE__ */ React15.createElement(
5088
+ return /* @__PURE__ */ React16.createElement(Paper10, { sx: { p: 2 } }, /* @__PURE__ */ React16.createElement(Box14, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1.5, minWidth: 0 } }, /* @__PURE__ */ React16.createElement(Typography14, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 } }, title), !loading && !error && /* @__PURE__ */ React16.createElement(
4920
5089
  StatusPill,
4921
5090
  {
4922
5091
  label: summaryText,
4923
5092
  tone: budgetTone2(headline.closest?.pct ?? 0),
4924
5093
  dot: headline.count > 0
4925
5094
  }
4926
- )), loading && /* @__PURE__ */ React15.createElement(Box14, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 110 }, /* @__PURE__ */ React15.createElement(CircularProgress8, { size: 28 })), !loading && error && /* @__PURE__ */ React15.createElement(Alert8, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(Box14, { sx: { display: "flex", alignItems: "flex-start", gap: 1 } }, gauges.map((gauge) => /* @__PURE__ */ React15.createElement(LevelGauge, { key: gauge.kind, gauge, size, keysHref: keysTabHref }))), /* @__PURE__ */ React15.createElement(Collapse4, { in: isExpanded, unmountOnExit: true }, /* @__PURE__ */ React15.createElement(
5095
+ )), loading && /* @__PURE__ */ React16.createElement(Box14, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 110 }, /* @__PURE__ */ React16.createElement(CircularProgress8, { size: 28 })), !loading && error && /* @__PURE__ */ React16.createElement(Alert8, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(Box14, { sx: { display: "flex", alignItems: "flex-start", gap: 1 } }, gauges.map((gauge) => /* @__PURE__ */ React16.createElement(LevelGauge, { key: gauge.kind, gauge, size, keysHref: keysTabHref })), /* @__PURE__ */ React16.createElement(
5096
+ UsageMiniChart,
5097
+ {
5098
+ data: dailyTokens,
5099
+ totalTokens: mtdTokens,
5100
+ loading: usageLoading,
5101
+ height: size
5102
+ }
5103
+ )), /* @__PURE__ */ React16.createElement(Collapse4, { in: isExpanded, unmountOnExit: true }, /* @__PURE__ */ React16.createElement(
4927
5104
  Box14,
4928
5105
  {
4929
5106
  sx: {
@@ -4934,7 +5111,7 @@ var LiteLLMBudgetGauges = ({
4934
5111
  overflowY: "auto"
4935
5112
  }
4936
5113
  },
4937
- /* @__PURE__ */ React15.createElement(LimitListPanel, null, /* @__PURE__ */ React15.createElement(
5114
+ /* @__PURE__ */ React16.createElement(LimitListPanel, null, /* @__PURE__ */ React16.createElement(
4938
5115
  BudgetLimitList,
4939
5116
  {
4940
5117
  limits: expandedLimits,
@@ -4942,7 +5119,7 @@ var LiteLLMBudgetGauges = ({
4942
5119
  keysHref: keysTabHref
4943
5120
  }
4944
5121
  ))
4945
- ))), hasFooter && /* @__PURE__ */ React15.createElement(
5122
+ ))), hasFooter && /* @__PURE__ */ React16.createElement(
4946
5123
  Box14,
4947
5124
  {
4948
5125
  sx: (theme) => ({
@@ -4962,11 +5139,12 @@ var LiteLLMBudgetGauges = ({
4962
5139
 
4963
5140
  // src/index.ts
4964
5141
  init_KeyFormDialog();
5142
+ init_GenerateKeyButton();
4965
5143
 
4966
5144
  // src/components/GenerateKeyDialog.tsx
4967
5145
  init_KeyFormDialog();
4968
- import React16 from "react";
4969
- var GenerateKeyDialog = (props) => /* @__PURE__ */ React16.createElement(
5146
+ import React17 from "react";
5147
+ var GenerateKeyDialog = (props) => /* @__PURE__ */ React17.createElement(
4970
5148
  KeyFormDialog,
4971
5149
  {
4972
5150
  open: props.open,
@@ -4990,6 +5168,7 @@ init_api();
4990
5168
  init_permissions();
4991
5169
  export {
4992
5170
  DashboardHeader,
5171
+ GenerateKeyButton,
4993
5172
  GenerateKeyDialog,
4994
5173
  KeyFormDialog,
4995
5174
  KeysTable,