@acarmisc/backstage-plugin-litellm 0.26.0 → 0.28.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,79 @@ 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
+ fullWidth = false,
854
+ disabled = false
855
+ }) => {
856
+ if (onClick && !disabled) {
857
+ return /* @__PURE__ */ React2.createElement(
858
+ Button,
859
+ {
860
+ variant: "contained",
861
+ color: "primary",
862
+ disableElevation: true,
863
+ size,
864
+ fullWidth,
865
+ startIcon: /* @__PURE__ */ React2.createElement(Add, null),
866
+ onClick
867
+ },
868
+ label
869
+ );
870
+ }
871
+ if (to && !disabled) {
872
+ return /* @__PURE__ */ React2.createElement(
873
+ Button,
874
+ {
875
+ variant: "contained",
876
+ color: "primary",
877
+ disableElevation: true,
878
+ size,
879
+ fullWidth,
880
+ startIcon: /* @__PURE__ */ React2.createElement(Add, null),
881
+ component: Link,
882
+ to
883
+ },
884
+ label
885
+ );
886
+ }
887
+ return /* @__PURE__ */ React2.createElement(
888
+ Button,
889
+ {
890
+ variant: "contained",
891
+ color: "primary",
892
+ disableElevation: true,
893
+ size,
894
+ fullWidth,
895
+ startIcon: /* @__PURE__ */ React2.createElement(Add, null),
896
+ disabled: true
897
+ },
898
+ label
899
+ );
900
+ };
901
+ }
902
+ });
903
+
839
904
  // src/components/DashboardHeader.tsx
840
- import React2, { useMemo } from "react";
905
+ import React3, { useMemo } from "react";
841
906
  import Box2 from "@mui/material/Box";
842
907
  import Typography2 from "@mui/material/Typography";
843
908
  import Skeleton from "@mui/material/Skeleton";
844
909
  import Paper2 from "@mui/material/Paper";
845
- import Button from "@mui/material/Button";
846
910
  import Divider from "@mui/material/Divider";
847
911
  import { alpha as alpha2 } from "@mui/material/styles";
848
- import { Add } from "@mui/icons-material";
849
912
  function initials(name) {
850
913
  const local = name.split("@")[0] ?? name;
851
914
  const parts = local.split(/[.\-_\s]+/).filter(Boolean);
@@ -858,9 +921,10 @@ var init_DashboardHeader = __esm({
858
921
  "use strict";
859
922
  init_api();
860
923
  init_ui();
924
+ init_GenerateKeyButton();
861
925
  CountStat = ({ value, label, tone }) => {
862
926
  const active = value > 0;
863
- return /* @__PURE__ */ React2.createElement(Box2, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ React2.createElement(
927
+ return /* @__PURE__ */ React3.createElement(Box2, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ React3.createElement(
864
928
  Box2,
865
929
  {
866
930
  sx: (theme) => ({
@@ -871,14 +935,14 @@ var init_DashboardHeader = __esm({
871
935
  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
936
  })
873
937
  }
874
- ), /* @__PURE__ */ React2.createElement(
938
+ ), /* @__PURE__ */ React3.createElement(
875
939
  Typography2,
876
940
  {
877
941
  component: "span",
878
942
  sx: { fontSize: 15, fontWeight: 700, lineHeight: 1, fontVariantNumeric: "tabular-nums" }
879
943
  },
880
944
  value
881
- ), /* @__PURE__ */ React2.createElement(
945
+ ), /* @__PURE__ */ React3.createElement(
882
946
  Typography2,
883
947
  {
884
948
  component: "span",
@@ -902,7 +966,7 @@ var init_DashboardHeader = __esm({
902
966
  return { total: keys.length, expired, expiringSoon };
903
967
  }, [keys]);
904
968
  const displayName = userInfo.user_email ?? userInfo.email ?? userInfo.user_id;
905
- return /* @__PURE__ */ React2.createElement(Paper2, { sx: { borderRadius: 2, overflow: "hidden" } }, /* @__PURE__ */ React2.createElement(
969
+ return /* @__PURE__ */ React3.createElement(Paper2, { sx: { borderRadius: 2, overflow: "hidden" } }, /* @__PURE__ */ React3.createElement(
906
970
  Box2,
907
971
  {
908
972
  sx: {
@@ -915,7 +979,7 @@ var init_DashboardHeader = __esm({
915
979
  pb: 2
916
980
  }
917
981
  },
918
- /* @__PURE__ */ React2.createElement(
982
+ /* @__PURE__ */ React3.createElement(
919
983
  Box2,
920
984
  {
921
985
  sx: (theme) => ({
@@ -935,7 +999,7 @@ var init_DashboardHeader = __esm({
935
999
  },
936
1000
  initials(displayName)
937
1001
  ),
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(
1002
+ /* @__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
1003
  Typography2,
940
1004
  {
941
1005
  variant: "caption",
@@ -943,7 +1007,7 @@ var init_DashboardHeader = __esm({
943
1007
  sx: { display: "block", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
944
1008
  },
945
1009
  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(
1010
+ ), /* @__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
1011
  TagChip,
948
1012
  {
949
1013
  key: team.team_id,
@@ -951,18 +1015,8 @@ var init_DashboardHeader = __esm({
951
1015
  title: team.team_id
952
1016
  }
953
1017
  )))),
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(
1018
+ /* @__PURE__ */ React3.createElement(GenerateKeyButton, { onClick: onGenerateKeyClick })
1019
+ ), /* @__PURE__ */ React3.createElement(Divider, null), /* @__PURE__ */ React3.createElement(
966
1020
  Box2,
967
1021
  {
968
1022
  sx: {
@@ -974,18 +1028,18 @@ var init_DashboardHeader = __esm({
974
1028
  py: 1.5
975
1029
  }
976
1030
  },
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)));
1031
+ /* @__PURE__ */ React3.createElement(CountStat, { value: counts.total, label: "keys", tone: "accent" }),
1032
+ /* @__PURE__ */ React3.createElement(Divider, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1033
+ /* @__PURE__ */ React3.createElement(CountStat, { value: counts.expired, label: "expired", tone: "danger" }),
1034
+ /* @__PURE__ */ React3.createElement(Divider, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1035
+ /* @__PURE__ */ React3.createElement(CountStat, { value: counts.expiringSoon, label: "expiring soon", tone: "warning" })
1036
+ ), tabs && /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(Divider, null), /* @__PURE__ */ React3.createElement(Box2, { sx: { px: 1 } }, tabs)));
983
1037
  };
984
1038
  }
985
1039
  });
986
1040
 
987
1041
  // src/components/KeysTable.tsx
988
- import React3, { useState, useMemo as useMemo2 } from "react";
1042
+ import React4, { useState, useMemo as useMemo2 } from "react";
989
1043
  import Table from "@mui/material/Table";
990
1044
  import TableBody from "@mui/material/TableBody";
991
1045
  import TableCell from "@mui/material/TableCell";
@@ -1006,7 +1060,7 @@ import CircularProgress from "@mui/material/CircularProgress";
1006
1060
  import Skeleton2 from "@mui/material/Skeleton";
1007
1061
  import InputAdornment from "@mui/material/InputAdornment";
1008
1062
  import { alpha as alpha3 } from "@mui/material/styles";
1009
- import { ContentCopy, Delete, Add as Add2, Edit, Autorenew, Search, Lock, LockOpen } from "@mui/icons-material";
1063
+ import { ContentCopy, Delete, Edit, Autorenew, Search, Lock, LockOpen } from "@mui/icons-material";
1010
1064
  function expiryChipLabel(status, expiresAt) {
1011
1065
  if (status === "expired") return "Expired";
1012
1066
  if (status === "soon") return `${Math.ceil((new Date(expiresAt).getTime() - Date.now()) / 864e5)}d left`;
@@ -1020,12 +1074,12 @@ function expiryTone(status) {
1020
1074
  function ExpiryCell({ expiresAt }) {
1021
1075
  const status = expiryStatus(expiresAt);
1022
1076
  if (!status) {
1023
- return /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary" }, "Never");
1077
+ return /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, "Never");
1024
1078
  }
1025
1079
  if (status === "ok") {
1026
- return /* @__PURE__ */ React3.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(expiresAt));
1080
+ return /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(expiresAt));
1027
1081
  }
1028
- return /* @__PURE__ */ React3.createElement(
1082
+ return /* @__PURE__ */ React4.createElement(
1029
1083
  StatusPill,
1030
1084
  {
1031
1085
  label: expiryChipLabel(status, expiresAt),
@@ -1040,16 +1094,16 @@ function budgetTone(pct) {
1040
1094
  return "accent";
1041
1095
  }
1042
1096
  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" });
1097
+ if (isBlocking) return /* @__PURE__ */ React4.createElement(CircularProgress, { size: 18 });
1098
+ if (blocked) return /* @__PURE__ */ React4.createElement(LockOpen, { fontSize: "small" });
1099
+ return /* @__PURE__ */ React4.createElement(Lock, { fontSize: "small" });
1046
1100
  }
1047
1101
  function BudgetCell({ spend, maxBudget }) {
1048
1102
  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"));
1103
+ 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
1104
  }
1051
1105
  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 }));
1106
+ 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
1107
  }
1054
1108
  function compareKeys(a, b, sortKey) {
1055
1109
  switch (sortKey) {
@@ -1074,6 +1128,7 @@ var init_KeysTable = __esm({
1074
1128
  "src/components/KeysTable.tsx"() {
1075
1129
  "use strict";
1076
1130
  init_api();
1131
+ init_GenerateKeyButton();
1077
1132
  init_ui();
1078
1133
  shortKeyId = (token) => {
1079
1134
  if (!token) return "-";
@@ -1172,32 +1227,27 @@ var init_KeysTable = __esm({
1172
1227
  };
1173
1228
  const renderTableBody = () => {
1174
1229
  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 })));
1230
+ return /* @__PURE__ */ React4.createElement(TableRow, null, /* @__PURE__ */ React4.createElement(TableCell, { colSpan: 8, sx: { py: 2 } }, /* @__PURE__ */ React4.createElement(Skeleton2, { variant: "rounded", height: 140 })));
1176
1231
  }
1177
1232
  if (filteredKeys.length === 0) {
1178
- return /* @__PURE__ */ React3.createElement(TableRow, null, /* @__PURE__ */ React3.createElement(TableCell, { colSpan: 8 }, filterText ? /* @__PURE__ */ React3.createElement(
1233
+ return /* @__PURE__ */ React4.createElement(TableRow, null, /* @__PURE__ */ React4.createElement(TableCell, { colSpan: 8 }, filterText ? /* @__PURE__ */ React4.createElement(
1179
1234
  EmptyState,
1180
1235
  {
1181
1236
  message: "No keys match that filter",
1182
1237
  hint: "Try a different alias or model name."
1183
1238
  }
1184
- ) : /* @__PURE__ */ React3.createElement(
1239
+ ) : /* @__PURE__ */ React4.createElement(
1185
1240
  EmptyState,
1186
1241
  {
1187
1242
  message: "No keys yet",
1188
1243
  hint: "Generate your first key to start calling models.",
1189
- action: /* @__PURE__ */ React3.createElement(
1190
- Button2,
1244
+ action: /* @__PURE__ */ React4.createElement(
1245
+ GenerateKeyButton,
1191
1246
  {
1192
- variant: "contained",
1193
- color: "primary",
1194
1247
  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"
1248
+ label: "Generate Your First Key",
1249
+ onClick: onGenerateKeyClick
1250
+ }
1201
1251
  )
1202
1252
  }
1203
1253
  )));
@@ -1206,7 +1256,7 @@ var init_KeysTable = __esm({
1206
1256
  const keyId = key.token ?? key.key;
1207
1257
  const isBlocking = blockingKeyId === keyId;
1208
1258
  const keyModels = key.models ?? [];
1209
- return /* @__PURE__ */ React3.createElement(
1259
+ return /* @__PURE__ */ React4.createElement(
1210
1260
  TableRow,
1211
1261
  {
1212
1262
  key: keyId,
@@ -1217,8 +1267,8 @@ var init_KeysTable = __esm({
1217
1267
  "& td": { color: theme.palette.text.secondary }
1218
1268
  }) : void 0
1219
1269
  },
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(
1270
+ /* @__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" }))),
1271
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(Box3, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React4.createElement(
1222
1272
  Typography3,
1223
1273
  {
1224
1274
  variant: "body2",
@@ -1235,7 +1285,7 @@ var init_KeysTable = __esm({
1235
1285
  })
1236
1286
  },
1237
1287
  shortKeyId(keyId)
1238
- ), /* @__PURE__ */ React3.createElement(
1288
+ ), /* @__PURE__ */ React4.createElement(
1239
1289
  IconButton,
1240
1290
  {
1241
1291
  size: "small",
@@ -1243,13 +1293,13 @@ var init_KeysTable = __esm({
1243
1293
  title: "Copy Key ID",
1244
1294
  sx: quietIconButtonSx("accent")
1245
1295
  },
1246
- /* @__PURE__ */ React3.createElement(ContentCopy, { sx: { fontSize: 15 } })
1296
+ /* @__PURE__ */ React4.createElement(ContentCopy, { sx: { fontSize: 15 } })
1247
1297
  ))),
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(
1298
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(Typography3, { variant: "body2", color: "text.secondary" }, formatDate(key.created_at))),
1299
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(ExpiryCell, { expiresAt: key.expires_at })),
1300
+ /* @__PURE__ */ React4.createElement(TableCell, null, /* @__PURE__ */ React4.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })),
1301
+ /* @__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")),
1302
+ /* @__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
1303
  TagChip,
1254
1304
  {
1255
1305
  label: `+${keyModels.length - 2}`,
@@ -1257,7 +1307,7 @@ var init_KeysTable = __esm({
1257
1307
  title: keyModels.slice(2).join(", ")
1258
1308
  }
1259
1309
  ))),
1260
- /* @__PURE__ */ React3.createElement(TableCell, { align: "right" }, /* @__PURE__ */ React3.createElement(Box3, { display: "flex", justifyContent: "flex-end", gap: 0.25 }, /* @__PURE__ */ React3.createElement(
1310
+ /* @__PURE__ */ React4.createElement(TableCell, { align: "right" }, /* @__PURE__ */ React4.createElement(Box3, { display: "flex", justifyContent: "flex-end", gap: 0.25 }, /* @__PURE__ */ React4.createElement(
1261
1311
  IconButton,
1262
1312
  {
1263
1313
  size: "small",
@@ -1265,8 +1315,8 @@ var init_KeysTable = __esm({
1265
1315
  title: "Edit key",
1266
1316
  sx: quietIconButtonSx("accent")
1267
1317
  },
1268
- /* @__PURE__ */ React3.createElement(Edit, { fontSize: "small" })
1269
- ), /* @__PURE__ */ React3.createElement(
1318
+ /* @__PURE__ */ React4.createElement(Edit, { fontSize: "small" })
1319
+ ), /* @__PURE__ */ React4.createElement(
1270
1320
  IconButton,
1271
1321
  {
1272
1322
  size: "small",
@@ -1276,7 +1326,7 @@ var init_KeysTable = __esm({
1276
1326
  sx: quietIconButtonSx("warning")
1277
1327
  },
1278
1328
  keyBlockIcon(isBlocking, key.blocked)
1279
- ), /* @__PURE__ */ React3.createElement(
1329
+ ), /* @__PURE__ */ React4.createElement(
1280
1330
  IconButton,
1281
1331
  {
1282
1332
  size: "small",
@@ -1284,18 +1334,18 @@ var init_KeysTable = __esm({
1284
1334
  title: "Revoke key",
1285
1335
  sx: quietIconButtonSx("danger")
1286
1336
  },
1287
- /* @__PURE__ */ React3.createElement(Delete, { fontSize: "small" })
1337
+ /* @__PURE__ */ React4.createElement(Delete, { fontSize: "small" })
1288
1338
  )))
1289
1339
  );
1290
1340
  });
1291
1341
  };
1292
- return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
1342
+ return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
1293
1343
  SectionCard,
1294
1344
  {
1295
1345
  title: "Virtual Keys",
1296
1346
  subtitle: loading ? "Loading\u2026" : `${filteredKeys.length}${filterText ? ` of ${keys.length}` : ""} key${filteredKeys.length === 1 ? "" : "s"}`,
1297
1347
  flush: true,
1298
- actions: /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
1348
+ actions: /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
1299
1349
  TextField,
1300
1350
  {
1301
1351
  size: "small",
@@ -1305,15 +1355,15 @@ var init_KeysTable = __esm({
1305
1355
  onChange: (e) => setFilterText(e.target.value),
1306
1356
  sx: { minWidth: 240 },
1307
1357
  InputProps: {
1308
- startAdornment: /* @__PURE__ */ React3.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React3.createElement(Search, { fontSize: "small", color: "disabled" }))
1358
+ startAdornment: /* @__PURE__ */ React4.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React4.createElement(Search, { fontSize: "small", color: "disabled" }))
1309
1359
  }
1310
1360
  }
1311
- ), expiredKeys.length > 0 && /* @__PURE__ */ React3.createElement(
1361
+ ), expiredKeys.length > 0 && /* @__PURE__ */ React4.createElement(
1312
1362
  Button2,
1313
1363
  {
1314
1364
  variant: "outlined",
1315
1365
  color: "inherit",
1316
- startIcon: /* @__PURE__ */ React3.createElement(Autorenew, null),
1366
+ startIcon: /* @__PURE__ */ React4.createElement(Autorenew, null),
1317
1367
  onClick: () => setPruneConfirmCount(expiredKeys.length),
1318
1368
  sx: (theme) => ({
1319
1369
  color: theme.palette.text.secondary,
@@ -1328,20 +1378,10 @@ var init_KeysTable = __esm({
1328
1378
  "Prune expired (",
1329
1379
  expiredKeys.length,
1330
1380
  ")"
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
- ))
1381
+ ), /* @__PURE__ */ React4.createElement(GenerateKeyButton, { onClick: onGenerateKeyClick }))
1342
1382
  },
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(
1383
+ /* @__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())))
1384
+ ), /* @__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
1385
  Button2,
1346
1386
  {
1347
1387
  onClick: handleConfirmDelete,
@@ -1349,8 +1389,8 @@ var init_KeysTable = __esm({
1349
1389
  color: "error",
1350
1390
  disabled: deleteSubmitting
1351
1391
  },
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(
1392
+ deleteSubmitting ? /* @__PURE__ */ React4.createElement(CircularProgress, { size: 20 }) : "Revoke"
1393
+ ))), /* @__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
1394
  Button2,
1355
1395
  {
1356
1396
  onClick: handlePruneExpired,
@@ -1358,7 +1398,7 @@ var init_KeysTable = __esm({
1358
1398
  color: "error",
1359
1399
  disabled: pruneSubmitting
1360
1400
  },
1361
- pruneSubmitting ? /* @__PURE__ */ React3.createElement(CircularProgress, { size: 20 }) : "Prune"
1401
+ pruneSubmitting ? /* @__PURE__ */ React4.createElement(CircularProgress, { size: 20 }) : "Prune"
1362
1402
  ))));
1363
1403
  };
1364
1404
  }
@@ -1379,7 +1419,7 @@ var init_format = __esm({
1379
1419
  });
1380
1420
 
1381
1421
  // src/components/KeyFormDialog.tsx
1382
- import React4, { useState as useState2, useEffect, useMemo as useMemo3 } from "react";
1422
+ import React5, { useState as useState2, useEffect, useMemo as useMemo3 } from "react";
1383
1423
  import Box4 from "@mui/material/Box";
1384
1424
  import Typography4 from "@mui/material/Typography";
1385
1425
  import Dialog2 from "@mui/material/Dialog";
@@ -1556,14 +1596,14 @@ var init_KeyFormDialog = __esm({
1556
1596
  const snippetKey = tab === "claude-code" ? "claudeCode" : tab;
1557
1597
  const code = snippets[snippetKey];
1558
1598
  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(
1599
+ 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
1600
  Box4,
1561
1601
  {
1562
1602
  position: "relative",
1563
1603
  p: 1.5,
1564
1604
  sx: { backgroundColor: "action.hover", border: "1px solid", borderColor: "divider", borderRadius: 1 }
1565
1605
  },
1566
- /* @__PURE__ */ React4.createElement(
1606
+ /* @__PURE__ */ React5.createElement(
1567
1607
  IconButton2,
1568
1608
  {
1569
1609
  size: "small",
@@ -1571,9 +1611,9 @@ var init_KeyFormDialog = __esm({
1571
1611
  title: "Copy snippet",
1572
1612
  sx: { position: "absolute", top: 4, right: 4 }
1573
1613
  },
1574
- /* @__PURE__ */ React4.createElement(ContentCopy2, { fontSize: "small" })
1614
+ /* @__PURE__ */ React5.createElement(ContentCopy2, { fontSize: "small" })
1575
1615
  ),
1576
- /* @__PURE__ */ React4.createElement(
1616
+ /* @__PURE__ */ React5.createElement(
1577
1617
  Typography4,
1578
1618
  {
1579
1619
  component: "pre",
@@ -1588,7 +1628,7 @@ var init_KeyFormDialog = __esm({
1588
1628
  },
1589
1629
  code
1590
1630
  ),
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.")
1631
+ 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
1632
  ));
1593
1633
  };
1594
1634
  KeyFormDialog = ({
@@ -1743,11 +1783,11 @@ var init_KeyFormDialog = __esm({
1743
1783
  const inCost = fmtCost(m.input_cost_per_token);
1744
1784
  const outCost = fmtCost(m.output_cost_per_token);
1745
1785
  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"));
1786
+ 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
1787
  };
1748
1788
  const renderTeamField = () => {
1749
1789
  if (teams.length > 0) {
1750
- return /* @__PURE__ */ React4.createElement(
1790
+ return /* @__PURE__ */ React5.createElement(
1751
1791
  Autocomplete,
1752
1792
  {
1753
1793
  options: teams,
@@ -1761,7 +1801,7 @@ var init_KeyFormDialog = __esm({
1761
1801
  setFormData({ team_id: team?.team_id, models: restrictedModels });
1762
1802
  },
1763
1803
  disabled: !isCreate,
1764
- renderInput: (params) => /* @__PURE__ */ React4.createElement(
1804
+ renderInput: (params) => /* @__PURE__ */ React5.createElement(
1765
1805
  TextField2,
1766
1806
  {
1767
1807
  ...params,
@@ -1776,14 +1816,14 @@ var init_KeyFormDialog = __esm({
1776
1816
  );
1777
1817
  }
1778
1818
  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.");
1819
+ 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
1820
  }
1781
1821
  return null;
1782
1822
  };
1783
1823
  const editKeyId = keyToEdit?.token ?? keyToEdit?.key ?? "";
1784
1824
  const renderDangerZone = () => {
1785
1825
  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(
1826
+ 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
1827
  Button3,
1788
1828
  {
1789
1829
  size: "small",
@@ -1792,7 +1832,7 @@ var init_KeyFormDialog = __esm({
1792
1832
  onClick: () => setResetSpendConfirm(true)
1793
1833
  },
1794
1834
  "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(
1835
+ ) : /* @__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
1836
  Button3,
1797
1837
  {
1798
1838
  size: "small",
@@ -1801,8 +1841,8 @@ var init_KeyFormDialog = __esm({
1801
1841
  disabled: resetSpendSubmitting,
1802
1842
  onClick: handleResetSpend
1803
1843
  },
1804
- resetSpendSubmitting ? /* @__PURE__ */ React4.createElement(CircularProgress2, { size: 16 }) : "Confirm"
1805
- ), /* @__PURE__ */ React4.createElement(Button3, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel")));
1844
+ resetSpendSubmitting ? /* @__PURE__ */ React5.createElement(CircularProgress2, { size: 16 }) : "Confirm"
1845
+ ), /* @__PURE__ */ React5.createElement(Button3, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel")));
1806
1846
  };
1807
1847
  const maskKey = (key) => {
1808
1848
  if (key.length <= 8) return "***";
@@ -1812,7 +1852,7 @@ var init_KeyFormDialog = __esm({
1812
1852
  if (newKeyValue) dialogTitle = "Key Generated";
1813
1853
  else if (isCreate) dialogTitle = "Generate New Key";
1814
1854
  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(
1855
+ 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
1856
  Box4,
1817
1857
  {
1818
1858
  display: "flex",
@@ -1827,7 +1867,7 @@ var init_KeyFormDialog = __esm({
1827
1867
  borderRadius: 1
1828
1868
  }
1829
1869
  },
1830
- /* @__PURE__ */ React4.createElement(
1870
+ /* @__PURE__ */ React5.createElement(
1831
1871
  Typography4,
1832
1872
  {
1833
1873
  component: "code",
@@ -1836,8 +1876,8 @@ var init_KeyFormDialog = __esm({
1836
1876
  },
1837
1877
  newKeyValue
1838
1878
  ),
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(
1879
+ /* @__PURE__ */ React5.createElement(IconButton2, { onClick: () => copyToClipboard(newKeyValue) }, /* @__PURE__ */ React5.createElement(ContentCopy2, null))
1880
+ ), 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
1881
  Box4,
1842
1882
  {
1843
1883
  display: "flex",
@@ -1851,7 +1891,7 @@ var init_KeyFormDialog = __esm({
1851
1891
  borderRadius: 1
1852
1892
  }
1853
1893
  },
1854
- /* @__PURE__ */ React4.createElement(
1894
+ /* @__PURE__ */ React5.createElement(
1855
1895
  Typography4,
1856
1896
  {
1857
1897
  component: "code",
@@ -1860,8 +1900,8 @@ var init_KeyFormDialog = __esm({
1860
1900
  },
1861
1901
  newKeySnippets.publicEndpoint
1862
1902
  ),
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(
1903
+ /* @__PURE__ */ React5.createElement(IconButton2, { size: "small", onClick: () => copyToClipboard(newKeySnippets.publicEndpoint) }, /* @__PURE__ */ React5.createElement(ContentCopy2, { fontSize: "small" }))
1904
+ )), 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
1905
  TextField2,
1866
1906
  {
1867
1907
  label: "Alias",
@@ -1877,7 +1917,7 @@ var init_KeyFormDialog = __esm({
1877
1917
  required: true,
1878
1918
  fullWidth: true
1879
1919
  }
1880
- ), !isCreate ? null : /* @__PURE__ */ React4.createElement(
1920
+ ), !isCreate ? null : /* @__PURE__ */ React5.createElement(
1881
1921
  TextField2,
1882
1922
  {
1883
1923
  select: true,
@@ -1886,12 +1926,12 @@ var init_KeyFormDialog = __esm({
1886
1926
  onChange: (e) => setFormData({ duration: e.target.value }),
1887
1927
  fullWidth: true
1888
1928
  },
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(
1929
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "1d" }, "1 Day"),
1930
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "7d" }, "7 Days"),
1931
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "30d" }, "30 Days"),
1932
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "90d" }, "90 Days"),
1933
+ /* @__PURE__ */ React5.createElement(MenuItem, { value: "1y" }, "1 Year")
1934
+ ), renderTeamField(), availableModels.length > 0 && /* @__PURE__ */ React5.createElement(
1895
1935
  Autocomplete,
1896
1936
  {
1897
1937
  multiple: true,
@@ -1900,8 +1940,8 @@ var init_KeyFormDialog = __esm({
1900
1940
  getOptionLabel: (m) => m.model_name,
1901
1941
  value: selectedModels,
1902
1942
  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(
1943
+ renderOption: (props, m) => /* @__PURE__ */ React5.createElement("li", { ...props }, modelOption(m)),
1944
+ renderInput: (params) => /* @__PURE__ */ React5.createElement(
1905
1945
  TextField2,
1906
1946
  {
1907
1947
  ...params,
@@ -1911,10 +1951,10 @@ var init_KeyFormDialog = __esm({
1911
1951
  }
1912
1952
  )
1913
1953
  }
1914
- ), allowUnlimitedBudget && /* @__PURE__ */ React4.createElement(
1954
+ ), allowUnlimitedBudget && /* @__PURE__ */ React5.createElement(
1915
1955
  FormControlLabel,
1916
1956
  {
1917
- control: /* @__PURE__ */ React4.createElement(
1957
+ control: /* @__PURE__ */ React5.createElement(
1918
1958
  Checkbox,
1919
1959
  {
1920
1960
  checked: unlimitedBudget,
@@ -1930,7 +1970,7 @@ var init_KeyFormDialog = __esm({
1930
1970
  ),
1931
1971
  label: "Unlimited budget"
1932
1972
  }
1933
- ), /* @__PURE__ */ React4.createElement(
1973
+ ), /* @__PURE__ */ React5.createElement(
1934
1974
  TextField2,
1935
1975
  {
1936
1976
  label: "Max Budget (USD)",
@@ -1943,7 +1983,7 @@ var init_KeyFormDialog = __esm({
1943
1983
  required: true,
1944
1984
  fullWidth: true
1945
1985
  }
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(
1986
+ ), /* @__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
1987
  TextField2,
1948
1988
  {
1949
1989
  label: "TPM Limit",
@@ -1953,7 +1993,7 @@ var init_KeyFormDialog = __esm({
1953
1993
  helperText: "Max tokens per minute this key can consume across all models. Leave blank for no limit.",
1954
1994
  fullWidth: true
1955
1995
  }
1956
- ), /* @__PURE__ */ React4.createElement(
1996
+ ), /* @__PURE__ */ React5.createElement(
1957
1997
  TextField2,
1958
1998
  {
1959
1999
  label: "RPM Limit",
@@ -1963,7 +2003,7 @@ var init_KeyFormDialog = __esm({
1963
2003
  helperText: "Max requests per minute this key can make across all models. Leave blank for no limit.",
1964
2004
  fullWidth: true
1965
2005
  }
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(
2006
+ ))), 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
2007
  Button3,
1968
2008
  {
1969
2009
  onClick: isCreate ? handleGenerate : handleUpdate,
@@ -1971,14 +2011,14 @@ var init_KeyFormDialog = __esm({
1971
2011
  color: "primary",
1972
2012
  disabled: !canSubmit
1973
2013
  },
1974
- submitting ? /* @__PURE__ */ React4.createElement(CircularProgress2, { size: 24 }) : submitLabel
2014
+ submitting ? /* @__PURE__ */ React5.createElement(CircularProgress2, { size: 24 }) : submitLabel
1975
2015
  ))));
1976
2016
  };
1977
2017
  }
1978
2018
  });
1979
2019
 
1980
2020
  // src/components/ManageTeamDialog.tsx
1981
- import React5, { useState as useState3, useEffect as useEffect2, useMemo as useMemo4 } from "react";
2021
+ import React6, { useState as useState3, useEffect as useEffect2, useMemo as useMemo4 } from "react";
1982
2022
  import Dialog3 from "@mui/material/Dialog";
1983
2023
  import DialogTitle3 from "@mui/material/DialogTitle";
1984
2024
  import DialogContent3 from "@mui/material/DialogContent";
@@ -2247,7 +2287,7 @@ var init_ManageTeamDialog = __esm({
2247
2287
  const showMcpServers = mode === "edit" && !!canManageMcpServers;
2248
2288
  const mcpOptions = (mcpServers ?? []).map((s) => s.id);
2249
2289
  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(
2290
+ 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
2291
  TextField3,
2252
2292
  {
2253
2293
  label: "Team Alias",
@@ -2256,7 +2296,7 @@ var init_ManageTeamDialog = __esm({
2256
2296
  disabled: submitting,
2257
2297
  fullWidth: true
2258
2298
  }
2259
- ), /* @__PURE__ */ React5.createElement(
2299
+ ), /* @__PURE__ */ React6.createElement(
2260
2300
  Autocomplete2,
2261
2301
  {
2262
2302
  multiple: true,
@@ -2264,7 +2304,7 @@ var init_ManageTeamDialog = __esm({
2264
2304
  value: models,
2265
2305
  onChange: (_, newValue) => setModels(newValue),
2266
2306
  disabled: submitting,
2267
- renderInput: (params) => /* @__PURE__ */ React5.createElement(
2307
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(
2268
2308
  TextField3,
2269
2309
  {
2270
2310
  ...params,
@@ -2274,7 +2314,7 @@ var init_ManageTeamDialog = __esm({
2274
2314
  }
2275
2315
  )
2276
2316
  }
2277
- ), /* @__PURE__ */ React5.createElement(
2317
+ ), /* @__PURE__ */ React6.createElement(
2278
2318
  TextField3,
2279
2319
  {
2280
2320
  label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
@@ -2286,13 +2326,13 @@ var init_ManageTeamDialog = __esm({
2286
2326
  helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
2287
2327
  fullWidth: true
2288
2328
  }
2289
- ), allowUnlimitedBudget && /* @__PURE__ */ React5.createElement(
2329
+ ), allowUnlimitedBudget && /* @__PURE__ */ React6.createElement(
2290
2330
  FormControlLabel2,
2291
2331
  {
2292
- control: /* @__PURE__ */ React5.createElement(Checkbox2, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
2332
+ control: /* @__PURE__ */ React6.createElement(Checkbox2, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
2293
2333
  label: "Unlimited Budget"
2294
2334
  }
2295
- ), /* @__PURE__ */ React5.createElement(
2335
+ ), /* @__PURE__ */ React6.createElement(
2296
2336
  TextField3,
2297
2337
  {
2298
2338
  select: true,
@@ -2303,8 +2343,8 @@ var init_ManageTeamDialog = __esm({
2303
2343
  helperText: "Spend-reset period for the team budget",
2304
2344
  fullWidth: true
2305
2345
  },
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(
2346
+ durationOptions.map((o) => /* @__PURE__ */ React6.createElement(MenuItem2, { key: o.value, value: o.value }, o.label))
2347
+ ), 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
2348
  Typography5,
2309
2349
  {
2310
2350
  variant: "caption",
@@ -2312,14 +2352,14 @@ var init_ManageTeamDialog = __esm({
2312
2352
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
2313
2353
  },
2314
2354
  m.user_id
2315
- )) : /* @__PURE__ */ React5.createElement(
2355
+ )) : /* @__PURE__ */ React6.createElement(
2316
2356
  Typography5,
2317
2357
  {
2318
2358
  variant: "body2",
2319
2359
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
2320
2360
  },
2321
2361
  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(
2362
+ )), /* @__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
2363
  IconButton3,
2324
2364
  {
2325
2365
  edge: "end",
@@ -2328,8 +2368,8 @@ var init_ManageTeamDialog = __esm({
2328
2368
  disabled: memberBusy,
2329
2369
  onClick: () => handleRemoveMember(m.user_id)
2330
2370
  },
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(
2371
+ /* @__PURE__ */ React6.createElement(DeleteIcon, { fontSize: "small" })
2372
+ ))))))), /* @__PURE__ */ React6.createElement(Box5, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" } }, /* @__PURE__ */ React6.createElement(
2333
2373
  Autocomplete2,
2334
2374
  {
2335
2375
  freeSolo: true,
@@ -2353,7 +2393,7 @@ var init_ManageTeamDialog = __esm({
2353
2393
  isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
2354
2394
  disabled: memberBusy,
2355
2395
  sx: { flex: 1, minWidth: 260 },
2356
- renderInput: (params) => /* @__PURE__ */ React5.createElement(
2396
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(
2357
2397
  TextField3,
2358
2398
  {
2359
2399
  ...params,
@@ -2363,12 +2403,12 @@ var init_ManageTeamDialog = __esm({
2363
2403
  helperText: "Pick a catalog user, or paste a user entity ref",
2364
2404
  InputProps: {
2365
2405
  ...params.InputProps,
2366
- endAdornment: /* @__PURE__ */ React5.createElement(React5.Fragment, null, usersLoading ? /* @__PURE__ */ React5.createElement(CircularProgress3, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2406
+ endAdornment: /* @__PURE__ */ React6.createElement(React6.Fragment, null, usersLoading ? /* @__PURE__ */ React6.createElement(CircularProgress3, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2367
2407
  }
2368
2408
  }
2369
2409
  )
2370
2410
  }
2371
- ), /* @__PURE__ */ React5.createElement(
2411
+ ), /* @__PURE__ */ React6.createElement(
2372
2412
  TextField3,
2373
2413
  {
2374
2414
  label: "Max budget in team ($)",
@@ -2379,7 +2419,7 @@ var init_ManageTeamDialog = __esm({
2379
2419
  size: "small",
2380
2420
  sx: { width: 160 }
2381
2421
  }
2382
- ), /* @__PURE__ */ React5.createElement(
2422
+ ), /* @__PURE__ */ React6.createElement(
2383
2423
  Button4,
2384
2424
  {
2385
2425
  onClick: handleAddMember,
@@ -2388,7 +2428,7 @@ var init_ManageTeamDialog = __esm({
2388
2428
  sx: { mt: 0.5 }
2389
2429
  },
2390
2430
  "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(
2431
+ ))), 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
2432
  Autocomplete2,
2393
2433
  {
2394
2434
  multiple: true,
@@ -2397,9 +2437,9 @@ var init_ManageTeamDialog = __esm({
2397
2437
  getOptionLabel: kbLabel,
2398
2438
  onChange: (_, v) => setKbIds(v),
2399
2439
  disabled: kbBusy,
2400
- renderInput: (params) => /* @__PURE__ */ React5.createElement(TextField3, { ...params, label: "Attached knowledge bases" })
2440
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(TextField3, { ...params, label: "Attached knowledge bases" })
2401
2441
  }
2402
- ), /* @__PURE__ */ React5.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React5.createElement(
2442
+ ), /* @__PURE__ */ React6.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React6.createElement(
2403
2443
  Button4,
2404
2444
  {
2405
2445
  onClick: handleSaveKnowledgeBases,
@@ -2407,7 +2447,7 @@ var init_ManageTeamDialog = __esm({
2407
2447
  variant: "outlined"
2408
2448
  },
2409
2449
  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(
2450
+ ))), 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
2451
  Autocomplete2,
2412
2452
  {
2413
2453
  multiple: true,
@@ -2416,9 +2456,9 @@ var init_ManageTeamDialog = __esm({
2416
2456
  getOptionLabel: mcpLabel,
2417
2457
  onChange: (_, v) => setMcpIds(v),
2418
2458
  disabled: mcpBusy,
2419
- renderInput: (params) => /* @__PURE__ */ React5.createElement(TextField3, { ...params, label: "Attached MCP servers" })
2459
+ renderInput: (params) => /* @__PURE__ */ React6.createElement(TextField3, { ...params, label: "Attached MCP servers" })
2420
2460
  }
2421
- ), /* @__PURE__ */ React5.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React5.createElement(
2461
+ ), /* @__PURE__ */ React6.createElement(Box5, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ React6.createElement(
2422
2462
  Button4,
2423
2463
  {
2424
2464
  onClick: handleSaveMcpServers,
@@ -2426,13 +2466,13 @@ var init_ManageTeamDialog = __esm({
2426
2466
  variant: "outlined"
2427
2467
  },
2428
2468
  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")));
2469
+ )))), /* @__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
2470
  };
2431
2471
  }
2432
2472
  });
2433
2473
 
2434
2474
  // src/components/UsageStats.tsx
2435
- import React6, { useMemo as useMemo5, useState as useState4 } from "react";
2475
+ import React7, { useMemo as useMemo5, useState as useState4 } from "react";
2436
2476
  import Paper4 from "@mui/material/Paper";
2437
2477
  import Box6 from "@mui/material/Box";
2438
2478
  import Typography6 from "@mui/material/Typography";
@@ -2482,16 +2522,16 @@ var init_UsageStats = __esm({
2482
2522
  "30d": "Last 30 days"
2483
2523
  };
2484
2524
  fmtPct = (n) => `${(n * 100).toFixed(1)}%`;
2485
- ChartSkeleton = ({ height = 240 }) => /* @__PURE__ */ React6.createElement(Skeleton3, { variant: "rounded", height });
2525
+ ChartSkeleton = ({ height = 240 }) => /* @__PURE__ */ React7.createElement(Skeleton3, { variant: "rounded", height });
2486
2526
  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);
2527
+ if (loading) return /* @__PURE__ */ React7.createElement(ChartSkeleton, { height });
2528
+ if (empty) return /* @__PURE__ */ React7.createElement(EmptyState, { message: "No data for this period", height });
2529
+ return /* @__PURE__ */ React7.createElement(React7.Fragment, null, children);
2490
2530
  };
2491
2531
  SuccessRateCell = ({ rate, requests }) => {
2492
- if (requests === 0) return /* @__PURE__ */ React6.createElement(Typography6, { variant: "body2", color: "text.secondary" }, "\u2014");
2532
+ if (requests === 0) return /* @__PURE__ */ React7.createElement(Typography6, { variant: "body2", color: "text.secondary" }, "\u2014");
2493
2533
  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(
2534
+ 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
2535
  Typography6,
2496
2536
  {
2497
2537
  variant: "caption",
@@ -2640,23 +2680,23 @@ var init_UsageStats = __esm({
2640
2680
  ];
2641
2681
  const renderKeyRows = () => {
2642
2682
  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 })));
2683
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ React7.createElement(Skeleton3, { variant: "rounded", height: 80 })));
2644
2684
  }
2645
2685
  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" })));
2686
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 7 }, /* @__PURE__ */ React7.createElement(EmptyState, { message: "No key activity in this period" })));
2647
2687
  }
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 }))));
2688
+ 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
2689
  };
2650
2690
  const renderModelRows = () => {
2651
2691
  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 })));
2692
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ React7.createElement(Skeleton3, { variant: "rounded", height: 80 })));
2653
2693
  }
2654
2694
  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" })));
2695
+ return /* @__PURE__ */ React7.createElement(TableRow3, null, /* @__PURE__ */ React7.createElement(TableCell3, { colSpan: 8 }, /* @__PURE__ */ React7.createElement(EmptyState, { message: "No model activity in this period" })));
2656
2696
  }
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 }))));
2697
+ 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
2698
  };
2659
- const periodSelect = /* @__PURE__ */ React6.createElement(
2699
+ const periodSelect = /* @__PURE__ */ React7.createElement(
2660
2700
  TextField4,
2661
2701
  {
2662
2702
  select: true,
@@ -2666,17 +2706,17 @@ var init_UsageStats = __esm({
2666
2706
  onChange: (e) => handlePresetChange(e.target.value),
2667
2707
  sx: { minWidth: 160 }
2668
2708
  },
2669
- Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ React6.createElement(MenuItem3, { key: p, value: p }, PRESET_LABELS[p]))
2709
+ Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ React7.createElement(MenuItem3, { key: p, value: p }, PRESET_LABELS[p]))
2670
2710
  );
2671
- return /* @__PURE__ */ React6.createElement(
2711
+ return /* @__PURE__ */ React7.createElement(
2672
2712
  SectionCard,
2673
2713
  {
2674
2714
  title: "Usage Analytics",
2675
2715
  subtitle: `${PRESET_LABELS[currentPreset]} \xB7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`,
2676
2716
  actions: periodSelect
2677
2717
  },
2678
- /* @__PURE__ */ React6.createElement(MetricStrip, { metrics }),
2679
- /* @__PURE__ */ React6.createElement(
2718
+ /* @__PURE__ */ React7.createElement(MetricStrip, { metrics }),
2719
+ /* @__PURE__ */ React7.createElement(
2680
2720
  Box6,
2681
2721
  {
2682
2722
  sx: {
@@ -2689,7 +2729,7 @@ var init_UsageStats = __esm({
2689
2729
  mb: 2
2690
2730
  }
2691
2731
  },
2692
- /* @__PURE__ */ React6.createElement(
2732
+ /* @__PURE__ */ React7.createElement(
2693
2733
  SegmentedControl,
2694
2734
  {
2695
2735
  value: tab,
@@ -2701,7 +2741,7 @@ var init_UsageStats = __esm({
2701
2741
  ]
2702
2742
  }
2703
2743
  ),
2704
- tab === "models" && /* @__PURE__ */ React6.createElement(
2744
+ tab === "models" && /* @__PURE__ */ React7.createElement(
2705
2745
  TextField4,
2706
2746
  {
2707
2747
  select: true,
@@ -2711,17 +2751,17 @@ var init_UsageStats = __esm({
2711
2751
  onChange: (e) => setSelectedModel(e.target.value),
2712
2752
  sx: { minWidth: 220 }
2713
2753
  },
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))
2754
+ /* @__PURE__ */ React7.createElement(MenuItem3, { value: "all" }, "All models"),
2755
+ models.map((m) => /* @__PURE__ */ React7.createElement(MenuItem3, { key: m.model_name, value: m.model_name }, m.model_name))
2716
2756
  )
2717
2757
  ),
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(
2758
+ 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
2759
  Tooltip,
2720
2760
  {
2721
2761
  cursor: chart.cursor,
2722
- content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtUsd, hideZero: true })
2762
+ content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtUsd, hideZero: true })
2723
2763
  }
2724
- ), topSpendModels.map((m) => /* @__PURE__ */ React6.createElement(
2764
+ ), topSpendModels.map((m) => /* @__PURE__ */ React7.createElement(
2725
2765
  Area,
2726
2766
  {
2727
2767
  key: m,
@@ -2733,13 +2773,13 @@ var init_UsageStats = __esm({
2733
2773
  fill: chartColor(m),
2734
2774
  fillOpacity: 0.28
2735
2775
  }
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(
2776
+ ))))), !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
2777
  Tooltip,
2738
2778
  {
2739
2779
  cursor: chart.cursor,
2740
- content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: (v) => `${v}%` })
2780
+ content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: (v) => `${v}%` })
2741
2781
  }
2742
- ), /* @__PURE__ */ React6.createElement(ReferenceLine, { y: 100, stroke: SERIES.success, strokeDasharray: "4 4", strokeOpacity: 0.5 }), /* @__PURE__ */ React6.createElement(
2782
+ ), /* @__PURE__ */ React7.createElement(ReferenceLine, { y: 100, stroke: SERIES.success, strokeDasharray: "4 4", strokeOpacity: 0.5 }), /* @__PURE__ */ React7.createElement(
2743
2783
  Line,
2744
2784
  {
2745
2785
  type: "monotone",
@@ -2750,13 +2790,13 @@ var init_UsageStats = __esm({
2750
2790
  dot: { r: 2.5, strokeWidth: 0, fill: SERIES.input },
2751
2791
  activeDot: { r: 4 }
2752
2792
  }
2753
- )))))), /* @__PURE__ */ React6.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React6.createElement(
2793
+ )))))), /* @__PURE__ */ React7.createElement(Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ React7.createElement(
2754
2794
  ChartCard,
2755
2795
  {
2756
2796
  title: maxBudget > 0 ? "Cumulative spend vs budget" : "Cumulative spend",
2757
2797
  meta: maxBudget > 0 ? `${fmtUsd(totalCumSpend)} used \xB7 ${fmtUsd(Math.max(0, maxBudget - totalCumSpend))} left` : void 0
2758
2798
  },
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(
2799
+ /* @__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
2800
  YAxis,
2761
2801
  {
2762
2802
  tickFormatter: fmtUsdCompact,
@@ -2764,13 +2804,13 @@ var init_UsageStats = __esm({
2764
2804
  domain: cumulativeDomain,
2765
2805
  ...chart.axis
2766
2806
  }
2767
- ), /* @__PURE__ */ React6.createElement(
2807
+ ), /* @__PURE__ */ React7.createElement(
2768
2808
  Tooltip,
2769
2809
  {
2770
2810
  cursor: chart.cursor,
2771
- content: /* @__PURE__ */ React6.createElement(ChartTooltip, { valueFormatter: fmtUsd })
2811
+ content: /* @__PURE__ */ React7.createElement(ChartTooltip, { valueFormatter: fmtUsd })
2772
2812
  }
2773
- ), maxBudget > 0 && /* @__PURE__ */ React6.createElement(
2813
+ ), maxBudget > 0 && /* @__PURE__ */ React7.createElement(
2774
2814
  ReferenceLine,
2775
2815
  {
2776
2816
  y: maxBudget,
@@ -2778,7 +2818,7 @@ var init_UsageStats = __esm({
2778
2818
  strokeDasharray: "5 4",
2779
2819
  label: { value: `Budget ${fmtUsd(maxBudget)}`, position: "insideTopRight", fontSize: 10, fill: SERIES.budget }
2780
2820
  }
2781
- ), /* @__PURE__ */ React6.createElement(
2821
+ ), /* @__PURE__ */ React7.createElement(
2782
2822
  Area,
2783
2823
  {
2784
2824
  type: "monotone",
@@ -2791,32 +2831,32 @@ var init_UsageStats = __esm({
2791
2831
  }
2792
2832
  ))))
2793
2833
  ))),
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(
2834
+ 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
2835
  ChartOrFallback,
2796
2836
  {
2797
2837
  loading,
2798
2838
  empty: topModelSpendBars.length === 0,
2799
2839
  height: Math.max(200, topModelSpendBars.length * 34)
2800
2840
  },
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(
2841
+ /* @__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) })))))
2842
+ ))), /* @__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
2843
  ChartOrFallback,
2804
2844
  {
2805
2845
  loading,
2806
2846
  empty: modelRows.length === 0,
2807
2847
  height: Math.max(200, topModelSpendBars.length * 34)
2808
2848
  },
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(
2849
+ /* @__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] })))
2850
+ ))), /* @__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()))))),
2851
+ 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
2852
  ChartOrFallback,
2813
2853
  {
2814
2854
  loading,
2815
2855
  empty: topKeySpendBars.length === 0,
2816
2856
  height: Math.max(160, topKeySpendBars.length * 32)
2817
2857
  },
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())))))
2858
+ /* @__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 })))
2859
+ ))), /* @__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
2860
  );
2821
2861
  };
2822
2862
  }
@@ -2944,12 +2984,12 @@ var init_budget = __esm({
2944
2984
  });
2945
2985
 
2946
2986
  // src/components/BudgetLimitList.tsx
2947
- import React7 from "react";
2987
+ import React8 from "react";
2948
2988
  import Box7 from "@mui/material/Box";
2949
2989
  import Paper5 from "@mui/material/Paper";
2950
2990
  import Typography7 from "@mui/material/Typography";
2951
2991
  import { alpha as alpha4, useTheme as useTheme2 } from "@mui/material/styles";
2952
- import { Link } from "@backstage/core-components";
2992
+ import { Link as Link2 } from "@backstage/core-components";
2953
2993
  function levelToneColor(tone, theme) {
2954
2994
  switch (tone) {
2955
2995
  case "success":
@@ -2975,7 +3015,7 @@ var init_BudgetLimitList = __esm({
2975
3015
  const tone = budgetTone2(limit.pct);
2976
3016
  const pct = Math.round(limit.pct);
2977
3017
  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(
3018
+ 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
3019
  Typography7,
2980
3020
  {
2981
3021
  variant: "body2",
@@ -2983,7 +3023,7 @@ var init_BudgetLimitList = __esm({
2983
3023
  title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label
2984
3024
  },
2985
3025
  limit.label
2986
- ), limit.sublabel && /* @__PURE__ */ React7.createElement(
3026
+ ), limit.sublabel && /* @__PURE__ */ React8.createElement(
2987
3027
  Typography7,
2988
3028
  {
2989
3029
  variant: "caption",
@@ -2998,7 +3038,7 @@ var init_BudgetLimitList = __esm({
2998
3038
  }
2999
3039
  },
3000
3040
  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(
3041
+ )), 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
3042
  Box7,
3003
3043
  {
3004
3044
  sx: {
@@ -3009,14 +3049,14 @@ var init_BudgetLimitList = __esm({
3009
3049
  mt: 0.75
3010
3050
  }
3011
3051
  },
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")
3052
+ /* @__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`)),
3053
+ /* @__PURE__ */ React8.createElement(Typography7, { variant: "caption", color: "text.secondary" }, fmtBudgetDuration(limit.budgetDuration) ? `resets ${fmtBudgetDuration(limit.budgetDuration)}` : "never resets")
3014
3054
  ));
3015
3055
  };
3016
3056
  TaggedLimit = ({ limit }) => {
3017
3057
  const theme = useTheme2();
3018
3058
  const tone = budgetTone2(limit.pct);
3019
- return /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(
3059
+ return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(
3020
3060
  Typography7,
3021
3061
  {
3022
3062
  sx: {
@@ -3029,7 +3069,7 @@ var init_BudgetLimitList = __esm({
3029
3069
  }
3030
3070
  },
3031
3071
  limit.kind
3032
- ), /* @__PURE__ */ React7.createElement(LimitCard, { limit }));
3072
+ ), /* @__PURE__ */ React8.createElement(LimitCard, { limit }));
3033
3073
  };
3034
3074
  MoreKeysNote = ({
3035
3075
  count,
@@ -3038,12 +3078,12 @@ var init_BudgetLimitList = __esm({
3038
3078
  }) => {
3039
3079
  const text = label ?? `+${count} more budgeted key${count > 1 ? "s" : ""} further from the cap`;
3040
3080
  if (!href) {
3041
- return /* @__PURE__ */ React7.createElement(Typography7, { variant: "caption", color: "text.secondary" }, text);
3081
+ return /* @__PURE__ */ React8.createElement(Typography7, { variant: "caption", color: "text.secondary" }, text);
3042
3082
  }
3043
- return /* @__PURE__ */ React7.createElement(Link, { to: href, variant: "caption" }, text, " \u2192");
3083
+ return /* @__PURE__ */ React8.createElement(Link2, { to: href, variant: "caption" }, text, " \u2192");
3044
3084
  };
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(
3085
+ 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 }));
3086
+ LimitListPanel = ({ children }) => /* @__PURE__ */ React8.createElement(
3047
3087
  Box7,
3048
3088
  {
3049
3089
  sx: (theme) => ({
@@ -3059,7 +3099,7 @@ var init_BudgetLimitList = __esm({
3059
3099
  });
3060
3100
 
3061
3101
  // src/components/LiteLLMBudgetWidget.tsx
3062
- import React8, { useEffect as useEffect3, useMemo as useMemo6, useState as useState5 } from "react";
3102
+ import React9, { useEffect as useEffect3, useMemo as useMemo6, useState as useState5 } from "react";
3063
3103
  import Paper6 from "@mui/material/Paper";
3064
3104
  import Box8 from "@mui/material/Box";
3065
3105
  import Typography8 from "@mui/material/Typography";
@@ -3086,7 +3126,7 @@ var init_LiteLLMBudgetWidget = __esm({
3086
3126
  tone,
3087
3127
  isLast,
3088
3128
  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(
3129
+ }) => /* @__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
3130
  Box8,
3091
3131
  {
3092
3132
  sx: (theme) => ({
@@ -3104,7 +3144,7 @@ var init_LiteLLMBudgetWidget = __esm({
3104
3144
  })
3105
3145
  },
3106
3146
  rank
3107
- ), /* @__PURE__ */ React8.createElement(
3147
+ ), /* @__PURE__ */ React9.createElement(
3108
3148
  Box8,
3109
3149
  {
3110
3150
  sx: (theme) => ({
@@ -3114,7 +3154,7 @@ var init_LiteLLMBudgetWidget = __esm({
3114
3154
  bgcolor: isLast ? "transparent" : alpha5(theme.palette.text.primary, 0.12)
3115
3155
  })
3116
3156
  }
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(
3157
+ )), /* @__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
3158
  Typography8,
3119
3159
  {
3120
3160
  sx: (theme) => ({
@@ -3126,8 +3166,8 @@ var init_LiteLLMBudgetWidget = __esm({
3126
3166
  })
3127
3167
  },
3128
3168
  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(
3169
+ ), /* @__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)));
3170
+ EmptyLimitCard = ({ children }) => /* @__PURE__ */ React9.createElement(
3131
3171
  Paper6,
3132
3172
  {
3133
3173
  variant: "outlined",
@@ -3138,7 +3178,7 @@ var init_LiteLLMBudgetWidget = __esm({
3138
3178
  bgcolor: alpha5(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.03 : 0.015)
3139
3179
  })
3140
3180
  },
3141
- /* @__PURE__ */ React8.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, children)
3181
+ /* @__PURE__ */ React9.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, children)
3142
3182
  );
3143
3183
  CLOSEST_LEVEL_LABEL = {
3144
3184
  key: "key",
@@ -3146,7 +3186,7 @@ var init_LiteLLMBudgetWidget = __esm({
3146
3186
  team: "team"
3147
3187
  };
3148
3188
  KEYS_PATH = "/litellm?tab=keys";
3149
- HierarchyNote = ({ withReset }) => /* @__PURE__ */ React8.createElement(
3189
+ HierarchyNote = ({ withReset }) => /* @__PURE__ */ React9.createElement(
3150
3190
  Box8,
3151
3191
  {
3152
3192
  sx: (theme) => ({
@@ -3157,11 +3197,11 @@ var init_LiteLLMBudgetWidget = __esm({
3157
3197
  borderColor: alpha5(theme.palette.text.primary, 0.18)
3158
3198
  })
3159
3199
  },
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.")
3200
+ /* @__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
3201
  );
3162
3202
  FullBody = ({ summary }) => {
3163
3203
  const hasBudgetedKeys = summary.keys.length + summary.hiddenBudgetedKeys > 0;
3164
- return /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(
3204
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
3165
3205
  LevelFrame,
3166
3206
  {
3167
3207
  rank: 1,
@@ -3169,10 +3209,10 @@ var init_LiteLLMBudgetWidget = __esm({
3169
3209
  tagline: "per-key cap \xB7 highest priority",
3170
3210
  note: hasBudgetedKeys ? void 0 : "no key budgets set"
3171
3211
  },
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(
3212
+ !hasBudgetedKeys && /* @__PURE__ */ React9.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3213
+ summary.keys.map((k) => /* @__PURE__ */ React9.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3214
+ summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ React9.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH })
3215
+ ), /* @__PURE__ */ React9.createElement(
3176
3216
  LevelFrame,
3177
3217
  {
3178
3218
  rank: 2,
@@ -3180,15 +3220,15 @@ var init_LiteLLMBudgetWidget = __esm({
3180
3220
  tagline: "cap on everything you spend with your own keys",
3181
3221
  note: "skipped for team-bound keys"
3182
3222
  },
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 })));
3223
+ summary.user ? /* @__PURE__ */ React9.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ React9.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3224
+ ), /* @__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
3225
  };
3186
3226
  CompactBody = ({ summary }) => {
3187
3227
  const { count } = budgetHeadline(summary);
3188
3228
  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.");
3229
+ return /* @__PURE__ */ React9.createElement(Typography8, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3190
3230
  }
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 })));
3231
+ 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
3232
  };
3193
3233
  LiteLLMBudgetWidget = ({
3194
3234
  title = "Budget Policy",
@@ -3239,8 +3279,8 @@ var init_LiteLLMBudgetWidget = __esm({
3239
3279
  headline.closest.pct
3240
3280
  )}%`;
3241
3281
  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(
3282
+ 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 })));
3283
+ return /* @__PURE__ */ React9.createElement(Paper6, { sx: { p: 2 } }, collapsible ? /* @__PURE__ */ React9.createElement(
3244
3284
  Box8,
3245
3285
  {
3246
3286
  onClick: () => setExpanded((e) => !e),
@@ -3253,14 +3293,14 @@ var init_LiteLLMBudgetWidget = __esm({
3253
3293
  mb: expanded ? 1.5 : 0
3254
3294
  }
3255
3295
  },
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(
3296
+ /* @__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
3297
  StatusPill,
3258
3298
  {
3259
3299
  label: summaryText,
3260
3300
  tone: budgetTone2(headline.closest?.pct ?? 0)
3261
3301
  }
3262
3302
  ))),
3263
- /* @__PURE__ */ React8.createElement(
3303
+ /* @__PURE__ */ React9.createElement(
3264
3304
  IconButton4,
3265
3305
  {
3266
3306
  size: "small",
@@ -3276,9 +3316,9 @@ var init_LiteLLMBudgetWidget = __esm({
3276
3316
  transition: theme.transitions.create("transform")
3277
3317
  })
3278
3318
  },
3279
- /* @__PURE__ */ React8.createElement(ExpandMore2, null)
3319
+ /* @__PURE__ */ React9.createElement(ExpandMore2, null)
3280
3320
  )
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(
3321
+ ) : /* @__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
3322
  Box8,
3283
3323
  {
3284
3324
  sx: (theme) => ({
@@ -3294,7 +3334,7 @@ var init_LiteLLMBudgetWidget = __esm({
3294
3334
  });
3295
3335
 
3296
3336
  // src/components/TeamUsage.tsx
3297
- import React9, { useState as useState6 } from "react";
3337
+ import React10, { useState as useState6 } from "react";
3298
3338
  import Paper7 from "@mui/material/Paper";
3299
3339
  import Box9 from "@mui/material/Box";
3300
3340
  import Typography9 from "@mui/material/Typography";
@@ -3311,7 +3351,7 @@ import IconButton5 from "@mui/material/IconButton";
3311
3351
  import Button5 from "@mui/material/Button";
3312
3352
  import CircularProgress5 from "@mui/material/CircularProgress";
3313
3353
  import { alpha as alpha6 } from "@mui/material/styles";
3314
- import { ExpandMore as ExpandMore3, Group, Add as Add3 } from "@mui/icons-material";
3354
+ import { ExpandMore as ExpandMore3, Group, Add as Add2 } from "@mui/icons-material";
3315
3355
  import {
3316
3356
  AreaChart as AreaChart2,
3317
3357
  Area as Area2,
@@ -3354,10 +3394,10 @@ var init_TeamUsage = __esm({
3354
3394
  const renderDailySpendSection = () => {
3355
3395
  if (hidden) return null;
3356
3396
  if (usageLoading) {
3357
- return /* @__PURE__ */ React9.createElement(Box9, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ React9.createElement(CircularProgress5, { size: 22 }));
3397
+ return /* @__PURE__ */ React10.createElement(Box9, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ React10.createElement(CircularProgress5, { size: 22 }));
3358
3398
  }
3359
3399
  if (dailyData.length === 0) return null;
3360
- return /* @__PURE__ */ React9.createElement(Box9, { mb: 2.5 }, /* @__PURE__ */ React9.createElement(
3400
+ return /* @__PURE__ */ React10.createElement(Box9, { mb: 2.5 }, /* @__PURE__ */ React10.createElement(
3361
3401
  Typography9,
3362
3402
  {
3363
3403
  variant: "caption",
@@ -3365,13 +3405,13 @@ var init_TeamUsage = __esm({
3365
3405
  sx: { display: "block", fontSize: 11, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase", mb: 1 }
3366
3406
  },
3367
3407
  "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(
3408
+ ), /* @__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
3409
  Tooltip2,
3370
3410
  {
3371
3411
  cursor: chart.cursor,
3372
- content: /* @__PURE__ */ React9.createElement(ChartTooltip, { valueFormatter: (v) => `$${v.toFixed(4)}` })
3412
+ content: /* @__PURE__ */ React10.createElement(ChartTooltip, { valueFormatter: (v) => `$${v.toFixed(4)}` })
3373
3413
  }
3374
- ), /* @__PURE__ */ React9.createElement(
3414
+ ), /* @__PURE__ */ React10.createElement(
3375
3415
  Area2,
3376
3416
  {
3377
3417
  type: "monotone",
@@ -3384,7 +3424,7 @@ var init_TeamUsage = __esm({
3384
3424
  }
3385
3425
  )))));
3386
3426
  };
3387
- const sectionLabel = (label) => /* @__PURE__ */ React9.createElement(
3427
+ const sectionLabel = (label) => /* @__PURE__ */ React10.createElement(
3388
3428
  Typography9,
3389
3429
  {
3390
3430
  variant: "caption",
@@ -3393,7 +3433,7 @@ var init_TeamUsage = __esm({
3393
3433
  },
3394
3434
  label
3395
3435
  );
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(
3436
+ 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
3437
  Box9,
3398
3438
  {
3399
3439
  sx: (theme) => ({
@@ -3408,8 +3448,8 @@ var init_TeamUsage = __esm({
3408
3448
  color: theme.palette.primary.main
3409
3449
  })
3410
3450
  },
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(
3451
+ /* @__PURE__ */ React10.createElement(Group, { fontSize: "small" })
3452
+ ), /* @__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
3453
  Typography9,
3414
3454
  {
3415
3455
  variant: "caption",
@@ -3417,7 +3457,7 @@ var init_TeamUsage = __esm({
3417
3457
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
3418
3458
  },
3419
3459
  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(
3460
+ )), 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
3461
  Button5,
3422
3462
  {
3423
3463
  size: "small",
@@ -3426,7 +3466,7 @@ var init_TeamUsage = __esm({
3426
3466
  sx: { textTransform: "none" }
3427
3467
  },
3428
3468
  "Edit"
3429
- ), /* @__PURE__ */ React9.createElement(
3469
+ ), /* @__PURE__ */ React10.createElement(
3430
3470
  IconButton5,
3431
3471
  {
3432
3472
  size: "small",
@@ -3439,8 +3479,8 @@ var init_TeamUsage = __esm({
3439
3479
  transition: theme.transitions.create("transform")
3440
3480
  })
3441
3481
  },
3442
- /* @__PURE__ */ React9.createElement(ExpandMore3, null)
3443
- )), /* @__PURE__ */ React9.createElement(
3482
+ /* @__PURE__ */ React10.createElement(ExpandMore3, null)
3483
+ )), /* @__PURE__ */ React10.createElement(
3444
3484
  Box9,
3445
3485
  {
3446
3486
  sx: {
@@ -3451,20 +3491,20 @@ var init_TeamUsage = __esm({
3451
3491
  maxWidth: 640
3452
3492
  }
3453
3493
  },
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(
3494
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Members", value: team.members_with_roles?.length ?? "\u2014" }),
3495
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Models", value: team.models?.length ? team.models.length : "All" }),
3496
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Budget", value: budgetStatValue(hidden, budget) }),
3497
+ /* @__PURE__ */ React10.createElement(Stat, { label: "Spend", value: hidden ? "\u2014" : fmtUsd2(spend) }),
3498
+ /* @__PURE__ */ React10.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
3499
+ /* @__PURE__ */ React10.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
3500
+ ), 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
3501
  TableContainer4,
3462
3502
  {
3463
3503
  component: Paper7,
3464
3504
  variant: "outlined",
3465
3505
  sx: { borderRadius: 1.5 }
3466
3506
  },
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(
3507
+ /* @__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
3508
  Typography9,
3469
3509
  {
3470
3510
  variant: "caption",
@@ -3472,14 +3512,14 @@ var init_TeamUsage = __esm({
3472
3512
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
3473
3513
  },
3474
3514
  m.user_id
3475
- )) : /* @__PURE__ */ React9.createElement(
3515
+ )) : /* @__PURE__ */ React10.createElement(
3476
3516
  Typography9,
3477
3517
  {
3478
3518
  variant: "body2",
3479
3519
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
3480
3520
  },
3481
3521
  m.user_id
3482
- )), /* @__PURE__ */ React9.createElement(TableCell4, { align: "right" }, /* @__PURE__ */ React9.createElement(
3522
+ )), /* @__PURE__ */ React10.createElement(TableCell4, { align: "right" }, /* @__PURE__ */ React10.createElement(
3483
3523
  StatusPill,
3484
3524
  {
3485
3525
  label: m.role,
@@ -3487,7 +3527,7 @@ var init_TeamUsage = __esm({
3487
3527
  dot: false
3488
3528
  }
3489
3529
  ))))))
3490
- ) : /* @__PURE__ */ React9.createElement(Typography9, { variant: "body2", color: "text.secondary" }, "No members assigned."))));
3530
+ ) : /* @__PURE__ */ React10.createElement(Typography9, { variant: "body2", color: "text.secondary" }, "No members assigned."))));
3491
3531
  };
3492
3532
  TeamUsage = ({
3493
3533
  teams,
@@ -3499,22 +3539,22 @@ var init_TeamUsage = __esm({
3499
3539
  canCreate,
3500
3540
  onCreateTeam
3501
3541
  }) => {
3502
- const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ React9.createElement(
3542
+ const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ React10.createElement(
3503
3543
  Button5,
3504
3544
  {
3505
3545
  variant: "contained",
3506
3546
  color: "primary",
3507
3547
  disableElevation: true,
3508
- startIcon: /* @__PURE__ */ React9.createElement(Add3, null),
3548
+ startIcon: /* @__PURE__ */ React10.createElement(Add2, null),
3509
3549
  onClick: onCreateTeam
3510
3550
  },
3511
3551
  "Create Team"
3512
3552
  ) : void 0;
3513
3553
  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 }));
3554
+ 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
3555
  }
3516
3556
  if (!teams.length) {
3517
- return /* @__PURE__ */ React9.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ React9.createElement(
3557
+ return /* @__PURE__ */ React10.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ React10.createElement(
3518
3558
  EmptyState,
3519
3559
  {
3520
3560
  message: "You're not a member of any LiteLLM team yet.",
@@ -3522,14 +3562,14 @@ var init_TeamUsage = __esm({
3522
3562
  }
3523
3563
  ));
3524
3564
  }
3525
- return /* @__PURE__ */ React9.createElement(
3565
+ return /* @__PURE__ */ React10.createElement(
3526
3566
  SectionCard,
3527
3567
  {
3528
3568
  title: "Teams",
3529
3569
  subtitle: `${teams.length} team${teams.length === 1 ? "" : "s"}`,
3530
3570
  actions: createAction
3531
3571
  },
3532
- /* @__PURE__ */ React9.createElement(Box9, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ React9.createElement(
3572
+ /* @__PURE__ */ React10.createElement(Box9, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ React10.createElement(
3533
3573
  TeamCard,
3534
3574
  {
3535
3575
  key: team.team_id,
@@ -3546,7 +3586,7 @@ var init_TeamUsage = __esm({
3546
3586
  });
3547
3587
 
3548
3588
  // src/components/ModelsTable.tsx
3549
- import React10, { useState as useState7, useMemo as useMemo7, useCallback } from "react";
3589
+ import React11, { useState as useState7, useMemo as useMemo7, useCallback } from "react";
3550
3590
  import Box10 from "@mui/material/Box";
3551
3591
  import Table5 from "@mui/material/Table";
3552
3592
  import TableBody5 from "@mui/material/TableBody";
@@ -3678,13 +3718,13 @@ var init_ModelsTable = __esm({
3678
3718
  return theme.palette.info.main;
3679
3719
  }
3680
3720
  };
3681
- return /* @__PURE__ */ React10.createElement(
3721
+ return /* @__PURE__ */ React11.createElement(
3682
3722
  SectionCard,
3683
3723
  {
3684
3724
  title: "Available Models",
3685
3725
  subtitle: selectedTeam ? `${filteredModels.length}${filterText.trim() ? ` of ${teamModels.length}` : ""} model${filteredModels.length === 1 ? "" : "s"}` : "Select a team to view its models"
3686
3726
  },
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(
3727
+ /* @__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
3728
  Select,
3689
3729
  {
3690
3730
  labelId: "team-select-label",
@@ -3692,8 +3732,8 @@ var init_ModelsTable = __esm({
3692
3732
  label: "Team",
3693
3733
  onChange: (e) => setSelectedTeamId(e.target.value)
3694
3734
  },
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(
3735
+ teams.map((t) => /* @__PURE__ */ React11.createElement(MenuItem4, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
3736
+ )), /* @__PURE__ */ React11.createElement(
3697
3737
  TextField5,
3698
3738
  {
3699
3739
  label: "Filter Models",
@@ -3703,33 +3743,33 @@ var init_ModelsTable = __esm({
3703
3743
  disabled: !selectedTeamId,
3704
3744
  sx: { minWidth: 240, mb: 2 },
3705
3745
  InputProps: {
3706
- startAdornment: /* @__PURE__ */ React10.createElement(InputAdornment2, { position: "start" }, /* @__PURE__ */ React10.createElement(Search2, { fontSize: "small" }))
3746
+ startAdornment: /* @__PURE__ */ React11.createElement(InputAdornment2, { position: "start" }, /* @__PURE__ */ React11.createElement(Search2, { fontSize: "small" }))
3707
3747
  }
3708
3748
  }
3709
3749
  )),
3710
- loading && /* @__PURE__ */ React10.createElement(EmptyState, { message: "Loading models\u2026" }),
3711
- !loading && !selectedTeamId && /* @__PURE__ */ React10.createElement(
3750
+ loading && /* @__PURE__ */ React11.createElement(EmptyState, { message: "Loading models\u2026" }),
3751
+ !loading && !selectedTeamId && /* @__PURE__ */ React11.createElement(
3712
3752
  EmptyState,
3713
3753
  {
3714
3754
  message: "Select a team to see available models",
3715
3755
  hint: "Each team may have a different set of models assigned"
3716
3756
  }
3717
3757
  ),
3718
- !loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ React10.createElement(
3758
+ !loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ React11.createElement(
3719
3759
  EmptyState,
3720
3760
  {
3721
3761
  message: "No models available for this team",
3722
3762
  hint: allModels.length === 0 ? "No models are configured in the system" : "None of the team's assigned models were found in the catalog"
3723
3763
  }
3724
3764
  ),
3725
- !loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ React10.createElement(
3765
+ !loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ React11.createElement(
3726
3766
  EmptyState,
3727
3767
  {
3728
3768
  message: "No models match your search",
3729
3769
  hint: "Try a different search term"
3730
3770
  }
3731
3771
  ),
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(
3772
+ !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
3773
  "span",
3734
3774
  {
3735
3775
  role: "button",
@@ -3739,8 +3779,8 @@ var init_ModelsTable = __esm({
3739
3779
  onKeyDown: (e) => e.key === "Enter" && handleCopyModelId(m.model_name),
3740
3780
  style: { cursor: "pointer", display: "inline-flex" }
3741
3781
  },
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(
3782
+ /* @__PURE__ */ React11.createElement(TagChip, { label: m.model_name, title: "Copy model ID" })
3783
+ )), /* @__PURE__ */ React11.createElement(Tooltip3, { title: "Copy model ID" }, /* @__PURE__ */ React11.createElement(
3744
3784
  Box10,
3745
3785
  {
3746
3786
  component: "span",
@@ -3751,8 +3791,8 @@ var init_ModelsTable = __esm({
3751
3791
  sx: quietIconButtonSx("accent"),
3752
3792
  style: { cursor: "pointer", display: "inline-flex" }
3753
3793
  },
3754
- /* @__PURE__ */ React10.createElement(ContentCopyIcon, { sx: { fontSize: 14 } })
3755
- )))), /* @__PURE__ */ React10.createElement(TableCell5, null, /* @__PURE__ */ React10.createElement(
3794
+ /* @__PURE__ */ React11.createElement(ContentCopyIcon, { sx: { fontSize: 14 } })
3795
+ )))), /* @__PURE__ */ React11.createElement(TableCell5, null, /* @__PURE__ */ React11.createElement(
3756
3796
  Box10,
3757
3797
  {
3758
3798
  component: "span",
@@ -3769,8 +3809,8 @@ var init_ModelsTable = __esm({
3769
3809
  }
3770
3810
  },
3771
3811
  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(
3812
+ )), /* @__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" })))))))),
3813
+ /* @__PURE__ */ React11.createElement(
3774
3814
  Snackbar,
3775
3815
  {
3776
3816
  open: copiedSnackbar,
@@ -3778,7 +3818,7 @@ var init_ModelsTable = __esm({
3778
3818
  onClose: () => setCopiedSnackbar(false),
3779
3819
  anchorOrigin: { vertical: "bottom", horizontal: "center" }
3780
3820
  },
3781
- /* @__PURE__ */ React10.createElement(Alert4, { severity: "success", variant: "filled", sx: { fontSize: 13 } }, "Model ID copied to clipboard")
3821
+ /* @__PURE__ */ React11.createElement(Alert4, { severity: "success", variant: "filled", sx: { fontSize: 13 } }, "Model ID copied to clipboard")
3782
3822
  )
3783
3823
  );
3784
3824
  };
@@ -3786,7 +3826,7 @@ var init_ModelsTable = __esm({
3786
3826
  });
3787
3827
 
3788
3828
  // src/components/AuditLog.tsx
3789
- import React11, { useState as useState8, useMemo as useMemo8 } from "react";
3829
+ import React12, { useState as useState8, useMemo as useMemo8 } from "react";
3790
3830
  import Box11 from "@mui/material/Box";
3791
3831
  import Typography11 from "@mui/material/Typography";
3792
3832
  import Table6 from "@mui/material/Table";
@@ -3825,10 +3865,10 @@ function formatDateTime(iso) {
3825
3865
  }
3826
3866
  function renderAuditLogBody(loading, entries) {
3827
3867
  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 })));
3868
+ return /* @__PURE__ */ React12.createElement(TableRow6, null, /* @__PURE__ */ React12.createElement(TableCell6, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ React12.createElement(Skeleton5, { variant: "rounded", height: 160 })));
3829
3869
  }
3830
3870
  if (entries.length === 0) {
3831
- return /* @__PURE__ */ React11.createElement(TableRow6, null, /* @__PURE__ */ React11.createElement(TableCell6, { colSpan: 6 }, /* @__PURE__ */ React11.createElement(
3871
+ return /* @__PURE__ */ React12.createElement(TableRow6, null, /* @__PURE__ */ React12.createElement(TableCell6, { colSpan: 6 }, /* @__PURE__ */ React12.createElement(
3832
3872
  EmptyState,
3833
3873
  {
3834
3874
  message: "No audit events found",
@@ -3836,7 +3876,7 @@ function renderAuditLogBody(loading, entries) {
3836
3876
  }
3837
3877
  )));
3838
3878
  }
3839
- return entries.map((entry) => /* @__PURE__ */ React11.createElement(DetailRow, { key: entry.id, entry }));
3879
+ return entries.map((entry) => /* @__PURE__ */ React12.createElement(DetailRow, { key: entry.id, entry }));
3840
3880
  }
3841
3881
  var ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3842
3882
  var init_AuditLog = __esm({
@@ -3860,7 +3900,7 @@ var init_AuditLog = __esm({
3860
3900
  DetailRow = ({ entry }) => {
3861
3901
  const [open, setOpen] = useState8(false);
3862
3902
  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(
3903
+ 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
3904
  IconButton6,
3865
3905
  {
3866
3906
  size: "small",
@@ -3873,8 +3913,8 @@ var init_AuditLog = __esm({
3873
3913
  transition: theme.transitions.create("transform")
3874
3914
  })
3875
3915
  },
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(
3916
+ /* @__PURE__ */ React12.createElement(KeyboardArrowDown, { fontSize: "small" })
3917
+ )), /* @__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
3918
  Typography11,
3879
3919
  {
3880
3920
  variant: "body2",
@@ -3884,7 +3924,7 @@ var init_AuditLog = __esm({
3884
3924
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 12 }
3885
3925
  },
3886
3926
  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(
3927
+ )), /* @__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
3928
  Box11,
3889
3929
  {
3890
3930
  display: "flex",
@@ -3897,7 +3937,7 @@ var init_AuditLog = __esm({
3897
3937
  bgcolor: alpha8(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.05 : 0.03)
3898
3938
  })
3899
3939
  },
3900
- entry.before_value && /* @__PURE__ */ React11.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React11.createElement(
3940
+ entry.before_value && /* @__PURE__ */ React12.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React12.createElement(
3901
3941
  Typography11,
3902
3942
  {
3903
3943
  variant: "caption",
@@ -3907,8 +3947,8 @@ var init_AuditLog = __esm({
3907
3947
  sx: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase" }
3908
3948
  },
3909
3949
  "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(
3950
+ ), /* @__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))),
3951
+ entry.updated_values && /* @__PURE__ */ React12.createElement(Box11, { flex: 1, minWidth: 200 }, /* @__PURE__ */ React12.createElement(
3912
3952
  Typography11,
3913
3953
  {
3914
3954
  variant: "caption",
@@ -3918,7 +3958,7 @@ var init_AuditLog = __esm({
3918
3958
  sx: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase" }
3919
3959
  },
3920
3960
  "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)))
3961
+ ), /* @__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
3962
  )))));
3923
3963
  };
3924
3964
  AuditLog = ({ api }) => {
@@ -3935,13 +3975,13 @@ var init_AuditLog = __esm({
3935
3975
  );
3936
3976
  const entries = value?.audit_logs ?? [];
3937
3977
  const total = value?.total ?? 0;
3938
- return /* @__PURE__ */ React11.createElement(
3978
+ return /* @__PURE__ */ React12.createElement(
3939
3979
  SectionCard,
3940
3980
  {
3941
3981
  title: "Audit Log",
3942
3982
  subtitle: loading ? "Loading\u2026" : `${total.toLocaleString()} event${total === 1 ? "" : "s"}`,
3943
3983
  flush: true,
3944
- actions: /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
3984
+ actions: /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
3945
3985
  TextField6,
3946
3986
  {
3947
3987
  size: "small",
@@ -3954,12 +3994,12 @@ var init_AuditLog = __esm({
3954
3994
  },
3955
3995
  sx: { minWidth: 150 }
3956
3996
  },
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(
3997
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "" }, "All actions"),
3998
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "created" }, "Created"),
3999
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "updated" }, "Updated"),
4000
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "deleted" }, "Deleted"),
4001
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "blocked" }, "Blocked")
4002
+ ), /* @__PURE__ */ React12.createElement(
3963
4003
  TextField6,
3964
4004
  {
3965
4005
  size: "small",
@@ -3972,13 +4012,13 @@ var init_AuditLog = __esm({
3972
4012
  },
3973
4013
  sx: { minWidth: 150 }
3974
4014
  },
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(
4015
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "" }, "All tables"),
4016
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_VerificationToken" }, "Key"),
4017
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_TeamTable" }, "Team"),
4018
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_TeamMembership" }, "Team member"),
4019
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
4020
+ /* @__PURE__ */ React12.createElement(MenuItem5, { value: "LiteLLM_UserTable" }, "User")
4021
+ ), /* @__PURE__ */ React12.createElement(
3982
4022
  TextField6,
3983
4023
  {
3984
4024
  size: "small",
@@ -3992,9 +4032,9 @@ var init_AuditLog = __esm({
3992
4032
  }
3993
4033
  ))
3994
4034
  },
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(
4035
+ error && /* @__PURE__ */ React12.createElement(Box11, { px: 2.5, pb: 2 }, /* @__PURE__ */ React12.createElement(Alert5, { severity: "error" }, error.message)),
4036
+ /* @__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)))),
4037
+ /* @__PURE__ */ React12.createElement(
3998
4038
  TablePagination,
3999
4039
  {
4000
4040
  component: "div",
@@ -4049,7 +4089,7 @@ var LiteLLMPage_exports = {};
4049
4089
  __export(LiteLLMPage_exports, {
4050
4090
  LiteLLMPage: () => LiteLLMPage
4051
4091
  });
4052
- import React12, { useState as useState9, useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo9 } from "react";
4092
+ import React13, { useState as useState9, useCallback as useCallback2, useEffect as useEffect4, useMemo as useMemo9 } from "react";
4053
4093
  import Box12 from "@mui/material/Box";
4054
4094
  import Snackbar2 from "@mui/material/Snackbar";
4055
4095
  import Alert6 from "@mui/material/Alert";
@@ -4335,14 +4375,14 @@ var init_LiteLLMPage = __esm({
4335
4375
  );
4336
4376
  const isInitialLoading = userLoading && !userInfo;
4337
4377
  if (isInitialLoading) {
4338
- return /* @__PURE__ */ React12.createElement(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ React12.createElement(CircularProgress6, null));
4378
+ return /* @__PURE__ */ React13.createElement(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ React13.createElement(CircularProgress6, null));
4339
4379
  }
4340
4380
  if (userError || !userInfo) {
4341
4381
  const isProvisioningEnabled = userError?.body?.provisioning === true;
4342
4382
  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.")));
4383
+ 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
4384
  }
4345
- const pageTabs = /* @__PURE__ */ React12.createElement(
4385
+ const pageTabs = /* @__PURE__ */ React13.createElement(
4346
4386
  Tabs2,
4347
4387
  {
4348
4388
  value: activeTab,
@@ -4355,13 +4395,13 @@ var init_LiteLLMPage = __esm({
4355
4395
  '& [class*="MuiTab-root"]': { minHeight: 44, textTransform: "none", fontSize: 14 }
4356
4396
  }
4357
4397
  },
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" })
4398
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Overview", value: "overview" }),
4399
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Keys", value: "keys" }),
4400
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Teams", value: "teams" }),
4401
+ /* @__PURE__ */ React13.createElement(Tab2, { label: "Models", value: "models" }),
4402
+ userInfo.can_view_audit && /* @__PURE__ */ React13.createElement(Tab2, { label: "Audit Log", value: "audit" })
4363
4403
  );
4364
- return /* @__PURE__ */ React12.createElement(Box12, { sx: { p: 3, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React12.createElement(
4404
+ return /* @__PURE__ */ React13.createElement(Box12, { sx: { p: 3, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ React13.createElement(
4365
4405
  DashboardHeader,
4366
4406
  {
4367
4407
  userInfo,
@@ -4371,7 +4411,7 @@ var init_LiteLLMPage = __esm({
4371
4411
  onGenerateKeyClick: () => setGenerateDialogOpen(true),
4372
4412
  tabs: pageTabs
4373
4413
  }
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(
4414
+ ), 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
4415
  UsageStats,
4376
4416
  {
4377
4417
  usage: usage ?? null,
@@ -4382,7 +4422,7 @@ var init_LiteLLMPage = __esm({
4382
4422
  loading: usageLoading,
4383
4423
  userInfo
4384
4424
  }
4385
- )), /* @__PURE__ */ React12.createElement(Grid2, { item: true, xs: 12, lg: 4 }, /* @__PURE__ */ React12.createElement(LiteLLMBudgetWidget, { compact: true, collapsible: true }))), activeTab === "keys" && /* @__PURE__ */ React12.createElement(
4425
+ )), /* @__PURE__ */ React13.createElement(Grid2, { item: true, xs: 12, lg: 4 }, /* @__PURE__ */ React13.createElement(LiteLLMBudgetWidget, { compact: true, collapsible: true }))), activeTab === "keys" && /* @__PURE__ */ React13.createElement(
4386
4426
  KeysTable,
4387
4427
  {
4388
4428
  keys: keys ?? [],
@@ -4399,7 +4439,7 @@ var init_LiteLLMPage = __esm({
4399
4439
  for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);
4400
4440
  for (const t of teams ?? []) teamsById.set(t.team_id, t);
4401
4441
  const visibleTeams = Array.from(teamsById.values());
4402
- return /* @__PURE__ */ React12.createElement(
4442
+ return /* @__PURE__ */ React13.createElement(
4403
4443
  TeamUsage,
4404
4444
  {
4405
4445
  teams: visibleTeams,
@@ -4415,14 +4455,14 @@ var init_LiteLLMPage = __esm({
4415
4455
  onCreateTeam: () => setManageTeam({ mode: "create" })
4416
4456
  }
4417
4457
  );
4418
- })(), activeTab === "models" && /* @__PURE__ */ React12.createElement(
4458
+ })(), activeTab === "models" && /* @__PURE__ */ React13.createElement(
4419
4459
  ModelsTable,
4420
4460
  {
4421
4461
  allModels: allModels ?? [],
4422
4462
  teams: teams ?? [],
4423
4463
  loading: modelsLoading
4424
4464
  }
4425
- ), activeTab === "audit" && userInfo.can_view_audit && /* @__PURE__ */ React12.createElement(AuditLog, { api }), /* @__PURE__ */ React12.createElement(
4465
+ ), activeTab === "audit" && userInfo.can_view_audit && /* @__PURE__ */ React13.createElement(AuditLog, { api }), /* @__PURE__ */ React13.createElement(
4426
4466
  KeyFormDialog,
4427
4467
  {
4428
4468
  open: keyFormOpen,
@@ -4442,7 +4482,7 @@ var init_LiteLLMPage = __esm({
4442
4482
  onResetKeySpend: handleResetKeySpend,
4443
4483
  onGetConfig: () => api.getConfig()
4444
4484
  }
4445
- ), /* @__PURE__ */ React12.createElement(
4485
+ ), /* @__PURE__ */ React13.createElement(
4446
4486
  ManageTeamDialog,
4447
4487
  {
4448
4488
  open: !!manageTeam,
@@ -4504,7 +4544,7 @@ var init_LiteLLMPage = __esm({
4504
4544
  refreshTeams();
4505
4545
  }
4506
4546
  }
4507
- ), /* @__PURE__ */ React12.createElement(
4547
+ ), /* @__PURE__ */ React13.createElement(
4508
4548
  Snackbar2,
4509
4549
  {
4510
4550
  open: !!snackbar,
@@ -4512,7 +4552,7 @@ var init_LiteLLMPage = __esm({
4512
4552
  onClose: () => setSnackbar(null),
4513
4553
  anchorOrigin: { vertical: "bottom", horizontal: "right" }
4514
4554
  },
4515
- snackbar ? /* @__PURE__ */ React12.createElement(Alert6, { severity: snackbar.severity, onClose: () => setSnackbar(null) }, snackbar.message) : void 0
4555
+ snackbar ? /* @__PURE__ */ React13.createElement(Alert6, { severity: snackbar.severity, onClose: () => setSnackbar(null) }, snackbar.message) : void 0
4516
4556
  ));
4517
4557
  };
4518
4558
  }
@@ -4520,7 +4560,7 @@ var init_LiteLLMPage = __esm({
4520
4560
 
4521
4561
  // src/plugin.tsx
4522
4562
  init_api();
4523
- import React13 from "react";
4563
+ import React14 from "react";
4524
4564
  import { TrendingUp as TrendingUpIcon } from "@mui/icons-material";
4525
4565
  import {
4526
4566
  createFrontendPlugin,
@@ -4539,10 +4579,10 @@ var liteLlmPage = PageBlueprint.make({
4539
4579
  params: {
4540
4580
  path: "/litellm",
4541
4581
  title: "LiteLLM",
4542
- icon: /* @__PURE__ */ React13.createElement(TrendingUpIcon, null),
4582
+ icon: /* @__PURE__ */ React14.createElement(TrendingUpIcon, null),
4543
4583
  loader: async () => {
4544
4584
  const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
4545
- return /* @__PURE__ */ React13.createElement(LiteLLMPage2, null);
4585
+ return /* @__PURE__ */ React14.createElement(LiteLLMPage2, null);
4546
4586
  }
4547
4587
  }
4548
4588
  });
@@ -4561,7 +4601,7 @@ init_TeamUsage();
4561
4601
  // src/components/LiteLLMHomeWidget.tsx
4562
4602
  init_api();
4563
4603
  init_format();
4564
- import React14, { useState as useState10, useEffect as useEffect5 } from "react";
4604
+ import React15, { useState as useState10, useEffect as useEffect5 } from "react";
4565
4605
  import Paper9 from "@mui/material/Paper";
4566
4606
  import Box13 from "@mui/material/Box";
4567
4607
  import Typography13 from "@mui/material/Typography";
@@ -4585,7 +4625,7 @@ function presetToDateRange(preset) {
4585
4625
  }
4586
4626
  return { start, end };
4587
4627
  }
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));
4628
+ 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
4629
  var LiteLLMHomeWidget = ({
4590
4630
  defaultPeriod = "7d",
4591
4631
  title = "LiteLLM Usage"
@@ -4634,17 +4674,17 @@ var LiteLLMHomeWidget = ({
4634
4674
  spend: d.spend
4635
4675
  }));
4636
4676
  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(
4677
+ 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
4678
  Select2,
4639
4679
  {
4640
4680
  value: period,
4641
4681
  onChange: (e) => setPeriod(e.target.value),
4642
4682
  displayEmpty: true
4643
4683
  },
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(
4684
+ /* @__PURE__ */ React15.createElement(MenuItem6, { value: "today" }, "Today"),
4685
+ /* @__PURE__ */ React15.createElement(MenuItem6, { value: "7d" }, "7d"),
4686
+ /* @__PURE__ */ React15.createElement(MenuItem6, { value: "30d" }, "30d")
4687
+ ))), 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
4688
  Area3,
4649
4689
  {
4650
4690
  type: "monotone",
@@ -4665,9 +4705,10 @@ init_LiteLLMBudgetWidget();
4665
4705
  init_api();
4666
4706
  init_format();
4667
4707
  init_ui();
4708
+ init_GenerateKeyButton();
4668
4709
  init_BudgetLimitList();
4669
4710
  init_budget();
4670
- import React15, { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo10, useState as useState11 } from "react";
4711
+ import React16, { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo10, useState as useState11 } from "react";
4671
4712
  import Paper10 from "@mui/material/Paper";
4672
4713
  import Box14 from "@mui/material/Box";
4673
4714
  import Button6 from "@mui/material/Button";
@@ -4676,8 +4717,9 @@ import CircularProgress8 from "@mui/material/CircularProgress";
4676
4717
  import Alert8 from "@mui/material/Alert";
4677
4718
  import Collapse4 from "@mui/material/Collapse";
4678
4719
  import { ExpandMore as ExpandMore4 } from "@mui/icons-material";
4720
+ import { AreaChart as AreaChart4, Area as Area4, ResponsiveContainer as ResponsiveContainer4, Tooltip as Tooltip4 } from "recharts";
4679
4721
  import { useApi as useApi5 } from "@backstage/core-plugin-api";
4680
- import { Link as Link2 } from "@backstage/core-components";
4722
+ import { Link as Link3 } from "@backstage/core-components";
4681
4723
  var MODULE_PATH = "/litellm";
4682
4724
  var LEVEL = {
4683
4725
  key: { name: "Key", none: "No key budget" },
@@ -4686,7 +4728,7 @@ var LEVEL = {
4686
4728
  };
4687
4729
  var DEFAULT_CTAS = ["new-key", "module", "all-limits"];
4688
4730
  var CTA_LABELS = {
4689
- "new-key": "New key",
4731
+ "new-key": "Generate New Key",
4690
4732
  module: "Open module",
4691
4733
  "all-limits": "All limits"
4692
4734
  };
@@ -4712,7 +4754,7 @@ var LevelGauge = ({
4712
4754
  const limit = gauge.limit;
4713
4755
  const tone = limit ? budgetTone2(limit.pct) : "neutral";
4714
4756
  const extra = gauge.kind === "key" ? Math.max(0, gauge.count - 1) : 0;
4715
- return /* @__PURE__ */ React15.createElement(
4757
+ return /* @__PURE__ */ React16.createElement(
4716
4758
  Box14,
4717
4759
  {
4718
4760
  sx: {
@@ -4723,7 +4765,7 @@ var LevelGauge = ({
4723
4765
  flex: 1
4724
4766
  }
4725
4767
  },
4726
- /* @__PURE__ */ React15.createElement(
4768
+ /* @__PURE__ */ React16.createElement(
4727
4769
  Gauge,
4728
4770
  {
4729
4771
  value: limit?.pct ?? 0,
@@ -4732,7 +4774,7 @@ var LevelGauge = ({
4732
4774
  label: limit ? `${Math.round(limit.pct)}%` : "\u2014"
4733
4775
  }
4734
4776
  ),
4735
- /* @__PURE__ */ React15.createElement(
4777
+ /* @__PURE__ */ React16.createElement(
4736
4778
  Typography14,
4737
4779
  {
4738
4780
  sx: (theme) => ({
@@ -4746,7 +4788,7 @@ var LevelGauge = ({
4746
4788
  },
4747
4789
  name
4748
4790
  ),
4749
- limit ? /* @__PURE__ */ React15.createElement(React15.Fragment, null, /* @__PURE__ */ React15.createElement(
4791
+ limit ? /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
4750
4792
  Typography14,
4751
4793
  {
4752
4794
  variant: "caption",
@@ -4762,7 +4804,7 @@ var LevelGauge = ({
4762
4804
  }
4763
4805
  },
4764
4806
  limit.label
4765
- ), /* @__PURE__ */ React15.createElement(
4807
+ ), /* @__PURE__ */ React16.createElement(
4766
4808
  Typography14,
4767
4809
  {
4768
4810
  variant: "caption",
@@ -4774,10 +4816,10 @@ var LevelGauge = ({
4774
4816
  }
4775
4817
  },
4776
4818
  spendCaption(limit)
4777
- ), extra > 0 ? /* @__PURE__ */ React15.createElement(
4819
+ ), extra > 0 ? /* @__PURE__ */ React16.createElement(
4778
4820
  Typography14,
4779
4821
  {
4780
- component: Link2,
4822
+ component: Link3,
4781
4823
  to: keysHref,
4782
4824
  variant: "caption",
4783
4825
  sx: {
@@ -4790,7 +4832,7 @@ var LevelGauge = ({
4790
4832
  "+",
4791
4833
  extra,
4792
4834
  " more"
4793
- ) : /* @__PURE__ */ React15.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, resetLabel(limit))) : /* @__PURE__ */ React15.createElement(
4835
+ ) : /* @__PURE__ */ React16.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, resetLabel(limit))) : /* @__PURE__ */ React16.createElement(
4794
4836
  Typography14,
4795
4837
  {
4796
4838
  variant: "caption",
@@ -4801,6 +4843,125 @@ var LevelGauge = ({
4801
4843
  )
4802
4844
  );
4803
4845
  };
4846
+ function monthToDateRange(now = /* @__PURE__ */ new Date()) {
4847
+ const toDay = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(
4848
+ d.getDate()
4849
+ ).padStart(2, "0")}`;
4850
+ const start = new Date(now.getFullYear(), now.getMonth(), 1);
4851
+ return { startDate: toDay(start), endDate: toDay(now) };
4852
+ }
4853
+ var UsageMiniChart = ({ data, totalTokens, loading, height }) => {
4854
+ const renderPlot = () => {
4855
+ if (loading) {
4856
+ return /* @__PURE__ */ React16.createElement(Box14, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%" }, /* @__PURE__ */ React16.createElement(CircularProgress8, { size: 20 }));
4857
+ }
4858
+ if (data.length === 0) {
4859
+ return /* @__PURE__ */ React16.createElement(
4860
+ Box14,
4861
+ {
4862
+ display: "flex",
4863
+ justifyContent: "center",
4864
+ alignItems: "center",
4865
+ height: "100%",
4866
+ sx: (theme) => ({ color: theme.palette.text.secondary, fontSize: 18 })
4867
+ },
4868
+ "\u2014"
4869
+ );
4870
+ }
4871
+ 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(
4872
+ Area4,
4873
+ {
4874
+ type: "monotone",
4875
+ dataKey: "input",
4876
+ name: "Input",
4877
+ stackId: "tok",
4878
+ stroke: SERIES.input,
4879
+ strokeWidth: 1.5,
4880
+ fill: SERIES.input,
4881
+ fillOpacity: 0.25,
4882
+ dot: false,
4883
+ isAnimationActive: false
4884
+ }
4885
+ ), /* @__PURE__ */ React16.createElement(
4886
+ Area4,
4887
+ {
4888
+ type: "monotone",
4889
+ dataKey: "output",
4890
+ name: "Output",
4891
+ stackId: "tok",
4892
+ stroke: SERIES.output,
4893
+ strokeWidth: 1.5,
4894
+ fill: SERIES.output,
4895
+ fillOpacity: 0.25,
4896
+ dot: false,
4897
+ isAnimationActive: false
4898
+ }
4899
+ )));
4900
+ };
4901
+ const renderCaption = () => {
4902
+ if (loading) {
4903
+ return /* @__PURE__ */ React16.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { mt: 0.25, fontSize: 11 } }, "\u2026");
4904
+ }
4905
+ if (data.length === 0) {
4906
+ return /* @__PURE__ */ React16.createElement(
4907
+ Typography14,
4908
+ {
4909
+ variant: "caption",
4910
+ color: "text.secondary",
4911
+ sx: { mt: 0.25, fontSize: 10.5, textAlign: "center" }
4912
+ },
4913
+ "No usage this month"
4914
+ );
4915
+ }
4916
+ return /* @__PURE__ */ React16.createElement(React16.Fragment, null, /* @__PURE__ */ React16.createElement(
4917
+ Typography14,
4918
+ {
4919
+ variant: "caption",
4920
+ title: `${fmtInt(totalTokens)} tokens month to date`,
4921
+ sx: {
4922
+ mt: 0.25,
4923
+ fontSize: 11,
4924
+ fontWeight: 600,
4925
+ maxWidth: "100%",
4926
+ overflow: "hidden",
4927
+ textOverflow: "ellipsis",
4928
+ whiteSpace: "nowrap",
4929
+ fontVariantNumeric: "tabular-nums"
4930
+ }
4931
+ },
4932
+ fmtCompact(totalTokens),
4933
+ " tokens"
4934
+ ), /* @__PURE__ */ React16.createElement(Typography14, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, "month to date"));
4935
+ };
4936
+ return /* @__PURE__ */ React16.createElement(
4937
+ Box14,
4938
+ {
4939
+ sx: {
4940
+ display: "flex",
4941
+ flexDirection: "column",
4942
+ alignItems: "center",
4943
+ minWidth: 0,
4944
+ flex: 1
4945
+ }
4946
+ },
4947
+ /* @__PURE__ */ React16.createElement(Box14, { sx: { height, width: "100%" } }, renderPlot()),
4948
+ /* @__PURE__ */ React16.createElement(
4949
+ Typography14,
4950
+ {
4951
+ sx: (theme) => ({
4952
+ mt: 0.75,
4953
+ fontSize: 10.5,
4954
+ fontWeight: 700,
4955
+ letterSpacing: "0.08em",
4956
+ textTransform: "uppercase",
4957
+ color: theme.palette.text.secondary
4958
+ })
4959
+ },
4960
+ "Usage"
4961
+ ),
4962
+ renderCaption()
4963
+ );
4964
+ };
4804
4965
  var LiteLLMBudgetGauges = ({
4805
4966
  title = "Budget",
4806
4967
  size = 72,
@@ -4820,6 +4981,9 @@ var LiteLLMBudgetGauges = ({
4820
4981
  const [user, setUser] = useState11(null);
4821
4982
  const [teams, setTeams] = useState11([]);
4822
4983
  const [keys, setKeys] = useState11([]);
4984
+ const [usageLoading, setUsageLoading] = useState11(true);
4985
+ const [dailyTokens, setDailyTokens] = useState11([]);
4986
+ const [mtdTokens, setMtdTokens] = useState11(0);
4823
4987
  const isControlled = expanded !== void 0;
4824
4988
  const [uncontrolledExpanded, setUncontrolledExpanded] = useState11(defaultExpanded);
4825
4989
  const isExpanded = isControlled ? expanded : uncontrolledExpanded;
@@ -4832,23 +4996,43 @@ var LiteLLMBudgetGauges = ({
4832
4996
  useEffect6(() => {
4833
4997
  let cancelled = false;
4834
4998
  setLoading(true);
4999
+ setUsageLoading(true);
4835
5000
  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);
5001
+ const { startDate, endDate } = monthToDateRange();
5002
+ Promise.allSettled([
5003
+ api.getUserInfo(),
5004
+ api.getTeams(),
5005
+ api.listKeys(),
5006
+ api.getUsage(startDate, endDate)
5007
+ ]).then(([userResult, teamsResult, keysResult, usageResult]) => {
5008
+ if (cancelled) return;
5009
+ if (userResult.status === "fulfilled") {
5010
+ setUser(userResult.value);
5011
+ } else {
5012
+ setUser(null);
5013
+ setError(
5014
+ userResult.reason?.message ?? "Failed to load your LiteLLM profile"
5015
+ );
4850
5016
  }
4851
- );
5017
+ setTeams(teamsResult.status === "fulfilled" ? teamsResult.value : []);
5018
+ setKeys(keysResult.status === "fulfilled" ? keysResult.value : []);
5019
+ setLoading(false);
5020
+ if (usageResult.status === "fulfilled") {
5021
+ const daily = usageResult.value.daily_usage ?? [];
5022
+ setDailyTokens(
5023
+ daily.map((d) => ({
5024
+ date: d.date,
5025
+ input: d.prompt_tokens,
5026
+ output: d.completion_tokens
5027
+ }))
5028
+ );
5029
+ setMtdTokens(usageResult.value.total_tokens ?? 0);
5030
+ } else {
5031
+ setDailyTokens([]);
5032
+ setMtdTokens(0);
5033
+ }
5034
+ setUsageLoading(false);
5035
+ });
4852
5036
  return () => {
4853
5037
  cancelled = true;
4854
5038
  };
@@ -4877,28 +5061,18 @@ var LiteLLMBudgetGauges = ({
4877
5061
  const key = `${cta.kind}-${index}`;
4878
5062
  switch (cta.kind) {
4879
5063
  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
- );
5064
+ 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
5065
  case "module":
4892
- return /* @__PURE__ */ React15.createElement(Button6, { key, size: "small", variant: "outlined", component: Link2, to: moduleHref }, label);
5066
+ return /* @__PURE__ */ React16.createElement(Button6, { key, size: "small", variant: "outlined", component: Link3, to: moduleHref }, label);
4893
5067
  case "all-limits":
4894
- return /* @__PURE__ */ React15.createElement(
5068
+ return /* @__PURE__ */ React16.createElement(
4895
5069
  Button6,
4896
5070
  {
4897
5071
  key,
4898
5072
  size: "small",
4899
5073
  variant: "text",
4900
5074
  onClick: toggleExpanded,
4901
- endIcon: /* @__PURE__ */ React15.createElement(
5075
+ endIcon: /* @__PURE__ */ React16.createElement(
4902
5076
  ExpandMore4,
4903
5077
  {
4904
5078
  sx: {
@@ -4916,14 +5090,22 @@ var LiteLLMBudgetGauges = ({
4916
5090
  }
4917
5091
  };
4918
5092
  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(
5093
+ 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
5094
  StatusPill,
4921
5095
  {
4922
5096
  label: summaryText,
4923
5097
  tone: budgetTone2(headline.closest?.pct ?? 0),
4924
5098
  dot: headline.count > 0
4925
5099
  }
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(
5100
+ )), 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(
5101
+ UsageMiniChart,
5102
+ {
5103
+ data: dailyTokens,
5104
+ totalTokens: mtdTokens,
5105
+ loading: usageLoading,
5106
+ height: size
5107
+ }
5108
+ )), /* @__PURE__ */ React16.createElement(Collapse4, { in: isExpanded, unmountOnExit: true }, /* @__PURE__ */ React16.createElement(
4927
5109
  Box14,
4928
5110
  {
4929
5111
  sx: {
@@ -4934,7 +5116,7 @@ var LiteLLMBudgetGauges = ({
4934
5116
  overflowY: "auto"
4935
5117
  }
4936
5118
  },
4937
- /* @__PURE__ */ React15.createElement(LimitListPanel, null, /* @__PURE__ */ React15.createElement(
5119
+ /* @__PURE__ */ React16.createElement(LimitListPanel, null, /* @__PURE__ */ React16.createElement(
4938
5120
  BudgetLimitList,
4939
5121
  {
4940
5122
  limits: expandedLimits,
@@ -4942,7 +5124,7 @@ var LiteLLMBudgetGauges = ({
4942
5124
  keysHref: keysTabHref
4943
5125
  }
4944
5126
  ))
4945
- ))), hasFooter && /* @__PURE__ */ React15.createElement(
5127
+ ))), hasFooter && /* @__PURE__ */ React16.createElement(
4946
5128
  Box14,
4947
5129
  {
4948
5130
  sx: (theme) => ({
@@ -4962,11 +5144,12 @@ var LiteLLMBudgetGauges = ({
4962
5144
 
4963
5145
  // src/index.ts
4964
5146
  init_KeyFormDialog();
5147
+ init_GenerateKeyButton();
4965
5148
 
4966
5149
  // src/components/GenerateKeyDialog.tsx
4967
5150
  init_KeyFormDialog();
4968
- import React16 from "react";
4969
- var GenerateKeyDialog = (props) => /* @__PURE__ */ React16.createElement(
5151
+ import React17 from "react";
5152
+ var GenerateKeyDialog = (props) => /* @__PURE__ */ React17.createElement(
4970
5153
  KeyFormDialog,
4971
5154
  {
4972
5155
  open: props.open,
@@ -4990,6 +5173,7 @@ init_api();
4990
5173
  init_permissions();
4991
5174
  export {
4992
5175
  DashboardHeader,
5176
+ GenerateKeyButton,
4993
5177
  GenerateKeyDialog,
4994
5178
  KeyFormDialog,
4995
5179
  KeysTable,