@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.cjs.js CHANGED
@@ -858,6 +858,71 @@ var init_ui = __esm({
858
858
  }
859
859
  });
860
860
 
861
+ // src/components/GenerateKeyButton.tsx
862
+ var import_react2, import_Button, import_icons_material, import_core_components, GenerateKeyButton;
863
+ var init_GenerateKeyButton = __esm({
864
+ "src/components/GenerateKeyButton.tsx"() {
865
+ "use strict";
866
+ import_react2 = __toESM(require("react"));
867
+ import_Button = __toESM(require("@mui/material/Button"));
868
+ import_icons_material = require("@mui/icons-material");
869
+ import_core_components = require("@backstage/core-components");
870
+ GenerateKeyButton = ({
871
+ to,
872
+ onClick,
873
+ label = "Generate New Key",
874
+ size,
875
+ fullWidth = false,
876
+ disabled = false
877
+ }) => {
878
+ if (onClick && !disabled) {
879
+ return /* @__PURE__ */ import_react2.default.createElement(
880
+ import_Button.default,
881
+ {
882
+ variant: "contained",
883
+ color: "primary",
884
+ disableElevation: true,
885
+ size,
886
+ fullWidth,
887
+ startIcon: /* @__PURE__ */ import_react2.default.createElement(import_icons_material.Add, null),
888
+ onClick
889
+ },
890
+ label
891
+ );
892
+ }
893
+ if (to && !disabled) {
894
+ return /* @__PURE__ */ import_react2.default.createElement(
895
+ import_Button.default,
896
+ {
897
+ variant: "contained",
898
+ color: "primary",
899
+ disableElevation: true,
900
+ size,
901
+ fullWidth,
902
+ startIcon: /* @__PURE__ */ import_react2.default.createElement(import_icons_material.Add, null),
903
+ component: import_core_components.Link,
904
+ to
905
+ },
906
+ label
907
+ );
908
+ }
909
+ return /* @__PURE__ */ import_react2.default.createElement(
910
+ import_Button.default,
911
+ {
912
+ variant: "contained",
913
+ color: "primary",
914
+ disableElevation: true,
915
+ size,
916
+ fullWidth,
917
+ startIcon: /* @__PURE__ */ import_react2.default.createElement(import_icons_material.Add, null),
918
+ disabled: true
919
+ },
920
+ label
921
+ );
922
+ };
923
+ }
924
+ });
925
+
861
926
  // src/components/DashboardHeader.tsx
862
927
  function initials(name) {
863
928
  const local = name.split("@")[0] ?? name;
@@ -865,24 +930,23 @@ function initials(name) {
865
930
  if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
866
931
  return local.slice(0, 2).toUpperCase();
867
932
  }
868
- var import_react2, import_Box2, import_Typography2, import_Skeleton, import_Paper2, import_Button, import_Divider, import_styles2, import_icons_material, CountStat, DashboardHeader;
933
+ var import_react3, import_Box2, import_Typography2, import_Skeleton, import_Paper2, import_Divider, import_styles2, CountStat, DashboardHeader;
869
934
  var init_DashboardHeader = __esm({
870
935
  "src/components/DashboardHeader.tsx"() {
871
936
  "use strict";
872
- import_react2 = __toESM(require("react"));
937
+ import_react3 = __toESM(require("react"));
873
938
  import_Box2 = __toESM(require("@mui/material/Box"));
874
939
  import_Typography2 = __toESM(require("@mui/material/Typography"));
875
940
  import_Skeleton = __toESM(require("@mui/material/Skeleton"));
876
941
  import_Paper2 = __toESM(require("@mui/material/Paper"));
877
- import_Button = __toESM(require("@mui/material/Button"));
878
942
  import_Divider = __toESM(require("@mui/material/Divider"));
879
943
  import_styles2 = require("@mui/material/styles");
880
- import_icons_material = require("@mui/icons-material");
881
944
  init_api();
882
945
  init_ui();
946
+ init_GenerateKeyButton();
883
947
  CountStat = ({ value, label, tone }) => {
884
948
  const active = value > 0;
885
- return /* @__PURE__ */ import_react2.default.createElement(import_Box2.default, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ import_react2.default.createElement(
949
+ return /* @__PURE__ */ import_react3.default.createElement(import_Box2.default, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ import_react3.default.createElement(
886
950
  import_Box2.default,
887
951
  {
888
952
  sx: (theme) => ({
@@ -893,14 +957,14 @@ var init_DashboardHeader = __esm({
893
957
  bgcolor: active ? tone === "danger" && theme.palette.error.main || tone === "warning" && theme.palette.warning.main || theme.palette.primary.main : (0, import_styles2.alpha)(theme.palette.text.primary, 0.25)
894
958
  })
895
959
  }
896
- ), /* @__PURE__ */ import_react2.default.createElement(
960
+ ), /* @__PURE__ */ import_react3.default.createElement(
897
961
  import_Typography2.default,
898
962
  {
899
963
  component: "span",
900
964
  sx: { fontSize: 15, fontWeight: 700, lineHeight: 1, fontVariantNumeric: "tabular-nums" }
901
965
  },
902
966
  value
903
- ), /* @__PURE__ */ import_react2.default.createElement(
967
+ ), /* @__PURE__ */ import_react3.default.createElement(
904
968
  import_Typography2.default,
905
969
  {
906
970
  component: "span",
@@ -918,13 +982,13 @@ var init_DashboardHeader = __esm({
918
982
  onGenerateKeyClick,
919
983
  tabs
920
984
  }) => {
921
- const counts = (0, import_react2.useMemo)(() => {
985
+ const counts = (0, import_react3.useMemo)(() => {
922
986
  const expired = keys.filter((k) => expiryStatus(k.expires_at) === "expired").length;
923
987
  const expiringSoon = keys.filter((k) => expiryStatus(k.expires_at) === "soon").length;
924
988
  return { total: keys.length, expired, expiringSoon };
925
989
  }, [keys]);
926
990
  const displayName = userInfo.user_email ?? userInfo.email ?? userInfo.user_id;
927
- return /* @__PURE__ */ import_react2.default.createElement(import_Paper2.default, { sx: { borderRadius: 2, overflow: "hidden" } }, /* @__PURE__ */ import_react2.default.createElement(
991
+ return /* @__PURE__ */ import_react3.default.createElement(import_Paper2.default, { sx: { borderRadius: 2, overflow: "hidden" } }, /* @__PURE__ */ import_react3.default.createElement(
928
992
  import_Box2.default,
929
993
  {
930
994
  sx: {
@@ -937,7 +1001,7 @@ var init_DashboardHeader = __esm({
937
1001
  pb: 2
938
1002
  }
939
1003
  },
940
- /* @__PURE__ */ import_react2.default.createElement(
1004
+ /* @__PURE__ */ import_react3.default.createElement(
941
1005
  import_Box2.default,
942
1006
  {
943
1007
  sx: (theme) => ({
@@ -957,7 +1021,7 @@ var init_DashboardHeader = __esm({
957
1021
  },
958
1022
  initials(displayName)
959
1023
  ),
960
- /* @__PURE__ */ import_react2.default.createElement(import_Box2.default, { sx: { flexGrow: 1, minWidth: 220 } }, /* @__PURE__ */ import_react2.default.createElement(import_Typography2.default, { variant: "h6", sx: { lineHeight: 1.25, wordBreak: "break-word" } }, displayName), /* @__PURE__ */ import_react2.default.createElement(
1024
+ /* @__PURE__ */ import_react3.default.createElement(import_Box2.default, { sx: { flexGrow: 1, minWidth: 220 } }, /* @__PURE__ */ import_react3.default.createElement(import_Typography2.default, { variant: "h6", sx: { lineHeight: 1.25, wordBreak: "break-word" } }, displayName), /* @__PURE__ */ import_react3.default.createElement(
961
1025
  import_Typography2.default,
962
1026
  {
963
1027
  variant: "caption",
@@ -965,7 +1029,7 @@ var init_DashboardHeader = __esm({
965
1029
  sx: { display: "block", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
966
1030
  },
967
1031
  userInfo.user_id
968
- ), /* @__PURE__ */ import_react2.default.createElement(import_Box2.default, { sx: { display: "flex", gap: 0.75, flexWrap: "wrap", mt: 1, minHeight: 20 } }, loading ? /* @__PURE__ */ import_react2.default.createElement(import_Skeleton.default, { variant: "rounded", width: 140, height: 20 }) : teams.map((team) => /* @__PURE__ */ import_react2.default.createElement(
1032
+ ), /* @__PURE__ */ import_react3.default.createElement(import_Box2.default, { sx: { display: "flex", gap: 0.75, flexWrap: "wrap", mt: 1, minHeight: 20 } }, loading ? /* @__PURE__ */ import_react3.default.createElement(import_Skeleton.default, { variant: "rounded", width: 140, height: 20 }) : teams.map((team) => /* @__PURE__ */ import_react3.default.createElement(
969
1033
  TagChip,
970
1034
  {
971
1035
  key: team.team_id,
@@ -973,18 +1037,8 @@ var init_DashboardHeader = __esm({
973
1037
  title: team.team_id
974
1038
  }
975
1039
  )))),
976
- /* @__PURE__ */ import_react2.default.createElement(
977
- import_Button.default,
978
- {
979
- variant: "contained",
980
- color: "primary",
981
- disableElevation: true,
982
- startIcon: /* @__PURE__ */ import_react2.default.createElement(import_icons_material.Add, null),
983
- onClick: onGenerateKeyClick
984
- },
985
- "Generate New Key"
986
- )
987
- ), /* @__PURE__ */ import_react2.default.createElement(import_Divider.default, null), /* @__PURE__ */ import_react2.default.createElement(
1040
+ /* @__PURE__ */ import_react3.default.createElement(GenerateKeyButton, { onClick: onGenerateKeyClick })
1041
+ ), /* @__PURE__ */ import_react3.default.createElement(import_Divider.default, null), /* @__PURE__ */ import_react3.default.createElement(
988
1042
  import_Box2.default,
989
1043
  {
990
1044
  sx: {
@@ -996,12 +1050,12 @@ var init_DashboardHeader = __esm({
996
1050
  py: 1.5
997
1051
  }
998
1052
  },
999
- /* @__PURE__ */ import_react2.default.createElement(CountStat, { value: counts.total, label: "keys", tone: "accent" }),
1000
- /* @__PURE__ */ import_react2.default.createElement(import_Divider.default, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1001
- /* @__PURE__ */ import_react2.default.createElement(CountStat, { value: counts.expired, label: "expired", tone: "danger" }),
1002
- /* @__PURE__ */ import_react2.default.createElement(import_Divider.default, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1003
- /* @__PURE__ */ import_react2.default.createElement(CountStat, { value: counts.expiringSoon, label: "expiring soon", tone: "warning" })
1004
- ), tabs && /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_Divider.default, null), /* @__PURE__ */ import_react2.default.createElement(import_Box2.default, { sx: { px: 1 } }, tabs)));
1053
+ /* @__PURE__ */ import_react3.default.createElement(CountStat, { value: counts.total, label: "keys", tone: "accent" }),
1054
+ /* @__PURE__ */ import_react3.default.createElement(import_Divider.default, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1055
+ /* @__PURE__ */ import_react3.default.createElement(CountStat, { value: counts.expired, label: "expired", tone: "danger" }),
1056
+ /* @__PURE__ */ import_react3.default.createElement(import_Divider.default, { orientation: "vertical", flexItem: true, sx: { my: 0.25 } }),
1057
+ /* @__PURE__ */ import_react3.default.createElement(CountStat, { value: counts.expiringSoon, label: "expiring soon", tone: "warning" })
1058
+ ), tabs && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement(import_Divider.default, null), /* @__PURE__ */ import_react3.default.createElement(import_Box2.default, { sx: { px: 1 } }, tabs)));
1005
1059
  };
1006
1060
  }
1007
1061
  });
@@ -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__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, "Never");
1077
+ return /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, "Never");
1024
1078
  }
1025
1079
  if (status === "ok") {
1026
- return /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, formatDate(expiresAt));
1080
+ return /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, formatDate(expiresAt));
1027
1081
  }
1028
- return /* @__PURE__ */ import_react3.default.createElement(
1082
+ return /* @__PURE__ */ import_react4.default.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__ */ import_react3.default.createElement(import_CircularProgress.default, { size: 18 });
1044
- if (blocked) return /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.LockOpen, { fontSize: "small" });
1045
- return /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Lock, { fontSize: "small" });
1097
+ if (isBlocking) return /* @__PURE__ */ import_react4.default.createElement(import_CircularProgress.default, { size: 18 });
1098
+ if (blocked) return /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.LockOpen, { fontSize: "small" });
1099
+ return /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Lock, { fontSize: "small" });
1046
1100
  }
1047
1101
  function BudgetCell({ spend, maxBudget }) {
1048
1102
  if (!maxBudget) {
1049
- return /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, "$", spend.toFixed(2), /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { component: "span", variant: "caption", sx: { ml: 0.5, opacity: 0.7 } }, "/ \u221E"));
1103
+ return /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, "$", spend.toFixed(2), /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { 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__ */ import_react3.default.createElement(import_Box3.default, { minWidth: 104 }, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums", mb: 0.5 } }, "$", spend.toFixed(2), /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { component: "span", variant: "caption", color: "text.secondary", sx: { ml: 0.5 } }, "/ $", maxBudget)), /* @__PURE__ */ import_react3.default.createElement(Meter, { value: pct, tone: budgetTone(pct), height: 4 }));
1106
+ return /* @__PURE__ */ import_react4.default.createElement(import_Box3.default, { minWidth: 104 }, /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums", mb: 0.5 } }, "$", spend.toFixed(2), /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { component: "span", variant: "caption", color: "text.secondary", sx: { ml: 0.5 } }, "/ $", maxBudget)), /* @__PURE__ */ import_react4.default.createElement(Meter, { value: pct, tone: budgetTone(pct), height: 4 }));
1053
1107
  }
1054
1108
  function compareKeys(a, b, sortKey) {
1055
1109
  switch (sortKey) {
@@ -1069,11 +1123,11 @@ function compareKeys(a, b, sortKey) {
1069
1123
  return 0;
1070
1124
  }
1071
1125
  }
1072
- var import_react3, import_Table, import_TableBody, import_TableCell, import_TableContainer, import_TableHead, import_TableRow, import_TableSortLabel, import_Button2, import_IconButton, import_Box3, import_Typography3, import_Dialog, import_DialogTitle, import_DialogContent, import_DialogActions, import_TextField, import_CircularProgress, import_Skeleton2, import_InputAdornment, import_styles3, import_icons_material2, shortKeyId, formatDate, KeysTable;
1126
+ var import_react4, import_Table, import_TableBody, import_TableCell, import_TableContainer, import_TableHead, import_TableRow, import_TableSortLabel, import_Button2, import_IconButton, import_Box3, import_Typography3, import_Dialog, import_DialogTitle, import_DialogContent, import_DialogActions, import_TextField, import_CircularProgress, import_Skeleton2, import_InputAdornment, import_styles3, import_icons_material2, shortKeyId, formatDate, KeysTable;
1073
1127
  var init_KeysTable = __esm({
1074
1128
  "src/components/KeysTable.tsx"() {
1075
1129
  "use strict";
1076
- import_react3 = __toESM(require("react"));
1130
+ import_react4 = __toESM(require("react"));
1077
1131
  import_Table = __toESM(require("@mui/material/Table"));
1078
1132
  import_TableBody = __toESM(require("@mui/material/TableBody"));
1079
1133
  import_TableCell = __toESM(require("@mui/material/TableCell"));
@@ -1096,6 +1150,7 @@ var init_KeysTable = __esm({
1096
1150
  import_styles3 = require("@mui/material/styles");
1097
1151
  import_icons_material2 = require("@mui/icons-material");
1098
1152
  init_api();
1153
+ init_GenerateKeyButton();
1099
1154
  init_ui();
1100
1155
  shortKeyId = (token) => {
1101
1156
  if (!token) return "-";
@@ -1119,12 +1174,12 @@ var init_KeysTable = __esm({
1119
1174
  onDeleteKey,
1120
1175
  onPruneExpiredKeys
1121
1176
  }) => {
1122
- const [blockingKeyId, setBlockingKeyId] = (0, import_react3.useState)(null);
1123
- const [deleteConfirmId, setDeleteConfirmId] = (0, import_react3.useState)(null);
1124
- const [deleteSubmitting, setDeleteSubmitting] = (0, import_react3.useState)(false);
1125
- const [filterText, setFilterText] = (0, import_react3.useState)("");
1126
- const [sortKey, setSortKey] = (0, import_react3.useState)("created");
1127
- const [sortDirection, setSortDirection] = (0, import_react3.useState)("desc");
1177
+ const [blockingKeyId, setBlockingKeyId] = (0, import_react4.useState)(null);
1178
+ const [deleteConfirmId, setDeleteConfirmId] = (0, import_react4.useState)(null);
1179
+ const [deleteSubmitting, setDeleteSubmitting] = (0, import_react4.useState)(false);
1180
+ const [filterText, setFilterText] = (0, import_react4.useState)("");
1181
+ const [sortKey, setSortKey] = (0, import_react4.useState)("created");
1182
+ const [sortDirection, setSortDirection] = (0, import_react4.useState)("desc");
1128
1183
  const handleSort = (nextSortKey) => {
1129
1184
  if (sortKey === nextSortKey) {
1130
1185
  setSortDirection((current) => current === "asc" ? "desc" : "asc");
@@ -1133,7 +1188,7 @@ var init_KeysTable = __esm({
1133
1188
  setSortDirection("asc");
1134
1189
  }
1135
1190
  };
1136
- const filteredKeys = (0, import_react3.useMemo)(() => {
1191
+ const filteredKeys = (0, import_react4.useMemo)(() => {
1137
1192
  let result = keys;
1138
1193
  if (filterText.trim()) {
1139
1194
  const q = filterText.toLowerCase();
@@ -1175,9 +1230,9 @@ var init_KeysTable = __esm({
1175
1230
  const copyToClipboard = (text) => {
1176
1231
  navigator.clipboard.writeText(text);
1177
1232
  };
1178
- const [pruneConfirmCount, setPruneConfirmCount] = (0, import_react3.useState)(null);
1179
- const [pruneSubmitting, setPruneSubmitting] = (0, import_react3.useState)(false);
1180
- const expiredKeys = (0, import_react3.useMemo)(() => {
1233
+ const [pruneConfirmCount, setPruneConfirmCount] = (0, import_react4.useState)(null);
1234
+ const [pruneSubmitting, setPruneSubmitting] = (0, import_react4.useState)(false);
1235
+ const expiredKeys = (0, import_react4.useMemo)(() => {
1181
1236
  return keys.filter((k) => expiryStatus(k.expires_at) === "expired");
1182
1237
  }, [keys]);
1183
1238
  const handlePruneExpired = async () => {
@@ -1194,32 +1249,27 @@ var init_KeysTable = __esm({
1194
1249
  };
1195
1250
  const renderTableBody = () => {
1196
1251
  if (loading) {
1197
- return /* @__PURE__ */ import_react3.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { colSpan: 8, sx: { py: 2 } }, /* @__PURE__ */ import_react3.default.createElement(import_Skeleton2.default, { variant: "rounded", height: 140 })));
1252
+ return /* @__PURE__ */ import_react4.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { colSpan: 8, sx: { py: 2 } }, /* @__PURE__ */ import_react4.default.createElement(import_Skeleton2.default, { variant: "rounded", height: 140 })));
1198
1253
  }
1199
1254
  if (filteredKeys.length === 0) {
1200
- return /* @__PURE__ */ import_react3.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { colSpan: 8 }, filterText ? /* @__PURE__ */ import_react3.default.createElement(
1255
+ return /* @__PURE__ */ import_react4.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { colSpan: 8 }, filterText ? /* @__PURE__ */ import_react4.default.createElement(
1201
1256
  EmptyState,
1202
1257
  {
1203
1258
  message: "No keys match that filter",
1204
1259
  hint: "Try a different alias or model name."
1205
1260
  }
1206
- ) : /* @__PURE__ */ import_react3.default.createElement(
1261
+ ) : /* @__PURE__ */ import_react4.default.createElement(
1207
1262
  EmptyState,
1208
1263
  {
1209
1264
  message: "No keys yet",
1210
1265
  hint: "Generate your first key to start calling models.",
1211
- action: /* @__PURE__ */ import_react3.default.createElement(
1212
- import_Button2.default,
1266
+ action: /* @__PURE__ */ import_react4.default.createElement(
1267
+ GenerateKeyButton,
1213
1268
  {
1214
- variant: "contained",
1215
- color: "primary",
1216
1269
  size: "small",
1217
- disableElevation: true,
1218
- startIcon: /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Add, null),
1219
- onClick: onGenerateKeyClick,
1220
- sx: { mt: 1 }
1221
- },
1222
- "Generate Your First Key"
1270
+ label: "Generate Your First Key",
1271
+ onClick: onGenerateKeyClick
1272
+ }
1223
1273
  )
1224
1274
  }
1225
1275
  )));
@@ -1228,7 +1278,7 @@ var init_KeysTable = __esm({
1228
1278
  const keyId = key.token ?? key.key;
1229
1279
  const isBlocking = blockingKeyId === keyId;
1230
1280
  const keyModels = key.models ?? [];
1231
- return /* @__PURE__ */ import_react3.default.createElement(
1281
+ return /* @__PURE__ */ import_react4.default.createElement(
1232
1282
  import_TableRow.default,
1233
1283
  {
1234
1284
  key: keyId,
@@ -1239,8 +1289,8 @@ var init_KeysTable = __esm({
1239
1289
  "& td": { color: theme.palette.text.secondary }
1240
1290
  }) : void 0
1241
1291
  },
1242
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2" }, key.key_alias || "\u2014"), key.blocked && /* @__PURE__ */ import_react3.default.createElement(StatusPill, { label: "Blocked", tone: "danger" }))),
1243
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ import_react3.default.createElement(
1292
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2" }, key.key_alias || "\u2014"), key.blocked && /* @__PURE__ */ import_react4.default.createElement(StatusPill, { label: "Blocked", tone: "danger" }))),
1293
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Box3.default, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ import_react4.default.createElement(
1244
1294
  import_Typography3.default,
1245
1295
  {
1246
1296
  variant: "body2",
@@ -1257,7 +1307,7 @@ var init_KeysTable = __esm({
1257
1307
  })
1258
1308
  },
1259
1309
  shortKeyId(keyId)
1260
- ), /* @__PURE__ */ import_react3.default.createElement(
1310
+ ), /* @__PURE__ */ import_react4.default.createElement(
1261
1311
  import_IconButton.default,
1262
1312
  {
1263
1313
  size: "small",
@@ -1265,13 +1315,13 @@ var init_KeysTable = __esm({
1265
1315
  title: "Copy Key ID",
1266
1316
  sx: quietIconButtonSx("accent")
1267
1317
  },
1268
- /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.ContentCopy, { sx: { fontSize: 15 } })
1318
+ /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.ContentCopy, { sx: { fontSize: 15 } })
1269
1319
  ))),
1270
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, formatDate(key.created_at))),
1271
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(ExpiryCell, { expiresAt: key.expires_at })),
1272
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })),
1273
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, key.tpm_limit ?? "\u221E", " / ", key.rpm_limit ?? "\u221E")),
1274
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, keyModels.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, "All models") : /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, keyModels.slice(0, 2).map((model) => /* @__PURE__ */ import_react3.default.createElement(TagChip, { key: model, label: model, title: model })), keyModels.length > 2 && /* @__PURE__ */ import_react3.default.createElement(
1320
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, formatDate(key.created_at))),
1321
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react4.default.createElement(ExpiryCell, { expiresAt: key.expires_at })),
1322
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react4.default.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })),
1323
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, key.tpm_limit ?? "\u221E", " / ", key.rpm_limit ?? "\u221E")),
1324
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, keyModels.length === 0 ? /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, { variant: "body2", color: "text.secondary" }, "All models") : /* @__PURE__ */ import_react4.default.createElement(import_Box3.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, keyModels.slice(0, 2).map((model) => /* @__PURE__ */ import_react4.default.createElement(TagChip, { key: model, label: model, title: model })), keyModels.length > 2 && /* @__PURE__ */ import_react4.default.createElement(
1275
1325
  TagChip,
1276
1326
  {
1277
1327
  label: `+${keyModels.length - 2}`,
@@ -1279,7 +1329,7 @@ var init_KeysTable = __esm({
1279
1329
  title: keyModels.slice(2).join(", ")
1280
1330
  }
1281
1331
  ))),
1282
- /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { align: "right" }, /* @__PURE__ */ import_react3.default.createElement(import_Box3.default, { display: "flex", justifyContent: "flex-end", gap: 0.25 }, /* @__PURE__ */ import_react3.default.createElement(
1332
+ /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { align: "right" }, /* @__PURE__ */ import_react4.default.createElement(import_Box3.default, { display: "flex", justifyContent: "flex-end", gap: 0.25 }, /* @__PURE__ */ import_react4.default.createElement(
1283
1333
  import_IconButton.default,
1284
1334
  {
1285
1335
  size: "small",
@@ -1287,8 +1337,8 @@ var init_KeysTable = __esm({
1287
1337
  title: "Edit key",
1288
1338
  sx: quietIconButtonSx("accent")
1289
1339
  },
1290
- /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Edit, { fontSize: "small" })
1291
- ), /* @__PURE__ */ import_react3.default.createElement(
1340
+ /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Edit, { fontSize: "small" })
1341
+ ), /* @__PURE__ */ import_react4.default.createElement(
1292
1342
  import_IconButton.default,
1293
1343
  {
1294
1344
  size: "small",
@@ -1298,7 +1348,7 @@ var init_KeysTable = __esm({
1298
1348
  sx: quietIconButtonSx("warning")
1299
1349
  },
1300
1350
  keyBlockIcon(isBlocking, key.blocked)
1301
- ), /* @__PURE__ */ import_react3.default.createElement(
1351
+ ), /* @__PURE__ */ import_react4.default.createElement(
1302
1352
  import_IconButton.default,
1303
1353
  {
1304
1354
  size: "small",
@@ -1306,18 +1356,18 @@ var init_KeysTable = __esm({
1306
1356
  title: "Revoke key",
1307
1357
  sx: quietIconButtonSx("danger")
1308
1358
  },
1309
- /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Delete, { fontSize: "small" })
1359
+ /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Delete, { fontSize: "small" })
1310
1360
  )))
1311
1361
  );
1312
1362
  });
1313
1363
  };
1314
- return /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement(
1364
+ return /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
1315
1365
  SectionCard,
1316
1366
  {
1317
1367
  title: "Virtual Keys",
1318
1368
  subtitle: loading ? "Loading\u2026" : `${filteredKeys.length}${filterText ? ` of ${keys.length}` : ""} key${filteredKeys.length === 1 ? "" : "s"}`,
1319
1369
  flush: true,
1320
- actions: /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement(
1370
+ actions: /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
1321
1371
  import_TextField.default,
1322
1372
  {
1323
1373
  size: "small",
@@ -1327,15 +1377,15 @@ var init_KeysTable = __esm({
1327
1377
  onChange: (e) => setFilterText(e.target.value),
1328
1378
  sx: { minWidth: 240 },
1329
1379
  InputProps: {
1330
- startAdornment: /* @__PURE__ */ import_react3.default.createElement(import_InputAdornment.default, { position: "start" }, /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Search, { fontSize: "small", color: "disabled" }))
1380
+ startAdornment: /* @__PURE__ */ import_react4.default.createElement(import_InputAdornment.default, { position: "start" }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Search, { fontSize: "small", color: "disabled" }))
1331
1381
  }
1332
1382
  }
1333
- ), expiredKeys.length > 0 && /* @__PURE__ */ import_react3.default.createElement(
1383
+ ), expiredKeys.length > 0 && /* @__PURE__ */ import_react4.default.createElement(
1334
1384
  import_Button2.default,
1335
1385
  {
1336
1386
  variant: "outlined",
1337
1387
  color: "inherit",
1338
- startIcon: /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Autorenew, null),
1388
+ startIcon: /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Autorenew, null),
1339
1389
  onClick: () => setPruneConfirmCount(expiredKeys.length),
1340
1390
  sx: (theme) => ({
1341
1391
  color: theme.palette.text.secondary,
@@ -1350,20 +1400,10 @@ var init_KeysTable = __esm({
1350
1400
  "Prune expired (",
1351
1401
  expiredKeys.length,
1352
1402
  ")"
1353
- ), /* @__PURE__ */ import_react3.default.createElement(
1354
- import_Button2.default,
1355
- {
1356
- variant: "contained",
1357
- color: "primary",
1358
- disableElevation: true,
1359
- startIcon: /* @__PURE__ */ import_react3.default.createElement(import_icons_material2.Add, null),
1360
- onClick: onGenerateKeyClick
1361
- },
1362
- "Generate New Key"
1363
- ))
1403
+ ), /* @__PURE__ */ import_react4.default.createElement(GenerateKeyButton, { onClick: onGenerateKeyClick }))
1364
1404
  },
1365
- /* @__PURE__ */ import_react3.default.createElement(import_TableContainer.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Table.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react3.default.createElement(import_TableHead.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "alias" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "alias", direction: sortKey === "alias" ? sortDirection : "asc", onClick: () => handleSort("alias") }, "Alias")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, null, "Key ID"), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "created" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "created", direction: sortKey === "created" ? sortDirection : "asc", onClick: () => handleSort("created") }, "Created")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "expires" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "expires", direction: sortKey === "expires" ? sortDirection : "asc", onClick: () => handleSort("expires") }, "Expires")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "budget" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "budget", direction: sortKey === "budget" ? sortDirection : "asc", onClick: () => handleSort("budget") }, "Budget")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "limits" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "limits", direction: sortKey === "limits" ? sortDirection : "asc", onClick: () => handleSort("limits") }, "TPM / RPM")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { sortDirection: sortKey === "models" ? sortDirection : false }, /* @__PURE__ */ import_react3.default.createElement(import_TableSortLabel.default, { active: sortKey === "models", direction: sortKey === "models" ? sortDirection : "asc", onClick: () => handleSort("models") }, "Models")), /* @__PURE__ */ import_react3.default.createElement(import_TableCell.default, { align: "right" }, "Actions"))), /* @__PURE__ */ import_react3.default.createElement(import_TableBody.default, null, renderTableBody())))
1366
- ), /* @__PURE__ */ import_react3.default.createElement(import_Dialog.default, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ import_react3.default.createElement(import_DialogTitle.default, null, "Revoke Key?"), /* @__PURE__ */ import_react3.default.createElement(import_DialogContent.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ import_react3.default.createElement(import_DialogActions.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Button2.default, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ import_react3.default.createElement(
1405
+ /* @__PURE__ */ import_react4.default.createElement(import_TableContainer.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Table.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react4.default.createElement(import_TableHead.default, null, /* @__PURE__ */ import_react4.default.createElement(import_TableRow.default, null, /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { sortDirection: sortKey === "alias" ? sortDirection : false }, /* @__PURE__ */ import_react4.default.createElement(import_TableSortLabel.default, { active: sortKey === "alias", direction: sortKey === "alias" ? sortDirection : "asc", onClick: () => handleSort("alias") }, "Alias")), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, null, "Key ID"), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { sortDirection: sortKey === "created" ? sortDirection : false }, /* @__PURE__ */ import_react4.default.createElement(import_TableSortLabel.default, { active: sortKey === "created", direction: sortKey === "created" ? sortDirection : "asc", onClick: () => handleSort("created") }, "Created")), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { sortDirection: sortKey === "expires" ? sortDirection : false }, /* @__PURE__ */ import_react4.default.createElement(import_TableSortLabel.default, { active: sortKey === "expires", direction: sortKey === "expires" ? sortDirection : "asc", onClick: () => handleSort("expires") }, "Expires")), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { sortDirection: sortKey === "budget" ? sortDirection : false }, /* @__PURE__ */ import_react4.default.createElement(import_TableSortLabel.default, { active: sortKey === "budget", direction: sortKey === "budget" ? sortDirection : "asc", onClick: () => handleSort("budget") }, "Budget")), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { sortDirection: sortKey === "limits" ? sortDirection : false }, /* @__PURE__ */ import_react4.default.createElement(import_TableSortLabel.default, { active: sortKey === "limits", direction: sortKey === "limits" ? sortDirection : "asc", onClick: () => handleSort("limits") }, "TPM / RPM")), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { sortDirection: sortKey === "models" ? sortDirection : false }, /* @__PURE__ */ import_react4.default.createElement(import_TableSortLabel.default, { active: sortKey === "models", direction: sortKey === "models" ? sortDirection : "asc", onClick: () => handleSort("models") }, "Models")), /* @__PURE__ */ import_react4.default.createElement(import_TableCell.default, { align: "right" }, "Actions"))), /* @__PURE__ */ import_react4.default.createElement(import_TableBody.default, null, renderTableBody())))
1406
+ ), /* @__PURE__ */ import_react4.default.createElement(import_Dialog.default, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ import_react4.default.createElement(import_DialogTitle.default, null, "Revoke Key?"), /* @__PURE__ */ import_react4.default.createElement(import_DialogContent.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ import_react4.default.createElement(import_DialogActions.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Button2.default, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ import_react4.default.createElement(
1367
1407
  import_Button2.default,
1368
1408
  {
1369
1409
  onClick: handleConfirmDelete,
@@ -1371,8 +1411,8 @@ var init_KeysTable = __esm({
1371
1411
  color: "error",
1372
1412
  disabled: deleteSubmitting
1373
1413
  },
1374
- deleteSubmitting ? /* @__PURE__ */ import_react3.default.createElement(import_CircularProgress.default, { size: 20 }) : "Revoke"
1375
- ))), /* @__PURE__ */ import_react3.default.createElement(import_Dialog.default, { open: pruneConfirmCount !== null, onClose: () => setPruneConfirmCount(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ import_react3.default.createElement(import_DialogTitle.default, null, "Prune Expired Keys?"), /* @__PURE__ */ import_react3.default.createElement(import_DialogContent.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Typography3.default, null, "This will permanently delete ", pruneConfirmCount, " expired key", pruneConfirmCount !== 1 ? "s" : "", " from LiteLLM. Any integrations using them will stop working immediately.")), /* @__PURE__ */ import_react3.default.createElement(import_DialogActions.default, null, /* @__PURE__ */ import_react3.default.createElement(import_Button2.default, { onClick: () => setPruneConfirmCount(null), disabled: pruneSubmitting }, "Cancel"), /* @__PURE__ */ import_react3.default.createElement(
1414
+ deleteSubmitting ? /* @__PURE__ */ import_react4.default.createElement(import_CircularProgress.default, { size: 20 }) : "Revoke"
1415
+ ))), /* @__PURE__ */ import_react4.default.createElement(import_Dialog.default, { open: pruneConfirmCount !== null, onClose: () => setPruneConfirmCount(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ import_react4.default.createElement(import_DialogTitle.default, null, "Prune Expired Keys?"), /* @__PURE__ */ import_react4.default.createElement(import_DialogContent.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Typography3.default, null, "This will permanently delete ", pruneConfirmCount, " expired key", pruneConfirmCount !== 1 ? "s" : "", " from LiteLLM. Any integrations using them will stop working immediately.")), /* @__PURE__ */ import_react4.default.createElement(import_DialogActions.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Button2.default, { onClick: () => setPruneConfirmCount(null), disabled: pruneSubmitting }, "Cancel"), /* @__PURE__ */ import_react4.default.createElement(
1376
1416
  import_Button2.default,
1377
1417
  {
1378
1418
  onClick: handlePruneExpired,
@@ -1380,7 +1420,7 @@ var init_KeysTable = __esm({
1380
1420
  color: "error",
1381
1421
  disabled: pruneSubmitting
1382
1422
  },
1383
- pruneSubmitting ? /* @__PURE__ */ import_react3.default.createElement(import_CircularProgress.default, { size: 20 }) : "Prune"
1423
+ pruneSubmitting ? /* @__PURE__ */ import_react4.default.createElement(import_CircularProgress.default, { size: 20 }) : "Prune"
1384
1424
  ))));
1385
1425
  };
1386
1426
  }
@@ -1518,11 +1558,11 @@ function formatContextWindow(maxInput, maxOutput) {
1518
1558
  if (outPart) return `ctx ${outPart} out`;
1519
1559
  return null;
1520
1560
  }
1521
- var import_react4, import_Box4, import_Typography4, import_Dialog2, import_DialogTitle2, import_DialogContent2, import_DialogActions2, import_TextField2, import_MenuItem, import_Button3, import_IconButton2, import_CircularProgress2, import_Autocomplete, import_Checkbox, import_FormControlLabel, import_Alert, import_Accordion, import_AccordionSummary, import_AccordionDetails, import_Tabs, import_Tab, import_icons_material3, generateDefaultAlias, createForm, editForm, ALL_PROXY_MODELS, SNIPPET_FILE_HINTS, SnippetTabs, KeyFormDialog;
1561
+ var import_react5, import_Box4, import_Typography4, import_Dialog2, import_DialogTitle2, import_DialogContent2, import_DialogActions2, import_TextField2, import_MenuItem, import_Button3, import_IconButton2, import_CircularProgress2, import_Autocomplete, import_Checkbox, import_FormControlLabel, import_Alert, import_Accordion, import_AccordionSummary, import_AccordionDetails, import_Tabs, import_Tab, import_icons_material3, generateDefaultAlias, createForm, editForm, ALL_PROXY_MODELS, SNIPPET_FILE_HINTS, SnippetTabs, KeyFormDialog;
1522
1562
  var init_KeyFormDialog = __esm({
1523
1563
  "src/components/KeyFormDialog.tsx"() {
1524
1564
  "use strict";
1525
- import_react4 = __toESM(require("react"));
1565
+ import_react5 = __toESM(require("react"));
1526
1566
  import_Box4 = __toESM(require("@mui/material/Box"));
1527
1567
  import_Typography4 = __toESM(require("@mui/material/Typography"));
1528
1568
  import_Dialog2 = __toESM(require("@mui/material/Dialog"));
@@ -1574,18 +1614,18 @@ var init_KeyFormDialog = __esm({
1574
1614
  "claude-code": "Requires Claude Code CLI installed"
1575
1615
  };
1576
1616
  SnippetTabs = ({ snippets, model, onCopy }) => {
1577
- const [tab, setTab] = (0, import_react4.useState)("curl");
1617
+ const [tab, setTab] = (0, import_react5.useState)("curl");
1578
1618
  const snippetKey = tab === "claude-code" ? "claudeCode" : tab;
1579
1619
  const code = snippets[snippetKey];
1580
1620
  const fileHint = SNIPPET_FILE_HINTS[tab];
1581
- return /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Tabs.default, { value: tab, onChange: (_, v) => setTab(v), sx: { mb: 1 }, variant: "scrollable" }, /* @__PURE__ */ import_react4.default.createElement(import_Tab.default, { label: "curl", value: "curl" }), /* @__PURE__ */ import_react4.default.createElement(import_Tab.default, { label: "OpenAI SDK", value: "openai" }), /* @__PURE__ */ import_react4.default.createElement(import_Tab.default, { label: "opencode", value: "opencode" }), /* @__PURE__ */ import_react4.default.createElement(import_Tab.default, { label: "pi", value: "pi" }), /* @__PURE__ */ import_react4.default.createElement(import_Tab.default, { label: "Claude Code", value: "claude-code" })), fileHint && /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", mb: 0.5 }, fileHint), /* @__PURE__ */ import_react4.default.createElement(
1621
+ return /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Tabs.default, { value: tab, onChange: (_, v) => setTab(v), sx: { mb: 1 }, variant: "scrollable" }, /* @__PURE__ */ import_react5.default.createElement(import_Tab.default, { label: "curl", value: "curl" }), /* @__PURE__ */ import_react5.default.createElement(import_Tab.default, { label: "OpenAI SDK", value: "openai" }), /* @__PURE__ */ import_react5.default.createElement(import_Tab.default, { label: "opencode", value: "opencode" }), /* @__PURE__ */ import_react5.default.createElement(import_Tab.default, { label: "pi", value: "pi" }), /* @__PURE__ */ import_react5.default.createElement(import_Tab.default, { label: "Claude Code", value: "claude-code" })), fileHint && /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", mb: 0.5 }, fileHint), /* @__PURE__ */ import_react5.default.createElement(
1582
1622
  import_Box4.default,
1583
1623
  {
1584
1624
  position: "relative",
1585
1625
  p: 1.5,
1586
1626
  sx: { backgroundColor: "action.hover", border: "1px solid", borderColor: "divider", borderRadius: 1 }
1587
1627
  },
1588
- /* @__PURE__ */ import_react4.default.createElement(
1628
+ /* @__PURE__ */ import_react5.default.createElement(
1589
1629
  import_IconButton2.default,
1590
1630
  {
1591
1631
  size: "small",
@@ -1593,9 +1633,9 @@ var init_KeyFormDialog = __esm({
1593
1633
  title: "Copy snippet",
1594
1634
  sx: { position: "absolute", top: 4, right: 4 }
1595
1635
  },
1596
- /* @__PURE__ */ import_react4.default.createElement(import_icons_material3.ContentCopy, { fontSize: "small" })
1636
+ /* @__PURE__ */ import_react5.default.createElement(import_icons_material3.ContentCopy, { fontSize: "small" })
1597
1637
  ),
1598
- /* @__PURE__ */ import_react4.default.createElement(
1638
+ /* @__PURE__ */ import_react5.default.createElement(
1599
1639
  import_Typography4.default,
1600
1640
  {
1601
1641
  component: "pre",
@@ -1610,7 +1650,7 @@ var init_KeyFormDialog = __esm({
1610
1650
  },
1611
1651
  code
1612
1652
  ),
1613
- model && /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", mt: 1 }, "Using model \u201C", model, "\u201D \u2014 swap it for any model you have access to.")
1653
+ model && /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", mt: 1 }, "Using model \u201C", model, "\u201D \u2014 swap it for any model you have access to.")
1614
1654
  ));
1615
1655
  };
1616
1656
  KeyFormDialog = ({
@@ -1629,18 +1669,18 @@ var init_KeyFormDialog = __esm({
1629
1669
  onGetConfig
1630
1670
  }) => {
1631
1671
  const isCreate = mode === "create";
1632
- const [generateForm, setGenerateForm] = (0, import_react4.useState)(createForm(username));
1633
- const [editFormState, setEditFormState] = (0, import_react4.useState)({});
1634
- const [unlimitedBudget, setUnlimitedBudget] = (0, import_react4.useState)(false);
1635
- const [submitting, setSubmitting] = (0, import_react4.useState)(false);
1636
- const [newKeyValue, setNewKeyValue] = (0, import_react4.useState)(null);
1637
- const [newKeySnippets, setNewKeySnippets] = (0, import_react4.useState)(null);
1638
- const [newKeyModel, setNewKeyModel] = (0, import_react4.useState)("");
1639
- const [generateError, setGenerateError] = (0, import_react4.useState)(null);
1640
- const [editError, setEditError] = (0, import_react4.useState)(null);
1641
- const [resetSpendConfirm, setResetSpendConfirm] = (0, import_react4.useState)(false);
1642
- const [resetSpendSubmitting, setResetSpendSubmitting] = (0, import_react4.useState)(false);
1643
- (0, import_react4.useEffect)(() => {
1672
+ const [generateForm, setGenerateForm] = (0, import_react5.useState)(createForm(username));
1673
+ const [editFormState, setEditFormState] = (0, import_react5.useState)({});
1674
+ const [unlimitedBudget, setUnlimitedBudget] = (0, import_react5.useState)(false);
1675
+ const [submitting, setSubmitting] = (0, import_react5.useState)(false);
1676
+ const [newKeyValue, setNewKeyValue] = (0, import_react5.useState)(null);
1677
+ const [newKeySnippets, setNewKeySnippets] = (0, import_react5.useState)(null);
1678
+ const [newKeyModel, setNewKeyModel] = (0, import_react5.useState)("");
1679
+ const [generateError, setGenerateError] = (0, import_react5.useState)(null);
1680
+ const [editError, setEditError] = (0, import_react5.useState)(null);
1681
+ const [resetSpendConfirm, setResetSpendConfirm] = (0, import_react5.useState)(false);
1682
+ const [resetSpendSubmitting, setResetSpendSubmitting] = (0, import_react5.useState)(false);
1683
+ (0, import_react5.useEffect)(() => {
1644
1684
  if (open) {
1645
1685
  if (isCreate) {
1646
1686
  setGenerateForm(createForm(username));
@@ -1677,7 +1717,7 @@ var init_KeyFormDialog = __esm({
1677
1717
  else setFormData({ key_alias: value });
1678
1718
  };
1679
1719
  const selectedTeam = teams.find((t) => t.team_id === (isCreate ? generateForm.team_id : void 0)) ?? null;
1680
- const availableModels = (0, import_react4.useMemo)(() => {
1720
+ const availableModels = (0, import_react5.useMemo)(() => {
1681
1721
  return models.filter((m) => isModelAllowedByTeam(m, selectedTeam?.models));
1682
1722
  }, [models, selectedTeam]);
1683
1723
  const selectedModels = availableModels.filter((m) => (formData.models || []).includes(m.model_name));
@@ -1686,7 +1726,7 @@ var init_KeyFormDialog = __esm({
1686
1726
  const budgetInvalid = !unlimitedBudget && (formData.max_budget === void 0 || formData.max_budget === null || formData.max_budget <= 0);
1687
1727
  const canSubmit = !aliasError && !teamError && !budgetInvalid && !submitting;
1688
1728
  const aliasDuplicate = !!currentAlias && keys.some((k) => k.key_alias === currentAlias && k !== keyToEdit);
1689
- const budgetEstimate = (0, import_react4.useMemo)(() => {
1729
+ const budgetEstimate = (0, import_react5.useMemo)(() => {
1690
1730
  if (unlimitedBudget || budgetInvalid) return null;
1691
1731
  const inputCosts = selectedModels.map((m) => m.input_cost_per_token).filter((c) => typeof c === "number" && c > 0);
1692
1732
  if (inputCosts.length === 0) return null;
@@ -1765,11 +1805,11 @@ var init_KeyFormDialog = __esm({
1765
1805
  const inCost = fmtCost(m.input_cost_per_token);
1766
1806
  const outCost = fmtCost(m.output_cost_per_token);
1767
1807
  const ctx = formatContextWindow(m.max_input_tokens, m.max_output_tokens);
1768
- return /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, null, /* @__PURE__ */ import_react4.default.createElement("span", null, m.model_name), m.supports_function_calling && " \u{1F527}", m.supports_vision && " \u{1F441}\uFE0F", ctx && /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, ctx), (inCost || outCost) && /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, inCost, " in \xB7 ", outCost, " out"));
1808
+ return /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, null, /* @__PURE__ */ import_react5.default.createElement("span", null, m.model_name), m.supports_function_calling && " \u{1F527}", m.supports_vision && " \u{1F441}\uFE0F", ctx && /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, ctx), (inCost || outCost) && /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, inCost, " in \xB7 ", outCost, " out"));
1769
1809
  };
1770
1810
  const renderTeamField = () => {
1771
1811
  if (teams.length > 0) {
1772
- return /* @__PURE__ */ import_react4.default.createElement(
1812
+ return /* @__PURE__ */ import_react5.default.createElement(
1773
1813
  import_Autocomplete.default,
1774
1814
  {
1775
1815
  options: teams,
@@ -1783,7 +1823,7 @@ var init_KeyFormDialog = __esm({
1783
1823
  setFormData({ team_id: team?.team_id, models: restrictedModels });
1784
1824
  },
1785
1825
  disabled: !isCreate,
1786
- renderInput: (params) => /* @__PURE__ */ import_react4.default.createElement(
1826
+ renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(
1787
1827
  import_TextField2.default,
1788
1828
  {
1789
1829
  ...params,
@@ -1798,14 +1838,14 @@ var init_KeyFormDialog = __esm({
1798
1838
  );
1799
1839
  }
1800
1840
  if (teamRequired && isCreate) {
1801
- return /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "body2", color: "error" }, "Team selection is required, but you don't belong to any team yet \u2014 contact your administrator.");
1841
+ return /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "body2", color: "error" }, "Team selection is required, but you don't belong to any team yet \u2014 contact your administrator.");
1802
1842
  }
1803
1843
  return null;
1804
1844
  };
1805
1845
  const editKeyId = keyToEdit?.token ?? keyToEdit?.key ?? "";
1806
1846
  const renderDangerZone = () => {
1807
1847
  if (isCreate || !onResetKeySpend) return null;
1808
- return /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, { mt: 1, pt: 2, borderTop: "1px solid", sx: { borderColor: "divider" } }, /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", mb: 1 }, "Danger Zone"), !resetSpendConfirm ? /* @__PURE__ */ import_react4.default.createElement(
1848
+ return /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, { mt: 1, pt: 2, borderTop: "1px solid", sx: { borderColor: "divider" } }, /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", mb: 1 }, "Danger Zone"), !resetSpendConfirm ? /* @__PURE__ */ import_react5.default.createElement(
1809
1849
  import_Button3.default,
1810
1850
  {
1811
1851
  size: "small",
@@ -1814,7 +1854,7 @@ var init_KeyFormDialog = __esm({
1814
1854
  onClick: () => setResetSpendConfirm(true)
1815
1855
  },
1816
1856
  "Reset Spend to $0"
1817
- ) : /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "body2", color: "warning.main" }, "Zero out spend counter?"), /* @__PURE__ */ import_react4.default.createElement(
1857
+ ) : /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, { display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }, /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "body2", color: "warning.main" }, "Zero out spend counter?"), /* @__PURE__ */ import_react5.default.createElement(
1818
1858
  import_Button3.default,
1819
1859
  {
1820
1860
  size: "small",
@@ -1823,8 +1863,8 @@ var init_KeyFormDialog = __esm({
1823
1863
  disabled: resetSpendSubmitting,
1824
1864
  onClick: handleResetSpend
1825
1865
  },
1826
- resetSpendSubmitting ? /* @__PURE__ */ import_react4.default.createElement(import_CircularProgress2.default, { size: 16 }) : "Confirm"
1827
- ), /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel")));
1866
+ resetSpendSubmitting ? /* @__PURE__ */ import_react5.default.createElement(import_CircularProgress2.default, { size: 16 }) : "Confirm"
1867
+ ), /* @__PURE__ */ import_react5.default.createElement(import_Button3.default, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel")));
1828
1868
  };
1829
1869
  const maskKey = (key) => {
1830
1870
  if (key.length <= 8) return "***";
@@ -1834,7 +1874,7 @@ var init_KeyFormDialog = __esm({
1834
1874
  if (newKeyValue) dialogTitle = "Key Generated";
1835
1875
  else if (isCreate) dialogTitle = "Generate New Key";
1836
1876
  const submitLabel = isCreate ? "Generate" : "Save";
1837
- return /* @__PURE__ */ import_react4.default.createElement(import_Dialog2.default, { open, onClose: handleClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ import_react4.default.createElement(import_DialogTitle2.default, null, dialogTitle), /* @__PURE__ */ import_react4.default.createElement(import_DialogContent2.default, null, newKeyValue ? /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, null, /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "body2", color: "text.secondary", gutterBottom: true }, "Copy this key now. You won't be able to see it again."), /* @__PURE__ */ import_react4.default.createElement(
1877
+ return /* @__PURE__ */ import_react5.default.createElement(import_Dialog2.default, { open, onClose: handleClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ import_react5.default.createElement(import_DialogTitle2.default, null, dialogTitle), /* @__PURE__ */ import_react5.default.createElement(import_DialogContent2.default, null, newKeyValue ? /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "body2", color: "text.secondary", gutterBottom: true }, "Copy this key now. You won't be able to see it again."), /* @__PURE__ */ import_react5.default.createElement(
1838
1878
  import_Box4.default,
1839
1879
  {
1840
1880
  display: "flex",
@@ -1849,7 +1889,7 @@ var init_KeyFormDialog = __esm({
1849
1889
  borderRadius: 1
1850
1890
  }
1851
1891
  },
1852
- /* @__PURE__ */ import_react4.default.createElement(
1892
+ /* @__PURE__ */ import_react5.default.createElement(
1853
1893
  import_Typography4.default,
1854
1894
  {
1855
1895
  component: "code",
@@ -1858,8 +1898,8 @@ var init_KeyFormDialog = __esm({
1858
1898
  },
1859
1899
  newKeyValue
1860
1900
  ),
1861
- /* @__PURE__ */ import_react4.default.createElement(import_IconButton2.default, { onClick: () => copyToClipboard(newKeyValue) }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material3.ContentCopy, null))
1862
- ), newKeySnippets && /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, { mt: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "Public endpoint \u2014 paste into any tool's base URL / API base field"), /* @__PURE__ */ import_react4.default.createElement(
1901
+ /* @__PURE__ */ import_react5.default.createElement(import_IconButton2.default, { onClick: () => copyToClipboard(newKeyValue) }, /* @__PURE__ */ import_react5.default.createElement(import_icons_material3.ContentCopy, null))
1902
+ ), newKeySnippets && /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, { mt: 2 }, /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "Public endpoint \u2014 paste into any tool's base URL / API base field"), /* @__PURE__ */ import_react5.default.createElement(
1863
1903
  import_Box4.default,
1864
1904
  {
1865
1905
  display: "flex",
@@ -1873,7 +1913,7 @@ var init_KeyFormDialog = __esm({
1873
1913
  borderRadius: 1
1874
1914
  }
1875
1915
  },
1876
- /* @__PURE__ */ import_react4.default.createElement(
1916
+ /* @__PURE__ */ import_react5.default.createElement(
1877
1917
  import_Typography4.default,
1878
1918
  {
1879
1919
  component: "code",
@@ -1882,8 +1922,8 @@ var init_KeyFormDialog = __esm({
1882
1922
  },
1883
1923
  newKeySnippets.publicEndpoint
1884
1924
  ),
1885
- /* @__PURE__ */ import_react4.default.createElement(import_IconButton2.default, { size: "small", onClick: () => copyToClipboard(newKeySnippets.publicEndpoint) }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material3.ContentCopy, { fontSize: "small" }))
1886
- )), newKeySnippets && /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, { mt: 3 }, /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material3.Code, { fontSize: "small", color: "action" }), /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "subtitle2" }, "Start calling the proxy \u2014 paste and run")), /* @__PURE__ */ import_react4.default.createElement(SnippetTabs, { snippets: newKeySnippets, model: newKeyModel, onCopy: copyToClipboard }))) : /* @__PURE__ */ import_react4.default.createElement(import_Box4.default, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, !isCreate && /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ import_react4.default.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editKeyId))), generateError && /* @__PURE__ */ import_react4.default.createElement(import_Alert.default, { severity: "error", onClose: () => setGenerateError(null) }, generateError), editError && /* @__PURE__ */ import_react4.default.createElement(import_Alert.default, { severity: "error", onClose: () => setEditError(null) }, editError), /* @__PURE__ */ import_react4.default.createElement(
1925
+ /* @__PURE__ */ import_react5.default.createElement(import_IconButton2.default, { size: "small", onClick: () => copyToClipboard(newKeySnippets.publicEndpoint) }, /* @__PURE__ */ import_react5.default.createElement(import_icons_material3.ContentCopy, { fontSize: "small" }))
1926
+ )), newKeySnippets && /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, { mt: 3 }, /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ import_react5.default.createElement(import_icons_material3.Code, { fontSize: "small", color: "action" }), /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "subtitle2" }, "Start calling the proxy \u2014 paste and run")), /* @__PURE__ */ import_react5.default.createElement(SnippetTabs, { snippets: newKeySnippets, model: newKeyModel, onCopy: copyToClipboard }))) : /* @__PURE__ */ import_react5.default.createElement(import_Box4.default, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, !isCreate && /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ import_react5.default.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editKeyId))), generateError && /* @__PURE__ */ import_react5.default.createElement(import_Alert.default, { severity: "error", onClose: () => setGenerateError(null) }, generateError), editError && /* @__PURE__ */ import_react5.default.createElement(import_Alert.default, { severity: "error", onClose: () => setEditError(null) }, editError), /* @__PURE__ */ import_react5.default.createElement(
1887
1927
  import_TextField2.default,
1888
1928
  {
1889
1929
  label: "Alias",
@@ -1899,7 +1939,7 @@ var init_KeyFormDialog = __esm({
1899
1939
  required: true,
1900
1940
  fullWidth: true
1901
1941
  }
1902
- ), !isCreate ? null : /* @__PURE__ */ import_react4.default.createElement(
1942
+ ), !isCreate ? null : /* @__PURE__ */ import_react5.default.createElement(
1903
1943
  import_TextField2.default,
1904
1944
  {
1905
1945
  select: true,
@@ -1908,12 +1948,12 @@ var init_KeyFormDialog = __esm({
1908
1948
  onChange: (e) => setFormData({ duration: e.target.value }),
1909
1949
  fullWidth: true
1910
1950
  },
1911
- /* @__PURE__ */ import_react4.default.createElement(import_MenuItem.default, { value: "1d" }, "1 Day"),
1912
- /* @__PURE__ */ import_react4.default.createElement(import_MenuItem.default, { value: "7d" }, "7 Days"),
1913
- /* @__PURE__ */ import_react4.default.createElement(import_MenuItem.default, { value: "30d" }, "30 Days"),
1914
- /* @__PURE__ */ import_react4.default.createElement(import_MenuItem.default, { value: "90d" }, "90 Days"),
1915
- /* @__PURE__ */ import_react4.default.createElement(import_MenuItem.default, { value: "1y" }, "1 Year")
1916
- ), renderTeamField(), availableModels.length > 0 && /* @__PURE__ */ import_react4.default.createElement(
1951
+ /* @__PURE__ */ import_react5.default.createElement(import_MenuItem.default, { value: "1d" }, "1 Day"),
1952
+ /* @__PURE__ */ import_react5.default.createElement(import_MenuItem.default, { value: "7d" }, "7 Days"),
1953
+ /* @__PURE__ */ import_react5.default.createElement(import_MenuItem.default, { value: "30d" }, "30 Days"),
1954
+ /* @__PURE__ */ import_react5.default.createElement(import_MenuItem.default, { value: "90d" }, "90 Days"),
1955
+ /* @__PURE__ */ import_react5.default.createElement(import_MenuItem.default, { value: "1y" }, "1 Year")
1956
+ ), renderTeamField(), availableModels.length > 0 && /* @__PURE__ */ import_react5.default.createElement(
1917
1957
  import_Autocomplete.default,
1918
1958
  {
1919
1959
  multiple: true,
@@ -1922,8 +1962,8 @@ var init_KeyFormDialog = __esm({
1922
1962
  getOptionLabel: (m) => m.model_name,
1923
1963
  value: selectedModels,
1924
1964
  onChange: (_e, selected) => setFormData({ models: selected.map((m) => m.model_name) }),
1925
- renderOption: (props, m) => /* @__PURE__ */ import_react4.default.createElement("li", { ...props }, modelOption(m)),
1926
- renderInput: (params) => /* @__PURE__ */ import_react4.default.createElement(
1965
+ renderOption: (props, m) => /* @__PURE__ */ import_react5.default.createElement("li", { ...props }, modelOption(m)),
1966
+ renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(
1927
1967
  import_TextField2.default,
1928
1968
  {
1929
1969
  ...params,
@@ -1933,10 +1973,10 @@ var init_KeyFormDialog = __esm({
1933
1973
  }
1934
1974
  )
1935
1975
  }
1936
- ), allowUnlimitedBudget && /* @__PURE__ */ import_react4.default.createElement(
1976
+ ), allowUnlimitedBudget && /* @__PURE__ */ import_react5.default.createElement(
1937
1977
  import_FormControlLabel.default,
1938
1978
  {
1939
- control: /* @__PURE__ */ import_react4.default.createElement(
1979
+ control: /* @__PURE__ */ import_react5.default.createElement(
1940
1980
  import_Checkbox.default,
1941
1981
  {
1942
1982
  checked: unlimitedBudget,
@@ -1952,7 +1992,7 @@ var init_KeyFormDialog = __esm({
1952
1992
  ),
1953
1993
  label: "Unlimited budget"
1954
1994
  }
1955
- ), /* @__PURE__ */ import_react4.default.createElement(
1995
+ ), /* @__PURE__ */ import_react5.default.createElement(
1956
1996
  import_TextField2.default,
1957
1997
  {
1958
1998
  label: "Max Budget (USD)",
@@ -1965,7 +2005,7 @@ var init_KeyFormDialog = __esm({
1965
2005
  required: true,
1966
2006
  fullWidth: true
1967
2007
  }
1968
- ), /* @__PURE__ */ import_react4.default.createElement(import_Accordion.default, { disableGutters: true, elevation: 0, sx: { border: "1px solid", borderColor: "divider", "&:before": { display: "none" } } }, /* @__PURE__ */ import_react4.default.createElement(import_AccordionSummary.default, { expandIcon: /* @__PURE__ */ import_react4.default.createElement(import_icons_material3.ExpandMore, null) }, /* @__PURE__ */ import_react4.default.createElement(import_Typography4.default, { variant: "body2", fontWeight: 600 }, "Advanced")), /* @__PURE__ */ import_react4.default.createElement(import_AccordionDetails.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ import_react4.default.createElement(
2008
+ ), /* @__PURE__ */ import_react5.default.createElement(import_Accordion.default, { disableGutters: true, elevation: 0, sx: { border: "1px solid", borderColor: "divider", "&:before": { display: "none" } } }, /* @__PURE__ */ import_react5.default.createElement(import_AccordionSummary.default, { expandIcon: /* @__PURE__ */ import_react5.default.createElement(import_icons_material3.ExpandMore, null) }, /* @__PURE__ */ import_react5.default.createElement(import_Typography4.default, { variant: "body2", fontWeight: 600 }, "Advanced")), /* @__PURE__ */ import_react5.default.createElement(import_AccordionDetails.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ import_react5.default.createElement(
1969
2009
  import_TextField2.default,
1970
2010
  {
1971
2011
  label: "TPM Limit",
@@ -1975,7 +2015,7 @@ var init_KeyFormDialog = __esm({
1975
2015
  helperText: "Max tokens per minute this key can consume across all models. Leave blank for no limit.",
1976
2016
  fullWidth: true
1977
2017
  }
1978
- ), /* @__PURE__ */ import_react4.default.createElement(
2018
+ ), /* @__PURE__ */ import_react5.default.createElement(
1979
2019
  import_TextField2.default,
1980
2020
  {
1981
2021
  label: "RPM Limit",
@@ -1985,7 +2025,7 @@ var init_KeyFormDialog = __esm({
1985
2025
  helperText: "Max requests per minute this key can make across all models. Leave blank for no limit.",
1986
2026
  fullWidth: true
1987
2027
  }
1988
- ))), renderDangerZone())), /* @__PURE__ */ import_react4.default.createElement(import_DialogActions2.default, null, newKeyValue ? /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { onClick: handleClose, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(import_Button3.default, { onClick: handleClose }, "Cancel"), /* @__PURE__ */ import_react4.default.createElement(
2028
+ ))), renderDangerZone())), /* @__PURE__ */ import_react5.default.createElement(import_DialogActions2.default, null, newKeyValue ? /* @__PURE__ */ import_react5.default.createElement(import_Button3.default, { onClick: handleClose, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(import_Button3.default, { onClick: handleClose }, "Cancel"), /* @__PURE__ */ import_react5.default.createElement(
1989
2029
  import_Button3.default,
1990
2030
  {
1991
2031
  onClick: isCreate ? handleGenerate : handleUpdate,
@@ -1993,18 +2033,18 @@ var init_KeyFormDialog = __esm({
1993
2033
  color: "primary",
1994
2034
  disabled: !canSubmit
1995
2035
  },
1996
- submitting ? /* @__PURE__ */ import_react4.default.createElement(import_CircularProgress2.default, { size: 24 }) : submitLabel
2036
+ submitting ? /* @__PURE__ */ import_react5.default.createElement(import_CircularProgress2.default, { size: 24 }) : submitLabel
1997
2037
  ))));
1998
2038
  };
1999
2039
  }
2000
2040
  });
2001
2041
 
2002
2042
  // src/components/ManageTeamDialog.tsx
2003
- var import_react5, import_Dialog3, import_DialogTitle3, import_DialogContent3, import_DialogActions3, import_TextField3, import_Button4, import_Alert2, import_Checkbox2, import_FormControlLabel2, import_Autocomplete2, import_CircularProgress3, import_MenuItem2, import_Box5, import_Divider2, import_Typography5, import_IconButton3, import_Paper3, import_Table2, import_TableBody2, import_TableCell2, import_TableContainer2, import_TableHead2, import_TableRow2, import_icons_material4, import_core_plugin_api2, import_plugin_catalog_react, import_catalog_model, import_react_use, BUDGET_DURATION_OPTIONS, DEFAULT_BUDGET_DURATION, FALLBACK_BUDGET_CEILING, ManageTeamDialog;
2043
+ var import_react6, import_Dialog3, import_DialogTitle3, import_DialogContent3, import_DialogActions3, import_TextField3, import_Button4, import_Alert2, import_Checkbox2, import_FormControlLabel2, import_Autocomplete2, import_CircularProgress3, import_MenuItem2, import_Box5, import_Divider2, import_Typography5, import_IconButton3, import_Paper3, import_Table2, import_TableBody2, import_TableCell2, import_TableContainer2, import_TableHead2, import_TableRow2, import_icons_material4, import_core_plugin_api2, import_plugin_catalog_react, import_catalog_model, import_react_use, BUDGET_DURATION_OPTIONS, DEFAULT_BUDGET_DURATION, FALLBACK_BUDGET_CEILING, ManageTeamDialog;
2004
2044
  var init_ManageTeamDialog = __esm({
2005
2045
  "src/components/ManageTeamDialog.tsx"() {
2006
2046
  "use strict";
2007
- import_react5 = __toESM(require("react"));
2047
+ import_react6 = __toESM(require("react"));
2008
2048
  import_Dialog3 = __toESM(require("@mui/material/Dialog"));
2009
2049
  import_DialogTitle3 = __toESM(require("@mui/material/DialogTitle"));
2010
2050
  import_DialogContent3 = __toESM(require("@mui/material/DialogContent"));
@@ -2061,29 +2101,29 @@ var init_ManageTeamDialog = __esm({
2061
2101
  mcpServers,
2062
2102
  onSaveMcpServers
2063
2103
  }) => {
2064
- const [alias, setAlias] = (0, import_react5.useState)("");
2065
- const [models, setModels] = (0, import_react5.useState)([]);
2066
- const [maxBudget, setMaxBudget] = (0, import_react5.useState)("");
2067
- const [unlimited, setUnlimited] = (0, import_react5.useState)(false);
2068
- const [budgetDuration, setBudgetDuration] = (0, import_react5.useState)("");
2069
- const [submitting, setSubmitting] = (0, import_react5.useState)(false);
2070
- const [error, setError] = (0, import_react5.useState)(null);
2071
- const [memberQuery, setMemberQuery] = (0, import_react5.useState)("");
2072
- const [memberRef, setMemberRef] = (0, import_react5.useState)("");
2073
- const [memberBudget, setMemberBudget] = (0, import_react5.useState)("");
2074
- const [memberBusy, setMemberBusy] = (0, import_react5.useState)(false);
2075
- const [memberError, setMemberError] = (0, import_react5.useState)(null);
2076
- const [kbIds, setKbIds] = (0, import_react5.useState)([]);
2077
- const [kbBusy, setKbBusy] = (0, import_react5.useState)(false);
2078
- const [kbError, setKbError] = (0, import_react5.useState)(null);
2079
- const [mcpIds, setMcpIds] = (0, import_react5.useState)([]);
2080
- const [mcpBusy, setMcpBusy] = (0, import_react5.useState)(false);
2081
- const [mcpError, setMcpError] = (0, import_react5.useState)(null);
2104
+ const [alias, setAlias] = (0, import_react6.useState)("");
2105
+ const [models, setModels] = (0, import_react6.useState)([]);
2106
+ const [maxBudget, setMaxBudget] = (0, import_react6.useState)("");
2107
+ const [unlimited, setUnlimited] = (0, import_react6.useState)(false);
2108
+ const [budgetDuration, setBudgetDuration] = (0, import_react6.useState)("");
2109
+ const [submitting, setSubmitting] = (0, import_react6.useState)(false);
2110
+ const [error, setError] = (0, import_react6.useState)(null);
2111
+ const [memberQuery, setMemberQuery] = (0, import_react6.useState)("");
2112
+ const [memberRef, setMemberRef] = (0, import_react6.useState)("");
2113
+ const [memberBudget, setMemberBudget] = (0, import_react6.useState)("");
2114
+ const [memberBusy, setMemberBusy] = (0, import_react6.useState)(false);
2115
+ const [memberError, setMemberError] = (0, import_react6.useState)(null);
2116
+ const [kbIds, setKbIds] = (0, import_react6.useState)([]);
2117
+ const [kbBusy, setKbBusy] = (0, import_react6.useState)(false);
2118
+ const [kbError, setKbError] = (0, import_react6.useState)(null);
2119
+ const [mcpIds, setMcpIds] = (0, import_react6.useState)([]);
2120
+ const [mcpBusy, setMcpBusy] = (0, import_react6.useState)(false);
2121
+ const [mcpError, setMcpError] = (0, import_react6.useState)(null);
2082
2122
  const allowUnlimitedBudget = config?.teamManagement?.allowUnlimitedBudget ?? false;
2083
2123
  const maxBudgetCeiling = config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;
2084
2124
  const hideBudgetForManagers = config?.display?.hideTeamBudgetForManagers ?? false;
2085
2125
  const budgetWriteOnly = hideBudgetForManagers && mode === "edit";
2086
- const members = (0, import_react5.useMemo)(() => team?.members_with_roles ?? [], [team]);
2126
+ const members = (0, import_react6.useMemo)(() => team?.members_with_roles ?? [], [team]);
2087
2127
  const showMembers = mode === "edit" && !!canManageMembers;
2088
2128
  const catalogApi = (0, import_core_plugin_api2.useApi)(import_plugin_catalog_react.catalogApiRef);
2089
2129
  const { value: catalogUsers, loading: usersLoading } = (0, import_react_use.useAsync)(async () => {
@@ -2098,7 +2138,7 @@ var init_ManageTeamDialog = __esm({
2098
2138
  return [];
2099
2139
  }
2100
2140
  }, [open, showMembers, catalogApi]);
2101
- const userOptions = (0, import_react5.useMemo)(() => {
2141
+ const userOptions = (0, import_react6.useMemo)(() => {
2102
2142
  const existingEmails = new Set(
2103
2143
  members.map((m) => m.user_email?.toLowerCase()).filter((e) => !!e)
2104
2144
  );
@@ -2113,7 +2153,7 @@ var init_ManageTeamDialog = __esm({
2113
2153
  };
2114
2154
  }).filter((o) => !(o.email && existingEmails.has(o.email.toLowerCase()))).sort((a, b) => a.label.localeCompare(b.label));
2115
2155
  }, [catalogUsers, members]);
2116
- (0, import_react5.useEffect)(() => {
2156
+ (0, import_react6.useEffect)(() => {
2117
2157
  if (open) {
2118
2158
  if (mode === "edit" && team) {
2119
2159
  setAlias(team.team_alias ?? "");
@@ -2269,7 +2309,7 @@ var init_ManageTeamDialog = __esm({
2269
2309
  const showMcpServers = mode === "edit" && !!canManageMcpServers;
2270
2310
  const mcpOptions = (mcpServers ?? []).map((s) => s.id);
2271
2311
  const mcpLabel = (id) => (mcpServers ?? []).find((s) => s.id === id)?.name ?? id;
2272
- return /* @__PURE__ */ import_react5.default.createElement(import_Dialog3.default, { open, onClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ import_react5.default.createElement(import_DialogTitle3.default, null, mode === "create" ? "Create Team" : "Edit Team"), /* @__PURE__ */ import_react5.default.createElement(import_DialogContent3.default, { sx: { pt: 2, display: "flex", flexDirection: "column", gap: 2 } }, error && /* @__PURE__ */ import_react5.default.createElement(import_Alert2.default, { severity: "error" }, error), /* @__PURE__ */ import_react5.default.createElement(
2312
+ return /* @__PURE__ */ import_react6.default.createElement(import_Dialog3.default, { open, onClose, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ import_react6.default.createElement(import_DialogTitle3.default, null, mode === "create" ? "Create Team" : "Edit Team"), /* @__PURE__ */ import_react6.default.createElement(import_DialogContent3.default, { sx: { pt: 2, display: "flex", flexDirection: "column", gap: 2 } }, error && /* @__PURE__ */ import_react6.default.createElement(import_Alert2.default, { severity: "error" }, error), /* @__PURE__ */ import_react6.default.createElement(
2273
2313
  import_TextField3.default,
2274
2314
  {
2275
2315
  label: "Team Alias",
@@ -2278,7 +2318,7 @@ var init_ManageTeamDialog = __esm({
2278
2318
  disabled: submitting,
2279
2319
  fullWidth: true
2280
2320
  }
2281
- ), /* @__PURE__ */ import_react5.default.createElement(
2321
+ ), /* @__PURE__ */ import_react6.default.createElement(
2282
2322
  import_Autocomplete2.default,
2283
2323
  {
2284
2324
  multiple: true,
@@ -2286,7 +2326,7 @@ var init_ManageTeamDialog = __esm({
2286
2326
  value: models,
2287
2327
  onChange: (_, newValue) => setModels(newValue),
2288
2328
  disabled: submitting,
2289
- renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(
2329
+ renderInput: (params) => /* @__PURE__ */ import_react6.default.createElement(
2290
2330
  import_TextField3.default,
2291
2331
  {
2292
2332
  ...params,
@@ -2296,7 +2336,7 @@ var init_ManageTeamDialog = __esm({
2296
2336
  }
2297
2337
  )
2298
2338
  }
2299
- ), /* @__PURE__ */ import_react5.default.createElement(
2339
+ ), /* @__PURE__ */ import_react6.default.createElement(
2300
2340
  import_TextField3.default,
2301
2341
  {
2302
2342
  label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
@@ -2308,13 +2348,13 @@ var init_ManageTeamDialog = __esm({
2308
2348
  helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
2309
2349
  fullWidth: true
2310
2350
  }
2311
- ), allowUnlimitedBudget && /* @__PURE__ */ import_react5.default.createElement(
2351
+ ), allowUnlimitedBudget && /* @__PURE__ */ import_react6.default.createElement(
2312
2352
  import_FormControlLabel2.default,
2313
2353
  {
2314
- control: /* @__PURE__ */ import_react5.default.createElement(import_Checkbox2.default, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
2354
+ control: /* @__PURE__ */ import_react6.default.createElement(import_Checkbox2.default, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
2315
2355
  label: "Unlimited Budget"
2316
2356
  }
2317
- ), /* @__PURE__ */ import_react5.default.createElement(
2357
+ ), /* @__PURE__ */ import_react6.default.createElement(
2318
2358
  import_TextField3.default,
2319
2359
  {
2320
2360
  select: true,
@@ -2325,8 +2365,8 @@ var init_ManageTeamDialog = __esm({
2325
2365
  helperText: "Spend-reset period for the team budget",
2326
2366
  fullWidth: true
2327
2367
  },
2328
- durationOptions.map((o) => /* @__PURE__ */ import_react5.default.createElement(import_MenuItem2.default, { key: o.value, value: o.value }, o.label))
2329
- ), showMembers && /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "Members"), memberError && /* @__PURE__ */ import_react5.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null) }, memberError), members.length === 0 ? /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "No members yet.") : /* @__PURE__ */ import_react5.default.createElement(import_TableContainer2.default, { component: import_Paper3.default, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 } }, /* @__PURE__ */ import_react5.default.createElement(import_Table2.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react5.default.createElement(import_TableHead2.default, null, /* @__PURE__ */ import_react5.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, null, "User"), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right" }, "Role"), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right", sx: { width: 40 } }))), /* @__PURE__ */ import_react5.default.createElement(import_TableBody2.default, null, members.map((m) => /* @__PURE__ */ import_react5.default.createElement(import_TableRow2.default, { key: m.user_id }, /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, null, m.user_email ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react5.default.createElement(
2368
+ durationOptions.map((o) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem2.default, { key: o.value, value: o.value }, o.label))
2369
+ ), showMembers && /* @__PURE__ */ import_react6.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "Members"), memberError && /* @__PURE__ */ import_react6.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null) }, memberError), members.length === 0 ? /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "No members yet.") : /* @__PURE__ */ import_react6.default.createElement(import_TableContainer2.default, { component: import_Paper3.default, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table2.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, "User"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, "Role"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right", sx: { width: 40 } }))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody2.default, null, members.map((m) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow2.default, { key: m.user_id }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, null, m.user_email ? /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react6.default.createElement(
2330
2370
  import_Typography5.default,
2331
2371
  {
2332
2372
  variant: "caption",
@@ -2334,14 +2374,14 @@ var init_ManageTeamDialog = __esm({
2334
2374
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
2335
2375
  },
2336
2376
  m.user_id
2337
- )) : /* @__PURE__ */ import_react5.default.createElement(
2377
+ )) : /* @__PURE__ */ import_react6.default.createElement(
2338
2378
  import_Typography5.default,
2339
2379
  {
2340
2380
  variant: "body2",
2341
2381
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
2342
2382
  },
2343
2383
  m.user_id
2344
- )), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right" }, /* @__PURE__ */ import_react5.default.createElement(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false })), /* @__PURE__ */ import_react5.default.createElement(import_TableCell2.default, { align: "right" }, /* @__PURE__ */ import_react5.default.createElement(
2384
+ )), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, /* @__PURE__ */ import_react6.default.createElement(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false })), /* @__PURE__ */ import_react6.default.createElement(import_TableCell2.default, { align: "right" }, /* @__PURE__ */ import_react6.default.createElement(
2345
2385
  import_IconButton3.default,
2346
2386
  {
2347
2387
  edge: "end",
@@ -2350,8 +2390,8 @@ var init_ManageTeamDialog = __esm({
2350
2390
  disabled: memberBusy,
2351
2391
  onClick: () => handleRemoveMember(m.user_id)
2352
2392
  },
2353
- /* @__PURE__ */ import_react5.default.createElement(import_icons_material4.Delete, { fontSize: "small" })
2354
- ))))))), /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" } }, /* @__PURE__ */ import_react5.default.createElement(
2393
+ /* @__PURE__ */ import_react6.default.createElement(import_icons_material4.Delete, { fontSize: "small" })
2394
+ ))))))), /* @__PURE__ */ import_react6.default.createElement(import_Box5.default, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" } }, /* @__PURE__ */ import_react6.default.createElement(
2355
2395
  import_Autocomplete2.default,
2356
2396
  {
2357
2397
  freeSolo: true,
@@ -2375,7 +2415,7 @@ var init_ManageTeamDialog = __esm({
2375
2415
  isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
2376
2416
  disabled: memberBusy,
2377
2417
  sx: { flex: 1, minWidth: 260 },
2378
- renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(
2418
+ renderInput: (params) => /* @__PURE__ */ import_react6.default.createElement(
2379
2419
  import_TextField3.default,
2380
2420
  {
2381
2421
  ...params,
@@ -2385,12 +2425,12 @@ var init_ManageTeamDialog = __esm({
2385
2425
  helperText: "Pick a catalog user, or paste a user entity ref",
2386
2426
  InputProps: {
2387
2427
  ...params.InputProps,
2388
- endAdornment: /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, usersLoading ? /* @__PURE__ */ import_react5.default.createElement(import_CircularProgress3.default, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2428
+ endAdornment: /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, usersLoading ? /* @__PURE__ */ import_react6.default.createElement(import_CircularProgress3.default, { color: "inherit", size: 14 }) : null, params.InputProps.endAdornment)
2389
2429
  }
2390
2430
  }
2391
2431
  )
2392
2432
  }
2393
- ), /* @__PURE__ */ import_react5.default.createElement(
2433
+ ), /* @__PURE__ */ import_react6.default.createElement(
2394
2434
  import_TextField3.default,
2395
2435
  {
2396
2436
  label: "Max budget in team ($)",
@@ -2401,7 +2441,7 @@ var init_ManageTeamDialog = __esm({
2401
2441
  size: "small",
2402
2442
  sx: { width: 160 }
2403
2443
  }
2404
- ), /* @__PURE__ */ import_react5.default.createElement(
2444
+ ), /* @__PURE__ */ import_react6.default.createElement(
2405
2445
  import_Button4.default,
2406
2446
  {
2407
2447
  onClick: handleAddMember,
@@ -2410,7 +2450,7 @@ var init_ManageTeamDialog = __esm({
2410
2450
  sx: { mt: 0.5 }
2411
2451
  },
2412
2452
  "Add"
2413
- ))), showKnowledgeBases && /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "Knowledge Bases"), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "Attaching a knowledge base exposes its documents to every key in this team."), kbError && /* @__PURE__ */ import_react5.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setKbError(null) }, kbError), /* @__PURE__ */ import_react5.default.createElement(
2453
+ ))), showKnowledgeBases && /* @__PURE__ */ import_react6.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "Knowledge Bases"), /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, "Attaching a knowledge base exposes its documents to every key in this team."), kbError && /* @__PURE__ */ import_react6.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setKbError(null) }, kbError), /* @__PURE__ */ import_react6.default.createElement(
2414
2454
  import_Autocomplete2.default,
2415
2455
  {
2416
2456
  multiple: true,
@@ -2419,9 +2459,9 @@ var init_ManageTeamDialog = __esm({
2419
2459
  getOptionLabel: kbLabel,
2420
2460
  onChange: (_, v) => setKbIds(v),
2421
2461
  disabled: kbBusy,
2422
- renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(import_TextField3.default, { ...params, label: "Attached knowledge bases" })
2462
+ renderInput: (params) => /* @__PURE__ */ import_react6.default.createElement(import_TextField3.default, { ...params, label: "Attached knowledge bases" })
2423
2463
  }
2424
- ), /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ import_react5.default.createElement(
2464
+ ), /* @__PURE__ */ import_react6.default.createElement(import_Box5.default, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ import_react6.default.createElement(
2425
2465
  import_Button4.default,
2426
2466
  {
2427
2467
  onClick: handleSaveKnowledgeBases,
@@ -2429,7 +2469,7 @@ var init_ManageTeamDialog = __esm({
2429
2469
  variant: "outlined"
2430
2470
  },
2431
2471
  kbBusy ? "Saving\u2026" : "Save knowledge bases"
2432
- ))), showMcpServers && /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "MCP Servers"), /* @__PURE__ */ import_react5.default.createElement(import_Typography5.default, { 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__ */ import_react5.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMcpError(null) }, mcpError), /* @__PURE__ */ import_react5.default.createElement(
2472
+ ))), showMcpServers && /* @__PURE__ */ import_react6.default.createElement(import_Box5.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Divider2.default, { sx: { my: 1 } }), /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { variant: "subtitle2", sx: { mb: 1 } }, "MCP Servers"), /* @__PURE__ */ import_react6.default.createElement(import_Typography5.default, { 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__ */ import_react6.default.createElement(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMcpError(null) }, mcpError), /* @__PURE__ */ import_react6.default.createElement(
2433
2473
  import_Autocomplete2.default,
2434
2474
  {
2435
2475
  multiple: true,
@@ -2438,9 +2478,9 @@ var init_ManageTeamDialog = __esm({
2438
2478
  getOptionLabel: mcpLabel,
2439
2479
  onChange: (_, v) => setMcpIds(v),
2440
2480
  disabled: mcpBusy,
2441
- renderInput: (params) => /* @__PURE__ */ import_react5.default.createElement(import_TextField3.default, { ...params, label: "Attached MCP servers" })
2481
+ renderInput: (params) => /* @__PURE__ */ import_react6.default.createElement(import_TextField3.default, { ...params, label: "Attached MCP servers" })
2442
2482
  }
2443
- ), /* @__PURE__ */ import_react5.default.createElement(import_Box5.default, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ import_react5.default.createElement(
2483
+ ), /* @__PURE__ */ import_react6.default.createElement(import_Box5.default, { sx: { display: "flex", justifyContent: "flex-end", mt: 1 } }, /* @__PURE__ */ import_react6.default.createElement(
2444
2484
  import_Button4.default,
2445
2485
  {
2446
2486
  onClick: handleSaveMcpServers,
@@ -2448,7 +2488,7 @@ var init_ManageTeamDialog = __esm({
2448
2488
  variant: "outlined"
2449
2489
  },
2450
2490
  mcpBusy ? "Saving\u2026" : "Save MCP servers"
2451
- )))), /* @__PURE__ */ import_react5.default.createElement(import_DialogActions3.default, null, /* @__PURE__ */ import_react5.default.createElement(import_Button4.default, { onClick: onClose, disabled: submitting }, "Cancel"), /* @__PURE__ */ import_react5.default.createElement(import_Button4.default, { onClick: handleSubmit, disabled: submitting, variant: "contained" }, submitting ? "Saving..." : "Save")));
2491
+ )))), /* @__PURE__ */ import_react6.default.createElement(import_DialogActions3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Button4.default, { onClick: onClose, disabled: submitting }, "Cancel"), /* @__PURE__ */ import_react6.default.createElement(import_Button4.default, { onClick: handleSubmit, disabled: submitting, variant: "contained" }, submitting ? "Saving..." : "Save")));
2452
2492
  };
2453
2493
  }
2454
2494
  });
@@ -2459,11 +2499,11 @@ function rateTone(rate) {
2459
2499
  if (rate >= 0.9) return "warning";
2460
2500
  return "danger";
2461
2501
  }
2462
- var import_react6, import_Paper4, import_Box6, import_Typography6, import_TextField4, import_MenuItem3, import_Grid, import_Table3, import_TableBody3, import_TableCell3, import_TableContainer3, import_TableHead3, import_TableRow3, import_Skeleton3, import_recharts, TOP_N_MODELS, PERIOD_LS_KEY, PRESET_LABELS, fmtPct, ChartSkeleton, ChartOrFallback, SuccessRateCell, UsageStats;
2502
+ var import_react7, import_Paper4, import_Box6, import_Typography6, import_TextField4, import_MenuItem3, import_Grid, import_Table3, import_TableBody3, import_TableCell3, import_TableContainer3, import_TableHead3, import_TableRow3, import_Skeleton3, import_recharts, TOP_N_MODELS, PERIOD_LS_KEY, PRESET_LABELS, fmtPct, ChartSkeleton, ChartOrFallback, SuccessRateCell, UsageStats;
2463
2503
  var init_UsageStats = __esm({
2464
2504
  "src/components/UsageStats.tsx"() {
2465
2505
  "use strict";
2466
- import_react6 = __toESM(require("react"));
2506
+ import_react7 = __toESM(require("react"));
2467
2507
  import_Paper4 = __toESM(require("@mui/material/Paper"));
2468
2508
  import_Box6 = __toESM(require("@mui/material/Box"));
2469
2509
  import_Typography6 = __toESM(require("@mui/material/Typography"));
@@ -2489,16 +2529,16 @@ var init_UsageStats = __esm({
2489
2529
  "30d": "Last 30 days"
2490
2530
  };
2491
2531
  fmtPct = (n) => `${(n * 100).toFixed(1)}%`;
2492
- ChartSkeleton = ({ height = 240 }) => /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height });
2532
+ ChartSkeleton = ({ height = 240 }) => /* @__PURE__ */ import_react7.default.createElement(import_Skeleton3.default, { variant: "rounded", height });
2493
2533
  ChartOrFallback = ({ loading, empty, height = 240, children }) => {
2494
- if (loading) return /* @__PURE__ */ import_react6.default.createElement(ChartSkeleton, { height });
2495
- if (empty) return /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No data for this period", height });
2496
- return /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, children);
2534
+ if (loading) return /* @__PURE__ */ import_react7.default.createElement(ChartSkeleton, { height });
2535
+ if (empty) return /* @__PURE__ */ import_react7.default.createElement(EmptyState, { message: "No data for this period", height });
2536
+ return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, children);
2497
2537
  };
2498
2538
  SuccessRateCell = ({ rate, requests }) => {
2499
- if (requests === 0) return /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", color: "text.secondary" }, "\u2014");
2539
+ if (requests === 0) return /* @__PURE__ */ import_react7.default.createElement(import_Typography6.default, { variant: "body2", color: "text.secondary" }, "\u2014");
2500
2540
  const tone = rateTone(rate);
2501
- return /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { width: 72, flexShrink: 0 }, /* @__PURE__ */ import_react6.default.createElement(Meter, { value: rate * 100, tone, height: 4 })), /* @__PURE__ */ import_react6.default.createElement(
2541
+ return /* @__PURE__ */ import_react7.default.createElement(import_Box6.default, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react7.default.createElement(import_Box6.default, { width: 72, flexShrink: 0 }, /* @__PURE__ */ import_react7.default.createElement(Meter, { value: rate * 100, tone, height: 4 })), /* @__PURE__ */ import_react7.default.createElement(
2502
2542
  import_Typography6.default,
2503
2543
  {
2504
2544
  variant: "caption",
@@ -2517,8 +2557,8 @@ var init_UsageStats = __esm({
2517
2557
  userInfo
2518
2558
  }) => {
2519
2559
  const chart = useChartTheme();
2520
- const [selectedModel, setSelectedModel] = (0, import_react6.useState)("all");
2521
- const [tab, setTab] = (0, import_react6.useState)("costs");
2560
+ const [selectedModel, setSelectedModel] = (0, import_react7.useState)("all");
2561
+ const [tab, setTab] = (0, import_react7.useState)("costs");
2522
2562
  const handlePresetChange = (preset) => {
2523
2563
  const end = /* @__PURE__ */ new Date();
2524
2564
  const start = /* @__PURE__ */ new Date();
@@ -2532,7 +2572,7 @@ var init_UsageStats = __esm({
2532
2572
  }
2533
2573
  onDateRangeChange({ start, end }, preset);
2534
2574
  };
2535
- const dailyData = (0, import_react6.useMemo)(
2575
+ const dailyData = (0, import_react7.useMemo)(
2536
2576
  () => (usage?.daily_usage ?? []).map((d) => ({
2537
2577
  date: d.date,
2538
2578
  spend: d.spend,
@@ -2545,21 +2585,21 @@ var init_UsageStats = __esm({
2545
2585
  })),
2546
2586
  [usage]
2547
2587
  );
2548
- const cumulativeData = (0, import_react6.useMemo)(() => {
2588
+ const cumulativeData = (0, import_react7.useMemo)(() => {
2549
2589
  let cum = 0;
2550
2590
  return dailyData.map((d) => {
2551
2591
  cum += d.spend;
2552
2592
  return { date: d.date, cumulative: cum };
2553
2593
  });
2554
2594
  }, [dailyData]);
2555
- const successRateData = (0, import_react6.useMemo)(
2595
+ const successRateData = (0, import_react7.useMemo)(
2556
2596
  () => dailyData.filter((d) => d.apiRequests > 0).map((d) => ({
2557
2597
  date: d.date,
2558
2598
  successRate: parseFloat((d.successfulRequests / d.apiRequests * 100).toFixed(1))
2559
2599
  })),
2560
2600
  [dailyData]
2561
2601
  );
2562
- const { modelSpendByDate, topModels: topSpendModels } = (0, import_react6.useMemo)(() => {
2602
+ const { modelSpendByDate, topModels: topSpendModels } = (0, import_react7.useMemo)(() => {
2563
2603
  const rows = usage?.daily_by_model ?? [];
2564
2604
  const modelTotals = {};
2565
2605
  for (const r of rows) modelTotals[r.model] = (modelTotals[r.model] ?? 0) + r.spend;
@@ -2574,7 +2614,7 @@ var init_UsageStats = __esm({
2574
2614
  const hasOther = sorted.some((r) => r.Other > 0);
2575
2615
  return { modelSpendByDate: sorted, topModels: hasOther ? [...top, "Other"] : top };
2576
2616
  }, [usage]);
2577
- const modelRows = (0, import_react6.useMemo)(() => {
2617
+ const modelRows = (0, import_react7.useMemo)(() => {
2578
2618
  const entries = Object.entries(usage?.usage_by_model ?? {}).map(([model, d]) => ({
2579
2619
  model,
2580
2620
  spend: d.total_spend,
@@ -2588,11 +2628,11 @@ var init_UsageStats = __esm({
2588
2628
  }));
2589
2629
  return selectedModel === "all" ? entries : entries.filter((e) => e.model === selectedModel);
2590
2630
  }, [usage, selectedModel]);
2591
- const topModelSpendBars = (0, import_react6.useMemo)(
2631
+ const topModelSpendBars = (0, import_react7.useMemo)(
2592
2632
  () => [...modelRows].sort((a, b) => b.spend - a.spend).slice(0, 10),
2593
2633
  [modelRows]
2594
2634
  );
2595
- const keyRows = (0, import_react6.useMemo)(
2635
+ const keyRows = (0, import_react7.useMemo)(
2596
2636
  () => Object.entries(usage?.usage_by_key ?? {}).map(([keyHash, d]) => ({
2597
2637
  keyHash,
2598
2638
  keyAlias: d.key_alias ?? keyHash.slice(0, 8),
@@ -2609,7 +2649,7 @@ var init_UsageStats = __esm({
2609
2649
  })),
2610
2650
  [usage]
2611
2651
  );
2612
- const topKeySpendBars = (0, import_react6.useMemo)(
2652
+ const topKeySpendBars = (0, import_react7.useMemo)(
2613
2653
  () => [...keyRows].sort((a, b) => b.spend - a.spend).slice(0, 10),
2614
2654
  [keyRows]
2615
2655
  );
@@ -2647,23 +2687,23 @@ var init_UsageStats = __esm({
2647
2687
  ];
2648
2688
  const renderKeyRows = () => {
2649
2689
  if (loading) {
2650
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2690
+ return /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { colSpan: 7, sx: { py: 3 } }, /* @__PURE__ */ import_react7.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2651
2691
  }
2652
2692
  if (keyRows.length === 0) {
2653
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 7 }, /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No key activity in this period" })));
2693
+ return /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { colSpan: 7 }, /* @__PURE__ */ import_react7.default.createElement(EmptyState, { message: "No key activity in this period" })));
2654
2694
  }
2655
- return [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, { key: r.keyHash }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.keyAlias), r.teamId ? /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.slice(0, 3).map((m) => /* @__PURE__ */ import_react6.default.createElement(TagChip, { key: m, label: m, title: m })), r.models.length > 3 && /* @__PURE__ */ import_react6.default.createElement(TagChip, { label: `+${r.models.length - 3}`, mono: false }))), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.totalTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2695
+ return [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, { key: r.keyHash }, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.keyAlias), r.teamId ? /* @__PURE__ */ import_react7.default.createElement(import_Typography6.default, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_Box6.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.slice(0, 3).map((m) => /* @__PURE__ */ import_react7.default.createElement(TagChip, { key: m, label: m, title: m })), r.models.length > 3 && /* @__PURE__ */ import_react7.default.createElement(TagChip, { label: `+${r.models.length - 3}`, mono: false }))), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.totalTokens)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react7.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2656
2696
  };
2657
2697
  const renderModelRows = () => {
2658
2698
  if (loading) {
2659
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ import_react6.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2699
+ return /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { colSpan: 8, sx: { py: 3 } }, /* @__PURE__ */ import_react7.default.createElement(import_Skeleton3.default, { variant: "rounded", height: 80 })));
2660
2700
  }
2661
2701
  if (modelRows.length === 0) {
2662
- return /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { colSpan: 8 }, /* @__PURE__ */ import_react6.default.createElement(EmptyState, { message: "No model activity in this period" })));
2702
+ return /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { colSpan: 8 }, /* @__PURE__ */ import_react7.default.createElement(EmptyState, { message: "No model activity in this period" })));
2663
2703
  }
2664
- return [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, { key: r.model }, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react6.default.createElement(import_Box6.default, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: chartColor(r.model), flexShrink: 0 } }), /* @__PURE__ */ import_react6.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.model))), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.promptTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.completionTokens)), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react6.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2704
+ return [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, { key: r.model }, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_Box6.default, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react7.default.createElement(import_Box6.default, { sx: { width: 8, height: 8, borderRadius: "50%", bgcolor: chartColor(r.model), flexShrink: 0 } }), /* @__PURE__ */ import_react7.default.createElement(import_Typography6.default, { variant: "body2", sx: { fontWeight: 600 } }, r.model))), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.promptTokens)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, fmtCompact(r.completionTokens)), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, /* @__PURE__ */ import_react7.default.createElement(SuccessRateCell, { rate: r.successRate, requests: r.apiRequests }))));
2665
2705
  };
2666
- const periodSelect = /* @__PURE__ */ import_react6.default.createElement(
2706
+ const periodSelect = /* @__PURE__ */ import_react7.default.createElement(
2667
2707
  import_TextField4.default,
2668
2708
  {
2669
2709
  select: true,
@@ -2673,17 +2713,17 @@ var init_UsageStats = __esm({
2673
2713
  onChange: (e) => handlePresetChange(e.target.value),
2674
2714
  sx: { minWidth: 160 }
2675
2715
  },
2676
- Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem3.default, { key: p, value: p }, PRESET_LABELS[p]))
2716
+ Object.keys(PRESET_LABELS).map((p) => /* @__PURE__ */ import_react7.default.createElement(import_MenuItem3.default, { key: p, value: p }, PRESET_LABELS[p]))
2677
2717
  );
2678
- return /* @__PURE__ */ import_react6.default.createElement(
2718
+ return /* @__PURE__ */ import_react7.default.createElement(
2679
2719
  SectionCard,
2680
2720
  {
2681
2721
  title: "Usage Analytics",
2682
2722
  subtitle: `${PRESET_LABELS[currentPreset]} \xB7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`,
2683
2723
  actions: periodSelect
2684
2724
  },
2685
- /* @__PURE__ */ import_react6.default.createElement(MetricStrip, { metrics }),
2686
- /* @__PURE__ */ import_react6.default.createElement(
2725
+ /* @__PURE__ */ import_react7.default.createElement(MetricStrip, { metrics }),
2726
+ /* @__PURE__ */ import_react7.default.createElement(
2687
2727
  import_Box6.default,
2688
2728
  {
2689
2729
  sx: {
@@ -2696,7 +2736,7 @@ var init_UsageStats = __esm({
2696
2736
  mb: 2
2697
2737
  }
2698
2738
  },
2699
- /* @__PURE__ */ import_react6.default.createElement(
2739
+ /* @__PURE__ */ import_react7.default.createElement(
2700
2740
  SegmentedControl,
2701
2741
  {
2702
2742
  value: tab,
@@ -2708,7 +2748,7 @@ var init_UsageStats = __esm({
2708
2748
  ]
2709
2749
  }
2710
2750
  ),
2711
- tab === "models" && /* @__PURE__ */ import_react6.default.createElement(
2751
+ tab === "models" && /* @__PURE__ */ import_react7.default.createElement(
2712
2752
  import_TextField4.default,
2713
2753
  {
2714
2754
  select: true,
@@ -2718,17 +2758,17 @@ var init_UsageStats = __esm({
2718
2758
  onChange: (e) => setSelectedModel(e.target.value),
2719
2759
  sx: { minWidth: 220 }
2720
2760
  },
2721
- /* @__PURE__ */ import_react6.default.createElement(import_MenuItem3.default, { value: "all" }, "All models"),
2722
- models.map((m) => /* @__PURE__ */ import_react6.default.createElement(import_MenuItem3.default, { key: m.model_name, value: m.model_name }, m.model_name))
2761
+ /* @__PURE__ */ import_react7.default.createElement(import_MenuItem3.default, { value: "all" }, "All models"),
2762
+ models.map((m) => /* @__PURE__ */ import_react7.default.createElement(import_MenuItem3.default, { key: m.model_name, value: m.model_name }, m.model_name))
2723
2763
  )
2724
2764
  ),
2725
- tab === "costs" && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { container: true, spacing: 2 }, /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Daily spend by model", height: 260 }, /* @__PURE__ */ import_react6.default.createElement(ChartOrFallback, { loading, empty: modelSpendByDate.length === 0, height: 260 }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.AreaChart, { data: modelSpendByDate, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { tickFormatter: fmtUsdCompact, width: 56, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(
2765
+ tab === "costs" && /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { container: true, spacing: 2 }, /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Daily spend by model", height: 260 }, /* @__PURE__ */ import_react7.default.createElement(ChartOrFallback, { loading, empty: modelSpendByDate.length === 0, height: 260 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.AreaChart, { data: modelSpendByDate, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { tickFormatter: fmtUsdCompact, width: 56, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(
2726
2766
  import_recharts.Tooltip,
2727
2767
  {
2728
2768
  cursor: chart.cursor,
2729
- content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, hideZero: true })
2769
+ content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, hideZero: true })
2730
2770
  }
2731
- ), topSpendModels.map((m) => /* @__PURE__ */ import_react6.default.createElement(
2771
+ ), topSpendModels.map((m) => /* @__PURE__ */ import_react7.default.createElement(
2732
2772
  import_recharts.Area,
2733
2773
  {
2734
2774
  key: m,
@@ -2740,13 +2780,13 @@ var init_UsageStats = __esm({
2740
2780
  fill: chartColor(m),
2741
2781
  fillOpacity: 0.28
2742
2782
  }
2743
- ))))), !loading && topSpendModels.length > 0 && /* @__PURE__ */ import_react6.default.createElement(SeriesLegend, { series: topSpendModels.map((m) => ({ name: m, color: chartColor(m) })) }))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Daily token usage" }, /* @__PURE__ */ import_react6.default.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.AreaChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "promptTokens", name: "Input", stackId: "tok", stroke: SERIES.input, strokeWidth: 1.5, fill: SERIES.input, fillOpacity: 0.25 }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "completionTokens", name: "Output", stackId: "tok", stroke: SERIES.output, strokeWidth: 1.5, fill: SERIES.output, fillOpacity: 0.25 })))))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Daily requests" }, /* @__PURE__ */ import_react6.default.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 }, barCategoryGap: "30%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "successfulRequests", name: "Successful", fill: SERIES.success, stackId: "r" }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "failedRequests", name: "Failed", fill: SERIES.failure, stackId: "r", radius: [3, 3, 0, 0] })))))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Daily success rate" }, /* @__PURE__ */ import_react6.default.createElement(ChartOrFallback, { loading, empty: successRateData.length === 0 }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.LineChart, { data: successRateData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { domain: [0, 100], tickFormatter: (v) => `${v}%`, width: 44, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(
2783
+ ))))), !loading && topSpendModels.length > 0 && /* @__PURE__ */ import_react7.default.createElement(SeriesLegend, { series: topSpendModels.map((m) => ({ name: m, color: chartColor(m) })) }))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Daily token usage" }, /* @__PURE__ */ import_react7.default.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.AreaChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "promptTokens", name: "Input", stackId: "tok", stroke: SERIES.input, strokeWidth: 1.5, fill: SERIES.input, fillOpacity: 0.25 }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "completionTokens", name: "Output", stackId: "tok", stroke: SERIES.output, strokeWidth: 1.5, fill: SERIES.output, fillOpacity: 0.25 })))))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Daily requests" }, /* @__PURE__ */ import_react7.default.createElement(ChartOrFallback, { loading, empty: dailyData.length === 0 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.BarChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 }, barCategoryGap: "30%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { tickFormatter: fmtCompact, width: 48, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Bar, { dataKey: "successfulRequests", name: "Successful", fill: SERIES.success, stackId: "r" }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Bar, { dataKey: "failedRequests", name: "Failed", fill: SERIES.failure, stackId: "r", radius: [3, 3, 0, 0] })))))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Daily success rate" }, /* @__PURE__ */ import_react7.default.createElement(ChartOrFallback, { loading, empty: successRateData.length === 0 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.LineChart, { data: successRateData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { domain: [0, 100], tickFormatter: (v) => `${v}%`, width: 44, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(
2744
2784
  import_recharts.Tooltip,
2745
2785
  {
2746
2786
  cursor: chart.cursor,
2747
- content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: (v) => `${v}%` })
2787
+ content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: (v) => `${v}%` })
2748
2788
  }
2749
- ), /* @__PURE__ */ import_react6.default.createElement(import_recharts.ReferenceLine, { y: 100, stroke: SERIES.success, strokeDasharray: "4 4", strokeOpacity: 0.5 }), /* @__PURE__ */ import_react6.default.createElement(
2789
+ ), /* @__PURE__ */ import_react7.default.createElement(import_recharts.ReferenceLine, { y: 100, stroke: SERIES.success, strokeDasharray: "4 4", strokeOpacity: 0.5 }), /* @__PURE__ */ import_react7.default.createElement(
2750
2790
  import_recharts.Line,
2751
2791
  {
2752
2792
  type: "monotone",
@@ -2757,13 +2797,13 @@ var init_UsageStats = __esm({
2757
2797
  dot: { r: 2.5, strokeWidth: 0, fill: SERIES.input },
2758
2798
  activeDot: { r: 4 }
2759
2799
  }
2760
- )))))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react6.default.createElement(
2800
+ )))))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react7.default.createElement(
2761
2801
  ChartCard,
2762
2802
  {
2763
2803
  title: maxBudget > 0 ? "Cumulative spend vs budget" : "Cumulative spend",
2764
2804
  meta: maxBudget > 0 ? `${fmtUsd(totalCumSpend)} used \xB7 ${fmtUsd(Math.max(0, maxBudget - totalCumSpend))} left` : void 0
2765
2805
  },
2766
- /* @__PURE__ */ import_react6.default.createElement(ChartOrFallback, { loading, empty: cumulativeData.length === 0 }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.AreaChart, { data: cumulativeData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(
2806
+ /* @__PURE__ */ import_react7.default.createElement(ChartOrFallback, { loading, empty: cumulativeData.length === 0 }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.AreaChart, { data: cumulativeData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(
2767
2807
  import_recharts.YAxis,
2768
2808
  {
2769
2809
  tickFormatter: fmtUsdCompact,
@@ -2771,13 +2811,13 @@ var init_UsageStats = __esm({
2771
2811
  domain: cumulativeDomain,
2772
2812
  ...chart.axis
2773
2813
  }
2774
- ), /* @__PURE__ */ import_react6.default.createElement(
2814
+ ), /* @__PURE__ */ import_react7.default.createElement(
2775
2815
  import_recharts.Tooltip,
2776
2816
  {
2777
2817
  cursor: chart.cursor,
2778
- content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtUsd })
2818
+ content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtUsd })
2779
2819
  }
2780
- ), maxBudget > 0 && /* @__PURE__ */ import_react6.default.createElement(
2820
+ ), maxBudget > 0 && /* @__PURE__ */ import_react7.default.createElement(
2781
2821
  import_recharts.ReferenceLine,
2782
2822
  {
2783
2823
  y: maxBudget,
@@ -2785,7 +2825,7 @@ var init_UsageStats = __esm({
2785
2825
  strokeDasharray: "5 4",
2786
2826
  label: { value: `Budget ${fmtUsd(maxBudget)}`, position: "insideTopRight", fontSize: 10, fill: SERIES.budget }
2787
2827
  }
2788
- ), /* @__PURE__ */ import_react6.default.createElement(
2828
+ ), /* @__PURE__ */ import_react7.default.createElement(
2789
2829
  import_recharts.Area,
2790
2830
  {
2791
2831
  type: "monotone",
@@ -2798,32 +2838,32 @@ var init_UsageStats = __esm({
2798
2838
  }
2799
2839
  ))))
2800
2840
  ))),
2801
- tab === "models" && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { container: true, spacing: 2 }, /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Spend by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ import_react6.default.createElement(
2841
+ tab === "models" && /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { container: true, spacing: 2 }, /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Spend by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ import_react7.default.createElement(
2802
2842
  ChartOrFallback,
2803
2843
  {
2804
2844
  loading,
2805
2845
  empty: topModelSpendBars.length === 0,
2806
2846
  height: Math.max(200, topModelSpendBars.length * 34)
2807
2847
  },
2808
- /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", radius: [0, 3, 3, 0], barSize: 14 }, topModelSpendBars.map((r) => /* @__PURE__ */ import_react6.default.createElement(import_recharts.Cell, { key: r.model, fill: chartColor(r.model) })))))
2809
- ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Tokens by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ import_react6.default.createElement(
2848
+ /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", radius: [0, 3, 3, 0], barSize: 14 }, topModelSpendBars.map((r) => /* @__PURE__ */ import_react7.default.createElement(import_recharts.Cell, { key: r.model, fill: chartColor(r.model) })))))
2849
+ ))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Tokens by model", height: Math.max(200, topModelSpendBars.length * 34) }, /* @__PURE__ */ import_react7.default.createElement(
2810
2850
  ChartOrFallback,
2811
2851
  {
2812
2852
  loading,
2813
2853
  empty: modelRows.length === 0,
2814
2854
  height: Math.max(200, topModelSpendBars.length * 34)
2815
2855
  },
2816
- /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtCompact, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtInt, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "promptTokens", name: "Input", fill: SERIES.input, stackId: "t", barSize: 14 }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "completionTokens", name: "Output", fill: SERIES.output, stackId: "t", barSize: 14, radius: [0, 3, 3, 0] })))
2817
- ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(import_TableContainer3.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, "Model"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Success"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Input"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Output"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody3.default, null, renderModelRows()))))),
2818
- tab === "keys" && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { container: true, spacing: 2 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(ChartCard, { title: "Spend by key", height: Math.max(160, topKeySpendBars.length * 32) }, /* @__PURE__ */ import_react6.default.createElement(
2856
+ /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtCompact, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", width: 170, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtInt, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Legend, { ...chart.legend }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Bar, { dataKey: "promptTokens", name: "Input", fill: SERIES.input, stackId: "t", barSize: 14 }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Bar, { dataKey: "completionTokens", name: "Output", fill: SERIES.output, stackId: "t", barSize: 14, radius: [0, 3, 3, 0] })))
2857
+ ))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react7.default.createElement(import_TableContainer3.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react7.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react7.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, "Model"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Success"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Input"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Output"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react7.default.createElement(import_TableBody3.default, null, renderModelRows()))))),
2858
+ tab === "keys" && /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { container: true, spacing: 2 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react7.default.createElement(ChartCard, { title: "Spend by key", height: Math.max(160, topKeySpendBars.length * 32) }, /* @__PURE__ */ import_react7.default.createElement(
2819
2859
  ChartOrFallback,
2820
2860
  {
2821
2861
  loading,
2822
2862
  empty: topKeySpendBars.length === 0,
2823
2863
  height: Math.max(160, topKeySpendBars.length * 32)
2824
2864
  },
2825
- /* @__PURE__ */ import_react6.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.BarChart, { data: topKeySpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react6.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "keyAlias", width: 160, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react6.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react6.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", fill: SERIES.input, radius: [0, 3, 3, 0], barSize: 14 })))
2826
- ))), /* @__PURE__ */ import_react6.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react6.default.createElement(import_TableContainer3.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react6.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react6.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, "Key"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, null, "Models"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Tokens"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react6.default.createElement(import_TableCell3.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react6.default.createElement(import_TableBody3.default, null, renderKeyRows())))))
2865
+ /* @__PURE__ */ import_react7.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.BarChart, { data: topKeySpendBars, layout: "vertical", margin: { top: 0, right: 12, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react7.default.createElement(import_recharts.CartesianGrid, { ...chart.grid, vertical: true, horizontal: false }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.XAxis, { type: "number", tickFormatter: fmtUsdCompact, ...chart.axis }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "keyAlias", width: 160, ...chart.axis, tick: { fontSize: 10.5, fill: chart.axis.tick.fill } }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Tooltip, { cursor: chart.cursor, content: /* @__PURE__ */ import_react7.default.createElement(ChartTooltip, { valueFormatter: fmtUsd, labelFormatter: (l) => l }) }), /* @__PURE__ */ import_react7.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", fill: SERIES.input, radius: [0, 3, 3, 0], barSize: 14 })))
2866
+ ))), /* @__PURE__ */ import_react7.default.createElement(import_Grid.default, { item: true, xs: 12 }, /* @__PURE__ */ import_react7.default.createElement(import_TableContainer3.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 2 } }, /* @__PURE__ */ import_react7.default.createElement(import_Table3.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react7.default.createElement(import_TableHead3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableRow3.default, null, /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, "Key"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, null, "Models"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Spend"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Requests"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Tokens"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { align: "right" }, "Failed"), /* @__PURE__ */ import_react7.default.createElement(import_TableCell3.default, { sx: { width: 160 } }, "Success rate"))), /* @__PURE__ */ import_react7.default.createElement(import_TableBody3.default, null, renderKeyRows())))))
2827
2867
  );
2828
2868
  };
2829
2869
  }
@@ -2965,16 +3005,16 @@ function levelToneColor(tone, theme) {
2965
3005
  return theme.palette.primary.main;
2966
3006
  }
2967
3007
  }
2968
- var import_react7, import_Box7, import_Paper5, import_Typography7, import_styles4, import_core_components, LimitCard, TaggedLimit, MoreKeysNote, BudgetLimitList, LimitListPanel;
3008
+ var import_react8, import_Box7, import_Paper5, import_Typography7, import_styles4, import_core_components2, LimitCard, TaggedLimit, MoreKeysNote, BudgetLimitList, LimitListPanel;
2969
3009
  var init_BudgetLimitList = __esm({
2970
3010
  "src/components/BudgetLimitList.tsx"() {
2971
3011
  "use strict";
2972
- import_react7 = __toESM(require("react"));
3012
+ import_react8 = __toESM(require("react"));
2973
3013
  import_Box7 = __toESM(require("@mui/material/Box"));
2974
3014
  import_Paper5 = __toESM(require("@mui/material/Paper"));
2975
3015
  import_Typography7 = __toESM(require("@mui/material/Typography"));
2976
3016
  import_styles4 = require("@mui/material/styles");
2977
- import_core_components = require("@backstage/core-components");
3017
+ import_core_components2 = require("@backstage/core-components");
2978
3018
  init_budget();
2979
3019
  init_format();
2980
3020
  init_ui();
@@ -2982,7 +3022,7 @@ var init_BudgetLimitList = __esm({
2982
3022
  const tone = budgetTone2(limit.pct);
2983
3023
  const pct = Math.round(limit.pct);
2984
3024
  const closeTo = limit.softLimit !== void 0 && limit.spend >= limit.softLimit;
2985
- return /* @__PURE__ */ import_react7.default.createElement(import_Paper5.default, { variant: "outlined", sx: { px: 1.5, py: 1.25, borderRadius: 1.5 } }, /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 1.5 } }, /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ import_react7.default.createElement(
3025
+ return /* @__PURE__ */ import_react8.default.createElement(import_Paper5.default, { variant: "outlined", sx: { px: 1.5, py: 1.25, borderRadius: 1.5 } }, /* @__PURE__ */ import_react8.default.createElement(import_Box7.default, { sx: { display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 1.5 } }, /* @__PURE__ */ import_react8.default.createElement(import_Box7.default, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ import_react8.default.createElement(
2986
3026
  import_Typography7.default,
2987
3027
  {
2988
3028
  variant: "body2",
@@ -2990,7 +3030,7 @@ var init_BudgetLimitList = __esm({
2990
3030
  title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label
2991
3031
  },
2992
3032
  limit.label
2993
- ), limit.sublabel && /* @__PURE__ */ import_react7.default.createElement(
3033
+ ), limit.sublabel && /* @__PURE__ */ import_react8.default.createElement(
2994
3034
  import_Typography7.default,
2995
3035
  {
2996
3036
  variant: "caption",
@@ -3005,7 +3045,7 @@ var init_BudgetLimitList = __esm({
3005
3045
  }
3006
3046
  },
3007
3047
  limit.sublabel
3008
- )), limit.hidden ? /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, pct, "% used") : /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, fmtUsd(limit.spend), /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { component: "span", color: "text.secondary", sx: { fontWeight: 400 } }, " / ", fmtUsd(limit.budget)))), /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { mt: 1 } }, /* @__PURE__ */ import_react7.default.createElement(Meter, { value: limit.pct, tone, height: 6 })), /* @__PURE__ */ import_react7.default.createElement(
3048
+ )), limit.hidden ? /* @__PURE__ */ import_react8.default.createElement(import_Typography7.default, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, pct, "% used") : /* @__PURE__ */ import_react8.default.createElement(import_Typography7.default, { variant: "body2", sx: { fontWeight: 600, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" } }, fmtUsd(limit.spend), /* @__PURE__ */ import_react8.default.createElement(import_Box7.default, { component: "span", color: "text.secondary", sx: { fontWeight: 400 } }, " / ", fmtUsd(limit.budget)))), /* @__PURE__ */ import_react8.default.createElement(import_Box7.default, { sx: { mt: 1 } }, /* @__PURE__ */ import_react8.default.createElement(Meter, { value: limit.pct, tone, height: 6 })), /* @__PURE__ */ import_react8.default.createElement(
3009
3049
  import_Box7.default,
3010
3050
  {
3011
3051
  sx: {
@@ -3016,14 +3056,14 @@ var init_BudgetLimitList = __esm({
3016
3056
  mt: 0.75
3017
3057
  }
3018
3058
  },
3019
- /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, limit.hidden ? /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, "Hidden by admin") : /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, pct, "% of budget", closeTo && ` \xB7 soft-limit warning`)),
3020
- /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, fmtBudgetDuration(limit.budgetDuration) ? `resets ${fmtBudgetDuration(limit.budgetDuration)}` : "never resets")
3059
+ /* @__PURE__ */ import_react8.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, limit.hidden ? /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, "Hidden by admin") : /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, pct, "% of budget", closeTo && ` \xB7 soft-limit warning`)),
3060
+ /* @__PURE__ */ import_react8.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, fmtBudgetDuration(limit.budgetDuration) ? `resets ${fmtBudgetDuration(limit.budgetDuration)}` : "never resets")
3021
3061
  ));
3022
3062
  };
3023
3063
  TaggedLimit = ({ limit }) => {
3024
3064
  const theme = (0, import_styles4.useTheme)();
3025
3065
  const tone = budgetTone2(limit.pct);
3026
- return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, null, /* @__PURE__ */ import_react7.default.createElement(
3066
+ return /* @__PURE__ */ import_react8.default.createElement(import_Box7.default, null, /* @__PURE__ */ import_react8.default.createElement(
3027
3067
  import_Typography7.default,
3028
3068
  {
3029
3069
  sx: {
@@ -3036,7 +3076,7 @@ var init_BudgetLimitList = __esm({
3036
3076
  }
3037
3077
  },
3038
3078
  limit.kind
3039
- ), /* @__PURE__ */ import_react7.default.createElement(LimitCard, { limit }));
3079
+ ), /* @__PURE__ */ import_react8.default.createElement(LimitCard, { limit }));
3040
3080
  };
3041
3081
  MoreKeysNote = ({
3042
3082
  count,
@@ -3045,12 +3085,12 @@ var init_BudgetLimitList = __esm({
3045
3085
  }) => {
3046
3086
  const text = label ?? `+${count} more budgeted key${count > 1 ? "s" : ""} further from the cap`;
3047
3087
  if (!href) {
3048
- return /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, text);
3088
+ return /* @__PURE__ */ import_react8.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, text);
3049
3089
  }
3050
- return /* @__PURE__ */ import_react7.default.createElement(import_core_components.Link, { to: href, variant: "caption" }, text, " \u2192");
3090
+ return /* @__PURE__ */ import_react8.default.createElement(import_core_components2.Link, { to: href, variant: "caption" }, text, " \u2192");
3051
3091
  };
3052
- BudgetLimitList = ({ limits, hiddenKeyCount = 0, keysHref }) => /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, limits.map((limit) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: `${limit.kind}:${limit.sublabel ?? limit.label}`, limit })), hiddenKeyCount > 0 && /* @__PURE__ */ import_react7.default.createElement(MoreKeysNote, { count: hiddenKeyCount, href: keysHref }));
3053
- LimitListPanel = ({ children }) => /* @__PURE__ */ import_react7.default.createElement(
3092
+ BudgetLimitList = ({ limits, hiddenKeyCount = 0, keysHref }) => /* @__PURE__ */ import_react8.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, limits.map((limit) => /* @__PURE__ */ import_react8.default.createElement(TaggedLimit, { key: `${limit.kind}:${limit.sublabel ?? limit.label}`, limit })), hiddenKeyCount > 0 && /* @__PURE__ */ import_react8.default.createElement(MoreKeysNote, { count: hiddenKeyCount, href: keysHref }));
3093
+ LimitListPanel = ({ children }) => /* @__PURE__ */ import_react8.default.createElement(
3054
3094
  import_Box7.default,
3055
3095
  {
3056
3096
  sx: (theme) => ({
@@ -3066,11 +3106,11 @@ var init_BudgetLimitList = __esm({
3066
3106
  });
3067
3107
 
3068
3108
  // src/components/LiteLLMBudgetWidget.tsx
3069
- var import_react8, import_Paper6, import_Box8, import_Typography8, import_CircularProgress4, import_Alert3, import_Collapse, import_IconButton4, import_icons_material5, import_styles5, import_core_plugin_api3, LevelFrame, EmptyLimitCard, CLOSEST_LEVEL_LABEL, KEYS_PATH, HierarchyNote, FullBody, CompactBody, LiteLLMBudgetWidget;
3109
+ var import_react9, import_Paper6, import_Box8, import_Typography8, import_CircularProgress4, import_Alert3, import_Collapse, import_IconButton4, import_icons_material5, import_styles5, import_core_plugin_api3, LevelFrame, EmptyLimitCard, CLOSEST_LEVEL_LABEL, KEYS_PATH, HierarchyNote, FullBody, CompactBody, LiteLLMBudgetWidget;
3070
3110
  var init_LiteLLMBudgetWidget = __esm({
3071
3111
  "src/components/LiteLLMBudgetWidget.tsx"() {
3072
3112
  "use strict";
3073
- import_react8 = __toESM(require("react"));
3113
+ import_react9 = __toESM(require("react"));
3074
3114
  import_Paper6 = __toESM(require("@mui/material/Paper"));
3075
3115
  import_Box8 = __toESM(require("@mui/material/Box"));
3076
3116
  import_Typography8 = __toESM(require("@mui/material/Typography"));
@@ -3093,7 +3133,7 @@ var init_LiteLLMBudgetWidget = __esm({
3093
3133
  tone,
3094
3134
  isLast,
3095
3135
  children
3096
- }) => /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", gap: 1.5 } }, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", flexDirection: "column", alignItems: "center", width: 26, flexShrink: 0 } }, /* @__PURE__ */ import_react8.default.createElement(
3136
+ }) => /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { display: "flex", gap: 1.5 } }, /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { display: "flex", flexDirection: "column", alignItems: "center", width: 26, flexShrink: 0 } }, /* @__PURE__ */ import_react9.default.createElement(
3097
3137
  import_Box8.default,
3098
3138
  {
3099
3139
  sx: (theme) => ({
@@ -3111,7 +3151,7 @@ var init_LiteLLMBudgetWidget = __esm({
3111
3151
  })
3112
3152
  },
3113
3153
  rank
3114
- ), /* @__PURE__ */ import_react8.default.createElement(
3154
+ ), /* @__PURE__ */ import_react9.default.createElement(
3115
3155
  import_Box8.default,
3116
3156
  {
3117
3157
  sx: (theme) => ({
@@ -3121,7 +3161,7 @@ var init_LiteLLMBudgetWidget = __esm({
3121
3161
  bgcolor: isLast ? "transparent" : (0, import_styles5.alpha)(theme.palette.text.primary, 0.12)
3122
3162
  })
3123
3163
  }
3124
- )), /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { flex: 1, minWidth: 0, pb: isLast ? 0 : 2 } }, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", alignItems: "baseline", gap: 1, flexWrap: "wrap", mb: 0.75 } }, /* @__PURE__ */ import_react8.default.createElement(
3164
+ )), /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { flex: 1, minWidth: 0, pb: isLast ? 0 : 2 } }, /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { display: "flex", alignItems: "baseline", gap: 1, flexWrap: "wrap", mb: 0.75 } }, /* @__PURE__ */ import_react9.default.createElement(
3125
3165
  import_Typography8.default,
3126
3166
  {
3127
3167
  sx: (theme) => ({
@@ -3133,8 +3173,8 @@ var init_LiteLLMBudgetWidget = __esm({
3133
3173
  })
3134
3174
  },
3135
3175
  name
3136
- ), /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "caption", color: "text.secondary", sx: { fontSize: 11.5 } }, tagline), note && /* @__PURE__ */ import_react8.default.createElement(StatusPill, { label: note, tone: "neutral", dot: false, sx: { ml: "auto" } })), /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, children)));
3137
- EmptyLimitCard = ({ children }) => /* @__PURE__ */ import_react8.default.createElement(
3176
+ ), /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "caption", color: "text.secondary", sx: { fontSize: 11.5 } }, tagline), note && /* @__PURE__ */ import_react9.default.createElement(StatusPill, { label: note, tone: "neutral", dot: false, sx: { ml: "auto" } })), /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { display: "flex", flexDirection: "column", gap: 1 } }, children)));
3177
+ EmptyLimitCard = ({ children }) => /* @__PURE__ */ import_react9.default.createElement(
3138
3178
  import_Paper6.default,
3139
3179
  {
3140
3180
  variant: "outlined",
@@ -3145,7 +3185,7 @@ var init_LiteLLMBudgetWidget = __esm({
3145
3185
  bgcolor: (0, import_styles5.alpha)(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.03 : 0.015)
3146
3186
  })
3147
3187
  },
3148
- /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, children)
3188
+ /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, children)
3149
3189
  );
3150
3190
  CLOSEST_LEVEL_LABEL = {
3151
3191
  key: "key",
@@ -3153,7 +3193,7 @@ var init_LiteLLMBudgetWidget = __esm({
3153
3193
  team: "team"
3154
3194
  };
3155
3195
  KEYS_PATH = "/litellm?tab=keys";
3156
- HierarchyNote = ({ withReset }) => /* @__PURE__ */ import_react8.default.createElement(
3196
+ HierarchyNote = ({ withReset }) => /* @__PURE__ */ import_react9.default.createElement(
3157
3197
  import_Box8.default,
3158
3198
  {
3159
3199
  sx: (theme) => ({
@@ -3164,11 +3204,11 @@ var init_LiteLLMBudgetWidget = __esm({
3164
3204
  borderColor: (0, import_styles5.alpha)(theme.palette.text.primary, 0.18)
3165
3205
  })
3166
3206
  },
3167
- /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "caption", color: "text.secondary", display: "block" }, /* @__PURE__ */ import_react8.default.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.")
3207
+ /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "caption", color: "text.secondary", display: "block" }, /* @__PURE__ */ import_react9.default.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.")
3168
3208
  );
3169
3209
  FullBody = ({ summary }) => {
3170
3210
  const hasBudgetedKeys = summary.keys.length + summary.hiddenBudgetedKeys > 0;
3171
- return /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, /* @__PURE__ */ import_react8.default.createElement(
3211
+ return /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(
3172
3212
  LevelFrame,
3173
3213
  {
3174
3214
  rank: 1,
@@ -3176,10 +3216,10 @@ var init_LiteLLMBudgetWidget = __esm({
3176
3216
  tagline: "per-key cap \xB7 highest priority",
3177
3217
  note: hasBudgetedKeys ? void 0 : "no key budgets set"
3178
3218
  },
3179
- !hasBudgetedKeys && /* @__PURE__ */ import_react8.default.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3180
- summary.keys.map((k) => /* @__PURE__ */ import_react8.default.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3181
- summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react8.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH })
3182
- ), /* @__PURE__ */ import_react8.default.createElement(
3219
+ !hasBudgetedKeys && /* @__PURE__ */ import_react9.default.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3220
+ summary.keys.map((k) => /* @__PURE__ */ import_react9.default.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3221
+ summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react9.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH })
3222
+ ), /* @__PURE__ */ import_react9.default.createElement(
3183
3223
  LevelFrame,
3184
3224
  {
3185
3225
  rank: 2,
@@ -3187,15 +3227,15 @@ var init_LiteLLMBudgetWidget = __esm({
3187
3227
  tagline: "cap on everything you spend with your own keys",
3188
3228
  note: "skipped for team-bound keys"
3189
3229
  },
3190
- summary.user ? /* @__PURE__ */ import_react8.default.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ import_react8.default.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3191
- ), /* @__PURE__ */ import_react8.default.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__ */ import_react8.default.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ import_react8.default.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ import_react8.default.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ import_react8.default.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__ */ import_react8.default.createElement(import_Box8.default, { sx: { mt: 2 } }, /* @__PURE__ */ import_react8.default.createElement(HierarchyNote, { withReset: true })));
3230
+ summary.user ? /* @__PURE__ */ import_react9.default.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ import_react9.default.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3231
+ ), /* @__PURE__ */ import_react9.default.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__ */ import_react9.default.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ import_react9.default.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ import_react9.default.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ import_react9.default.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__ */ import_react9.default.createElement(import_Box8.default, { sx: { mt: 2 } }, /* @__PURE__ */ import_react9.default.createElement(HierarchyNote, { withReset: true })));
3192
3232
  };
3193
3233
  CompactBody = ({ summary }) => {
3194
3234
  const { count } = budgetHeadline(summary);
3195
3235
  if (count === 0) {
3196
- return /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3236
+ return /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3197
3237
  }
3198
- return /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, /* @__PURE__ */ import_react8.default.createElement(HierarchyNote, null), summary.keys.map((k) => /* @__PURE__ */ import_react8.default.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react8.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH }), summary.user && /* @__PURE__ */ import_react8.default.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ import_react8.default.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3238
+ return /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, /* @__PURE__ */ import_react9.default.createElement(HierarchyNote, null), summary.keys.map((k) => /* @__PURE__ */ import_react9.default.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react9.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys, href: KEYS_PATH }), summary.user && /* @__PURE__ */ import_react9.default.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ import_react9.default.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3199
3239
  };
3200
3240
  LiteLLMBudgetWidget = ({
3201
3241
  title = "Budget Policy",
@@ -3206,13 +3246,13 @@ var init_LiteLLMBudgetWidget = __esm({
3206
3246
  action
3207
3247
  }) => {
3208
3248
  const api = (0, import_core_plugin_api3.useApi)(liteLlmApiRef);
3209
- const [loading, setLoading] = (0, import_react8.useState)(true);
3210
- const [error, setError] = (0, import_react8.useState)(null);
3211
- const [user, setUser] = (0, import_react8.useState)(null);
3212
- const [teams, setTeams] = (0, import_react8.useState)([]);
3213
- const [keys, setKeys] = (0, import_react8.useState)([]);
3214
- const [expanded, setExpanded] = (0, import_react8.useState)(defaultExpanded);
3215
- (0, import_react8.useEffect)(() => {
3249
+ const [loading, setLoading] = (0, import_react9.useState)(true);
3250
+ const [error, setError] = (0, import_react9.useState)(null);
3251
+ const [user, setUser] = (0, import_react9.useState)(null);
3252
+ const [teams, setTeams] = (0, import_react9.useState)([]);
3253
+ const [keys, setKeys] = (0, import_react9.useState)([]);
3254
+ const [expanded, setExpanded] = (0, import_react9.useState)(defaultExpanded);
3255
+ (0, import_react9.useEffect)(() => {
3216
3256
  let cancelled = false;
3217
3257
  setLoading(true);
3218
3258
  setError(null);
@@ -3236,18 +3276,18 @@ var init_LiteLLMBudgetWidget = __esm({
3236
3276
  cancelled = true;
3237
3277
  };
3238
3278
  }, [api]);
3239
- const summary = (0, import_react8.useMemo)(
3279
+ const summary = (0, import_react9.useMemo)(
3240
3280
  () => buildBudgetSummary(user, teams, keys, maxKeys),
3241
3281
  [user, teams, keys, maxKeys]
3242
3282
  );
3243
- const headline = (0, import_react8.useMemo)(() => budgetHeadline(summary), [summary]);
3283
+ const headline = (0, import_react9.useMemo)(() => budgetHeadline(summary), [summary]);
3244
3284
  const limitsWord = `${headline.count} limit${headline.count === 1 ? "" : "s"}`;
3245
3285
  const closestWord = headline.closest === null ? "" : ` \xB7 closest: ${CLOSEST_LEVEL_LABEL[headline.closest.kind]} ${Math.round(
3246
3286
  headline.closest.pct
3247
3287
  )}%`;
3248
3288
  const summaryText = headline.count === 0 ? "no limits apply" : `${limitsWord}${closestWord}`;
3249
- const body = /* @__PURE__ */ import_react8.default.createElement(import_react8.default.Fragment, null, loading && /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 140 }, /* @__PURE__ */ import_react8.default.createElement(import_CircularProgress4.default, { size: 32 })), !loading && error && /* @__PURE__ */ import_react8.default.createElement(import_Alert3.default, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && (compact ? /* @__PURE__ */ import_react8.default.createElement(CompactBody, { summary }) : /* @__PURE__ */ import_react8.default.createElement(FullBody, { summary })));
3250
- return /* @__PURE__ */ import_react8.default.createElement(import_Paper6.default, { sx: { p: 2 } }, collapsible ? /* @__PURE__ */ import_react8.default.createElement(
3289
+ const body = /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, loading && /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 140 }, /* @__PURE__ */ import_react9.default.createElement(import_CircularProgress4.default, { size: 32 })), !loading && error && /* @__PURE__ */ import_react9.default.createElement(import_Alert3.default, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && (compact ? /* @__PURE__ */ import_react9.default.createElement(CompactBody, { summary }) : /* @__PURE__ */ import_react9.default.createElement(FullBody, { summary })));
3290
+ return /* @__PURE__ */ import_react9.default.createElement(import_Paper6.default, { sx: { p: 2 } }, collapsible ? /* @__PURE__ */ import_react9.default.createElement(
3251
3291
  import_Box8.default,
3252
3292
  {
3253
3293
  onClick: () => setExpanded((e) => !e),
@@ -3260,14 +3300,14 @@ var init_LiteLLMBudgetWidget = __esm({
3260
3300
  mb: expanded ? 1.5 : 0
3261
3301
  }
3262
3302
  },
3263
- /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "h6", lineHeight: 1.2 }, title), !loading && !error && /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { mt: 0.5 } }, /* @__PURE__ */ import_react8.default.createElement(
3303
+ /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { minWidth: 0, flex: 1 } }, /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "h6", lineHeight: 1.2 }, title), !loading && !error && /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { mt: 0.5 } }, /* @__PURE__ */ import_react9.default.createElement(
3264
3304
  StatusPill,
3265
3305
  {
3266
3306
  label: summaryText,
3267
3307
  tone: budgetTone2(headline.closest?.pct ?? 0)
3268
3308
  }
3269
3309
  ))),
3270
- /* @__PURE__ */ import_react8.default.createElement(
3310
+ /* @__PURE__ */ import_react9.default.createElement(
3271
3311
  import_IconButton4.default,
3272
3312
  {
3273
3313
  size: "small",
@@ -3283,9 +3323,9 @@ var init_LiteLLMBudgetWidget = __esm({
3283
3323
  transition: theme.transitions.create("transform")
3284
3324
  })
3285
3325
  },
3286
- /* @__PURE__ */ import_react8.default.createElement(import_icons_material5.ExpandMore, null)
3326
+ /* @__PURE__ */ import_react9.default.createElement(import_icons_material5.ExpandMore, null)
3287
3327
  )
3288
- ) : /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { mb: 1.5 } }, /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "h6", lineHeight: 1.2 }, title), /* @__PURE__ */ import_react8.default.createElement(import_Typography8.default, { variant: "caption", color: "text.secondary" }, "How LiteLLM caps spend \u2014 and where you stand right now")), collapsible ? /* @__PURE__ */ import_react8.default.createElement(import_Collapse.default, { in: expanded, unmountOnExit: true }, body) : body, action && /* @__PURE__ */ import_react8.default.createElement(
3328
+ ) : /* @__PURE__ */ import_react9.default.createElement(import_Box8.default, { sx: { mb: 1.5 } }, /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "h6", lineHeight: 1.2 }, title), /* @__PURE__ */ import_react9.default.createElement(import_Typography8.default, { variant: "caption", color: "text.secondary" }, "How LiteLLM caps spend \u2014 and where you stand right now")), collapsible ? /* @__PURE__ */ import_react9.default.createElement(import_Collapse.default, { in: expanded, unmountOnExit: true }, body) : body, action && /* @__PURE__ */ import_react9.default.createElement(
3289
3329
  import_Box8.default,
3290
3330
  {
3291
3331
  sx: (theme) => ({
@@ -3315,11 +3355,11 @@ function budgetStatValue(hidden, budget) {
3315
3355
  if (budget > 0) return fmtUsd2(budget);
3316
3356
  return "Unlimited";
3317
3357
  }
3318
- var import_react9, import_Paper7, import_Box9, import_Typography9, import_Skeleton4, import_Divider3, import_Table4, import_TableBody4, import_TableCell4, import_TableHead4, import_TableRow4, import_TableContainer4, import_Collapse2, import_IconButton5, import_Button5, import_CircularProgress5, import_styles6, import_icons_material6, import_recharts2, fmtUsd2, TeamCard, TeamUsage;
3358
+ var import_react10, import_Paper7, import_Box9, import_Typography9, import_Skeleton4, import_Divider3, import_Table4, import_TableBody4, import_TableCell4, import_TableHead4, import_TableRow4, import_TableContainer4, import_Collapse2, import_IconButton5, import_Button5, import_CircularProgress5, import_styles6, import_icons_material6, import_recharts2, fmtUsd2, TeamCard, TeamUsage;
3319
3359
  var init_TeamUsage = __esm({
3320
3360
  "src/components/TeamUsage.tsx"() {
3321
3361
  "use strict";
3322
- import_react9 = __toESM(require("react"));
3362
+ import_react10 = __toESM(require("react"));
3323
3363
  import_Paper7 = __toESM(require("@mui/material/Paper"));
3324
3364
  import_Box9 = __toESM(require("@mui/material/Box"));
3325
3365
  import_Typography9 = __toESM(require("@mui/material/Typography"));
@@ -3341,7 +3381,7 @@ var init_TeamUsage = __esm({
3341
3381
  init_ui();
3342
3382
  fmtUsd2 = (n) => `$${(n ?? 0).toFixed(2)}`;
3343
3383
  TeamCard = ({ team, usage, usageLoading, canManage, onEditTeam }) => {
3344
- const [expanded, setExpanded] = (0, import_react9.useState)(false);
3384
+ const [expanded, setExpanded] = (0, import_react10.useState)(false);
3345
3385
  const chart = useChartTheme();
3346
3386
  const hidden = team.budget_hidden === true;
3347
3387
  const budget = hidden ? 0 : team.max_budget ?? 0;
@@ -3353,10 +3393,10 @@ var init_TeamUsage = __esm({
3353
3393
  const renderDailySpendSection = () => {
3354
3394
  if (hidden) return null;
3355
3395
  if (usageLoading) {
3356
- return /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ import_react9.default.createElement(import_CircularProgress5.default, { size: 22 }));
3396
+ return /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { display: "flex", justifyContent: "center", py: 3 }, /* @__PURE__ */ import_react10.default.createElement(import_CircularProgress5.default, { size: 22 }));
3357
3397
  }
3358
3398
  if (dailyData.length === 0) return null;
3359
- return /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { mb: 2.5 }, /* @__PURE__ */ import_react9.default.createElement(
3399
+ return /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { mb: 2.5 }, /* @__PURE__ */ import_react10.default.createElement(
3360
3400
  import_Typography9.default,
3361
3401
  {
3362
3402
  variant: "caption",
@@ -3364,13 +3404,13 @@ var init_TeamUsage = __esm({
3364
3404
  sx: { display: "block", fontSize: 11, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase", mb: 1 }
3365
3405
  },
3366
3406
  "Daily spend"
3367
- ), /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { height: 150 }, /* @__PURE__ */ import_react9.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react9.default.createElement(import_recharts2.AreaChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react9.default.createElement(import_recharts2.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react9.default.createElement(import_recharts2.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react9.default.createElement(import_recharts2.YAxis, { tickFormatter: fmtUsdCompact, width: 52, ...chart.axis }), /* @__PURE__ */ import_react9.default.createElement(
3407
+ ), /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { height: 150 }, /* @__PURE__ */ import_react10.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react10.default.createElement(import_recharts2.AreaChart, { data: dailyData, margin: { top: 4, right: 8, left: 0, bottom: 0 } }, /* @__PURE__ */ import_react10.default.createElement(import_recharts2.CartesianGrid, { ...chart.grid }), /* @__PURE__ */ import_react10.default.createElement(import_recharts2.XAxis, { dataKey: "date", tickFormatter: fmtDateShort, ...chart.axis }), /* @__PURE__ */ import_react10.default.createElement(import_recharts2.YAxis, { tickFormatter: fmtUsdCompact, width: 52, ...chart.axis }), /* @__PURE__ */ import_react10.default.createElement(
3368
3408
  import_recharts2.Tooltip,
3369
3409
  {
3370
3410
  cursor: chart.cursor,
3371
- content: /* @__PURE__ */ import_react9.default.createElement(ChartTooltip, { valueFormatter: (v) => `$${v.toFixed(4)}` })
3411
+ content: /* @__PURE__ */ import_react10.default.createElement(ChartTooltip, { valueFormatter: (v) => `$${v.toFixed(4)}` })
3372
3412
  }
3373
- ), /* @__PURE__ */ import_react9.default.createElement(
3413
+ ), /* @__PURE__ */ import_react10.default.createElement(
3374
3414
  import_recharts2.Area,
3375
3415
  {
3376
3416
  type: "monotone",
@@ -3383,7 +3423,7 @@ var init_TeamUsage = __esm({
3383
3423
  }
3384
3424
  )))));
3385
3425
  };
3386
- const sectionLabel = (label) => /* @__PURE__ */ import_react9.default.createElement(
3426
+ const sectionLabel = (label) => /* @__PURE__ */ import_react10.default.createElement(
3387
3427
  import_Typography9.default,
3388
3428
  {
3389
3429
  variant: "caption",
@@ -3392,7 +3432,7 @@ var init_TeamUsage = __esm({
3392
3432
  },
3393
3433
  label
3394
3434
  );
3395
- return /* @__PURE__ */ import_react9.default.createElement(import_Paper7.default, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 } }, /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { display: "flex", alignItems: "center", gap: 1.5 }, /* @__PURE__ */ import_react9.default.createElement(
3435
+ return /* @__PURE__ */ import_react10.default.createElement(import_Paper7.default, { variant: "outlined", sx: { borderRadius: 2, p: 2.5 } }, /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { display: "flex", alignItems: "center", gap: 1.5 }, /* @__PURE__ */ import_react10.default.createElement(
3396
3436
  import_Box9.default,
3397
3437
  {
3398
3438
  sx: (theme) => ({
@@ -3407,8 +3447,8 @@ var init_TeamUsage = __esm({
3407
3447
  color: theme.palette.primary.main
3408
3448
  })
3409
3449
  },
3410
- /* @__PURE__ */ import_react9.default.createElement(import_icons_material6.Group, { fontSize: "small" })
3411
- ), /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { flexGrow: 1, minWidth: 0 }, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.3 } }, team.team_alias || "Untitled team"), /* @__PURE__ */ import_react9.default.createElement(
3450
+ /* @__PURE__ */ import_react10.default.createElement(import_icons_material6.Group, { fontSize: "small" })
3451
+ ), /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { flexGrow: 1, minWidth: 0 }, /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "subtitle1", sx: { fontWeight: 600, lineHeight: 1.3 } }, team.team_alias || "Untitled team"), /* @__PURE__ */ import_react10.default.createElement(
3412
3452
  import_Typography9.default,
3413
3453
  {
3414
3454
  variant: "caption",
@@ -3416,7 +3456,7 @@ var init_TeamUsage = __esm({
3416
3456
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
3417
3457
  },
3418
3458
  team.team_id
3419
- )), isOver && /* @__PURE__ */ import_react9.default.createElement(StatusPill, { label: "Over budget", tone: "danger" }), isNear && /* @__PURE__ */ import_react9.default.createElement(StatusPill, { label: "Near limit", tone: "warning" }), canManage && onEditTeam && /* @__PURE__ */ import_react9.default.createElement(
3459
+ )), isOver && /* @__PURE__ */ import_react10.default.createElement(StatusPill, { label: "Over budget", tone: "danger" }), isNear && /* @__PURE__ */ import_react10.default.createElement(StatusPill, { label: "Near limit", tone: "warning" }), canManage && onEditTeam && /* @__PURE__ */ import_react10.default.createElement(
3420
3460
  import_Button5.default,
3421
3461
  {
3422
3462
  size: "small",
@@ -3425,7 +3465,7 @@ var init_TeamUsage = __esm({
3425
3465
  sx: { textTransform: "none" }
3426
3466
  },
3427
3467
  "Edit"
3428
- ), /* @__PURE__ */ import_react9.default.createElement(
3468
+ ), /* @__PURE__ */ import_react10.default.createElement(
3429
3469
  import_IconButton5.default,
3430
3470
  {
3431
3471
  size: "small",
@@ -3438,8 +3478,8 @@ var init_TeamUsage = __esm({
3438
3478
  transition: theme.transitions.create("transform")
3439
3479
  })
3440
3480
  },
3441
- /* @__PURE__ */ import_react9.default.createElement(import_icons_material6.ExpandMore, null)
3442
- )), /* @__PURE__ */ import_react9.default.createElement(
3481
+ /* @__PURE__ */ import_react10.default.createElement(import_icons_material6.ExpandMore, null)
3482
+ )), /* @__PURE__ */ import_react10.default.createElement(
3443
3483
  import_Box9.default,
3444
3484
  {
3445
3485
  sx: {
@@ -3450,20 +3490,20 @@ var init_TeamUsage = __esm({
3450
3490
  maxWidth: 640
3451
3491
  }
3452
3492
  },
3453
- /* @__PURE__ */ import_react9.default.createElement(Stat, { label: "Members", value: team.members_with_roles?.length ?? "\u2014" }),
3454
- /* @__PURE__ */ import_react9.default.createElement(Stat, { label: "Models", value: team.models?.length ? team.models.length : "All" }),
3455
- /* @__PURE__ */ import_react9.default.createElement(Stat, { label: "Budget", value: budgetStatValue(hidden, budget) }),
3456
- /* @__PURE__ */ import_react9.default.createElement(Stat, { label: "Spend", value: hidden ? "\u2014" : fmtUsd2(spend) }),
3457
- /* @__PURE__ */ import_react9.default.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
3458
- /* @__PURE__ */ import_react9.default.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
3459
- ), hidden && /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "% used"), /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary" }, "Hidden by admin")), /* @__PURE__ */ import_react9.default.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 }), /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { 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__ */ import_react9.default.createElement(import_Box9.default, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ import_react9.default.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 })), /* @__PURE__ */ import_react9.default.createElement(import_Collapse2.default, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ import_react9.default.createElement(import_Divider3.default, { sx: { my: 2.5 } }), /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ import_react9.default.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ import_react9.default.createElement(
3493
+ /* @__PURE__ */ import_react10.default.createElement(Stat, { label: "Members", value: team.members_with_roles?.length ?? "\u2014" }),
3494
+ /* @__PURE__ */ import_react10.default.createElement(Stat, { label: "Models", value: team.models?.length ? team.models.length : "All" }),
3495
+ /* @__PURE__ */ import_react10.default.createElement(Stat, { label: "Budget", value: budgetStatValue(hidden, budget) }),
3496
+ /* @__PURE__ */ import_react10.default.createElement(Stat, { label: "Spend", value: hidden ? "\u2014" : fmtUsd2(spend) }),
3497
+ /* @__PURE__ */ import_react10.default.createElement(Stat, { label: "TPM", value: team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : "\u2014" }),
3498
+ /* @__PURE__ */ import_react10.default.createElement(Stat, { label: "RPM", value: team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : "\u2014" })
3499
+ ), hidden && /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "% used"), /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary" }, "Hidden by admin")), /* @__PURE__ */ import_react10.default.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 }), /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { 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__ */ import_react10.default.createElement(import_Box9.default, { mt: 2, maxWidth: 640 }, /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { display: "flex", justifyContent: "space-between", alignItems: "baseline", mb: 0.75 }, /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, fmtUsd2(spend), " of ", fmtUsd2(budget)), /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "caption", color: "text.secondary", sx: { fontVariantNumeric: "tabular-nums" } }, budgetPct.toFixed(0), "%")), /* @__PURE__ */ import_react10.default.createElement(Meter, { value: budgetPct, tone: budgetTone3(isOver, isNear), height: 5 })), /* @__PURE__ */ import_react10.default.createElement(import_Collapse2.default, { in: expanded, unmountOnExit: true }, /* @__PURE__ */ import_react10.default.createElement(import_Divider3.default, { sx: { my: 2.5 } }), /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { mb: 2.5 }, sectionLabel("Models"), team.models?.length ? /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { display: "flex", gap: 0.5, flexWrap: "wrap" }, team.models.map((m) => /* @__PURE__ */ import_react10.default.createElement(TagChip, { key: m, label: m, title: m }))) : /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, "All models allowed")), renderDailySpendSection(), /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, null, sectionLabel("Members"), team.members_with_roles?.length ? /* @__PURE__ */ import_react10.default.createElement(
3460
3500
  import_TableContainer4.default,
3461
3501
  {
3462
3502
  component: import_Paper7.default,
3463
3503
  variant: "outlined",
3464
3504
  sx: { borderRadius: 1.5 }
3465
3505
  },
3466
- /* @__PURE__ */ import_react9.default.createElement(import_Table4.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react9.default.createElement(import_TableHead4.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableRow4.default, null, /* @__PURE__ */ import_react9.default.createElement(import_TableCell4.default, null, "User"), /* @__PURE__ */ import_react9.default.createElement(import_TableCell4.default, { align: "right" }, "Role"))), /* @__PURE__ */ import_react9.default.createElement(import_TableBody4.default, null, team.members_with_roles.map((m) => /* @__PURE__ */ import_react9.default.createElement(import_TableRow4.default, { key: m.user_id }, /* @__PURE__ */ import_react9.default.createElement(import_TableCell4.default, null, m.user_email ? /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react9.default.createElement(
3506
+ /* @__PURE__ */ import_react10.default.createElement(import_Table4.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react10.default.createElement(import_TableHead4.default, null, /* @__PURE__ */ import_react10.default.createElement(import_TableRow4.default, null, /* @__PURE__ */ import_react10.default.createElement(import_TableCell4.default, null, "User"), /* @__PURE__ */ import_react10.default.createElement(import_TableCell4.default, { align: "right" }, "Role"))), /* @__PURE__ */ import_react10.default.createElement(import_TableBody4.default, null, team.members_with_roles.map((m) => /* @__PURE__ */ import_react10.default.createElement(import_TableRow4.default, { key: m.user_id }, /* @__PURE__ */ import_react10.default.createElement(import_TableCell4.default, null, m.user_email ? /* @__PURE__ */ import_react10.default.createElement(import_react10.default.Fragment, null, /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "body2" }, m.user_email), /* @__PURE__ */ import_react10.default.createElement(
3467
3507
  import_Typography9.default,
3468
3508
  {
3469
3509
  variant: "caption",
@@ -3471,14 +3511,14 @@ var init_TeamUsage = __esm({
3471
3511
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 }
3472
3512
  },
3473
3513
  m.user_id
3474
- )) : /* @__PURE__ */ import_react9.default.createElement(
3514
+ )) : /* @__PURE__ */ import_react10.default.createElement(
3475
3515
  import_Typography9.default,
3476
3516
  {
3477
3517
  variant: "body2",
3478
3518
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }
3479
3519
  },
3480
3520
  m.user_id
3481
- )), /* @__PURE__ */ import_react9.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react9.default.createElement(
3521
+ )), /* @__PURE__ */ import_react10.default.createElement(import_TableCell4.default, { align: "right" }, /* @__PURE__ */ import_react10.default.createElement(
3482
3522
  StatusPill,
3483
3523
  {
3484
3524
  label: m.role,
@@ -3486,7 +3526,7 @@ var init_TeamUsage = __esm({
3486
3526
  dot: false
3487
3527
  }
3488
3528
  ))))))
3489
- ) : /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, "No members assigned."))));
3529
+ ) : /* @__PURE__ */ import_react10.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, "No members assigned."))));
3490
3530
  };
3491
3531
  TeamUsage = ({
3492
3532
  teams,
@@ -3498,22 +3538,22 @@ var init_TeamUsage = __esm({
3498
3538
  canCreate,
3499
3539
  onCreateTeam
3500
3540
  }) => {
3501
- const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ import_react9.default.createElement(
3541
+ const createAction = canCreate && onCreateTeam ? /* @__PURE__ */ import_react10.default.createElement(
3502
3542
  import_Button5.default,
3503
3543
  {
3504
3544
  variant: "contained",
3505
3545
  color: "primary",
3506
3546
  disableElevation: true,
3507
- startIcon: /* @__PURE__ */ import_react9.default.createElement(import_icons_material6.Add, null),
3547
+ startIcon: /* @__PURE__ */ import_react10.default.createElement(import_icons_material6.Add, null),
3508
3548
  onClick: onCreateTeam
3509
3549
  },
3510
3550
  "Create Team"
3511
3551
  ) : void 0;
3512
3552
  if (loading) {
3513
- return /* @__PURE__ */ import_react9.default.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ import_react9.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120, sx: { mb: 2 } }), /* @__PURE__ */ import_react9.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120 }));
3553
+ return /* @__PURE__ */ import_react10.default.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ import_react10.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120, sx: { mb: 2 } }), /* @__PURE__ */ import_react10.default.createElement(import_Skeleton4.default, { variant: "rounded", height: 120 }));
3514
3554
  }
3515
3555
  if (!teams.length) {
3516
- return /* @__PURE__ */ import_react9.default.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ import_react9.default.createElement(
3556
+ return /* @__PURE__ */ import_react10.default.createElement(SectionCard, { title: "Teams", actions: createAction }, /* @__PURE__ */ import_react10.default.createElement(
3517
3557
  EmptyState,
3518
3558
  {
3519
3559
  message: "You're not a member of any LiteLLM team yet.",
@@ -3521,14 +3561,14 @@ var init_TeamUsage = __esm({
3521
3561
  }
3522
3562
  ));
3523
3563
  }
3524
- return /* @__PURE__ */ import_react9.default.createElement(
3564
+ return /* @__PURE__ */ import_react10.default.createElement(
3525
3565
  SectionCard,
3526
3566
  {
3527
3567
  title: "Teams",
3528
3568
  subtitle: `${teams.length} team${teams.length === 1 ? "" : "s"}`,
3529
3569
  actions: createAction
3530
3570
  },
3531
- /* @__PURE__ */ import_react9.default.createElement(import_Box9.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ import_react9.default.createElement(
3571
+ /* @__PURE__ */ import_react10.default.createElement(import_Box9.default, { sx: { display: "flex", flexDirection: "column", gap: 2 } }, teams.map((team) => /* @__PURE__ */ import_react10.default.createElement(
3532
3572
  TeamCard,
3533
3573
  {
3534
3574
  key: team.team_id,
@@ -3562,11 +3602,11 @@ function fmtTokens(n) {
3562
3602
  if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
3563
3603
  return String(n);
3564
3604
  }
3565
- var import_react10, import_Box10, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TableSortLabel2, import_Typography10, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_TextField5, import_InputAdornment2, import_icons_material7, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert4, import_styles7, ALL_PROXY_MODELS2, ModelsTable;
3605
+ var import_react11, import_Box10, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_TableSortLabel2, import_Typography10, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_TextField5, import_InputAdornment2, import_icons_material7, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert4, import_styles7, ALL_PROXY_MODELS2, ModelsTable;
3566
3606
  var init_ModelsTable = __esm({
3567
3607
  "src/components/ModelsTable.tsx"() {
3568
3608
  "use strict";
3569
- import_react10 = __toESM(require("react"));
3609
+ import_react11 = __toESM(require("react"));
3570
3610
  import_Box10 = __toESM(require("@mui/material/Box"));
3571
3611
  import_Table5 = __toESM(require("@mui/material/Table"));
3572
3612
  import_TableBody5 = __toESM(require("@mui/material/TableBody"));
@@ -3592,20 +3632,20 @@ var init_ModelsTable = __esm({
3592
3632
  ALL_PROXY_MODELS2 = "all-proxy-models";
3593
3633
  ModelsTable = ({ allModels, teams, loading }) => {
3594
3634
  const theme = (0, import_styles7.useTheme)();
3595
- const [selectedTeamId, setSelectedTeamId] = (0, import_react10.useState)("");
3596
- const [filterText, setFilterText] = (0, import_react10.useState)("");
3597
- const [copiedSnackbar, setCopiedSnackbar] = (0, import_react10.useState)(false);
3598
- const [sortKey, setSortKey] = (0, import_react10.useState)("model_name");
3599
- const [sortDirection, setSortDirection] = (0, import_react10.useState)("asc");
3600
- const selectedTeam = (0, import_react10.useMemo)(
3635
+ const [selectedTeamId, setSelectedTeamId] = (0, import_react11.useState)("");
3636
+ const [filterText, setFilterText] = (0, import_react11.useState)("");
3637
+ const [copiedSnackbar, setCopiedSnackbar] = (0, import_react11.useState)(false);
3638
+ const [sortKey, setSortKey] = (0, import_react11.useState)("model_name");
3639
+ const [sortDirection, setSortDirection] = (0, import_react11.useState)("asc");
3640
+ const selectedTeam = (0, import_react11.useMemo)(
3601
3641
  () => teams.find((t) => t.team_id === selectedTeamId) ?? null,
3602
3642
  [teams, selectedTeamId]
3603
3643
  );
3604
- const teamModels = (0, import_react10.useMemo)(() => {
3644
+ const teamModels = (0, import_react11.useMemo)(() => {
3605
3645
  if (!selectedTeam) return [];
3606
3646
  return allModels.filter((model) => isModelAllowedByTeam2(model, selectedTeam.models));
3607
3647
  }, [allModels, selectedTeam]);
3608
- const filteredModels = (0, import_react10.useMemo)(() => {
3648
+ const filteredModels = (0, import_react11.useMemo)(() => {
3609
3649
  const q = filterText.trim().toLowerCase();
3610
3650
  let models = teamModels;
3611
3651
  if (q) {
@@ -3652,10 +3692,10 @@ var init_ModelsTable = __esm({
3652
3692
  return sortDirection === "asc" ? aVal - bVal : bVal - aVal;
3653
3693
  });
3654
3694
  }, [teamModels, filterText, sortKey, sortDirection]);
3655
- const handleCopyModelId = (0, import_react10.useCallback)((modelId) => {
3695
+ const handleCopyModelId = (0, import_react11.useCallback)((modelId) => {
3656
3696
  navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));
3657
3697
  }, []);
3658
- const handleSort = (0, import_react10.useCallback)((key) => {
3698
+ const handleSort = (0, import_react11.useCallback)((key) => {
3659
3699
  if (sortKey === key) {
3660
3700
  setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
3661
3701
  } else {
@@ -3677,13 +3717,13 @@ var init_ModelsTable = __esm({
3677
3717
  return theme.palette.info.main;
3678
3718
  }
3679
3719
  };
3680
- return /* @__PURE__ */ import_react10.default.createElement(
3720
+ return /* @__PURE__ */ import_react11.default.createElement(
3681
3721
  SectionCard,
3682
3722
  {
3683
3723
  title: "Available Models",
3684
3724
  subtitle: selectedTeam ? `${filteredModels.length}${filterText.trim() ? ` of ${teamModels.length}` : ""} model${filteredModels.length === 1 ? "" : "s"}` : "Select a team to view its models"
3685
3725
  },
3686
- /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { sx: { px: 2.5, pb: 2.5, pt: 1, display: "flex", gap: 2, flexWrap: "wrap" } }, /* @__PURE__ */ import_react10.default.createElement(import_FormControl.default, { size: "small", sx: { minWidth: 240, mb: 2 } }, /* @__PURE__ */ import_react10.default.createElement(import_InputLabel.default, { id: "team-select-label" }, "Team"), /* @__PURE__ */ import_react10.default.createElement(
3726
+ /* @__PURE__ */ import_react11.default.createElement(import_Box10.default, { sx: { px: 2.5, pb: 2.5, pt: 1, display: "flex", gap: 2, flexWrap: "wrap" } }, /* @__PURE__ */ import_react11.default.createElement(import_FormControl.default, { size: "small", sx: { minWidth: 240, mb: 2 } }, /* @__PURE__ */ import_react11.default.createElement(import_InputLabel.default, { id: "team-select-label" }, "Team"), /* @__PURE__ */ import_react11.default.createElement(
3687
3727
  import_Select.default,
3688
3728
  {
3689
3729
  labelId: "team-select-label",
@@ -3691,8 +3731,8 @@ var init_ModelsTable = __esm({
3691
3731
  label: "Team",
3692
3732
  onChange: (e) => setSelectedTeamId(e.target.value)
3693
3733
  },
3694
- teams.map((t) => /* @__PURE__ */ import_react10.default.createElement(import_MenuItem4.default, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
3695
- )), /* @__PURE__ */ import_react10.default.createElement(
3734
+ teams.map((t) => /* @__PURE__ */ import_react11.default.createElement(import_MenuItem4.default, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
3735
+ )), /* @__PURE__ */ import_react11.default.createElement(
3696
3736
  import_TextField5.default,
3697
3737
  {
3698
3738
  label: "Filter Models",
@@ -3702,33 +3742,33 @@ var init_ModelsTable = __esm({
3702
3742
  disabled: !selectedTeamId,
3703
3743
  sx: { minWidth: 240, mb: 2 },
3704
3744
  InputProps: {
3705
- startAdornment: /* @__PURE__ */ import_react10.default.createElement(import_InputAdornment2.default, { position: "start" }, /* @__PURE__ */ import_react10.default.createElement(import_icons_material7.Search, { fontSize: "small" }))
3745
+ startAdornment: /* @__PURE__ */ import_react11.default.createElement(import_InputAdornment2.default, { position: "start" }, /* @__PURE__ */ import_react11.default.createElement(import_icons_material7.Search, { fontSize: "small" }))
3706
3746
  }
3707
3747
  }
3708
3748
  )),
3709
- loading && /* @__PURE__ */ import_react10.default.createElement(EmptyState, { message: "Loading models\u2026" }),
3710
- !loading && !selectedTeamId && /* @__PURE__ */ import_react10.default.createElement(
3749
+ loading && /* @__PURE__ */ import_react11.default.createElement(EmptyState, { message: "Loading models\u2026" }),
3750
+ !loading && !selectedTeamId && /* @__PURE__ */ import_react11.default.createElement(
3711
3751
  EmptyState,
3712
3752
  {
3713
3753
  message: "Select a team to see available models",
3714
3754
  hint: "Each team may have a different set of models assigned"
3715
3755
  }
3716
3756
  ),
3717
- !loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ import_react10.default.createElement(
3757
+ !loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ import_react11.default.createElement(
3718
3758
  EmptyState,
3719
3759
  {
3720
3760
  message: "No models available for this team",
3721
3761
  hint: allModels.length === 0 ? "No models are configured in the system" : "None of the team's assigned models were found in the catalog"
3722
3762
  }
3723
3763
  ),
3724
- !loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ import_react10.default.createElement(
3764
+ !loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ import_react11.default.createElement(
3725
3765
  EmptyState,
3726
3766
  {
3727
3767
  message: "No models match your search",
3728
3768
  hint: "Try a different search term"
3729
3769
  }
3730
3770
  ),
3731
- !loading && filteredModels.length > 0 && /* @__PURE__ */ import_react10.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react10.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react10.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react10.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { sortDirection: sortKey === "model_name" ? sortDirection : false }, /* @__PURE__ */ import_react10.default.createElement(import_TableSortLabel2.default, { active: sortKey === "model_name", direction: sortKey === "model_name" ? sortDirection : "asc", onClick: () => handleSort("model_name") }, "Model ID")), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { sortDirection: sortKey === "mode" ? sortDirection : false }, /* @__PURE__ */ import_react10.default.createElement(import_TableSortLabel2.default, { active: sortKey === "mode", direction: sortKey === "mode" ? sortDirection : "asc", onClick: () => handleSort("mode") }, "Mode")), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "input_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ import_react10.default.createElement(import_TableSortLabel2.default, { active: sortKey === "input_cost_per_token", direction: sortKey === "input_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("input_cost_per_token") }, "Input Cost")), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "output_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ import_react10.default.createElement(import_TableSortLabel2.default, { active: sortKey === "output_cost_per_token", direction: sortKey === "output_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("output_cost_per_token") }, "Output Cost")), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "max_input_tokens" ? sortDirection : false }, /* @__PURE__ */ import_react10.default.createElement(import_TableSortLabel2.default, { active: sortKey === "max_input_tokens", direction: sortKey === "max_input_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_input_tokens") }, "Max Input")), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "max_output_tokens" ? sortDirection : false }, /* @__PURE__ */ import_react10.default.createElement(import_TableSortLabel2.default, { active: sortKey === "max_output_tokens", direction: sortKey === "max_output_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_output_tokens") }, "Max Output")), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, null, "Capabilities"))), /* @__PURE__ */ import_react10.default.createElement(import_TableBody5.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react10.default.createElement(import_TableRow5.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react10.default.createElement(import_Tooltip.default, { title: m.model_name, placement: "top" }, /* @__PURE__ */ import_react10.default.createElement(
3771
+ !loading && filteredModels.length > 0 && /* @__PURE__ */ import_react11.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react11.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react11.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { sortDirection: sortKey === "model_name" ? sortDirection : false }, /* @__PURE__ */ import_react11.default.createElement(import_TableSortLabel2.default, { active: sortKey === "model_name", direction: sortKey === "model_name" ? sortDirection : "asc", onClick: () => handleSort("model_name") }, "Model ID")), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { sortDirection: sortKey === "mode" ? sortDirection : false }, /* @__PURE__ */ import_react11.default.createElement(import_TableSortLabel2.default, { active: sortKey === "mode", direction: sortKey === "mode" ? sortDirection : "asc", onClick: () => handleSort("mode") }, "Mode")), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "input_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ import_react11.default.createElement(import_TableSortLabel2.default, { active: sortKey === "input_cost_per_token", direction: sortKey === "input_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("input_cost_per_token") }, "Input Cost")), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "output_cost_per_token" ? sortDirection : false }, /* @__PURE__ */ import_react11.default.createElement(import_TableSortLabel2.default, { active: sortKey === "output_cost_per_token", direction: sortKey === "output_cost_per_token" ? sortDirection : "asc", onClick: () => handleSort("output_cost_per_token") }, "Output Cost")), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "max_input_tokens" ? sortDirection : false }, /* @__PURE__ */ import_react11.default.createElement(import_TableSortLabel2.default, { active: sortKey === "max_input_tokens", direction: sortKey === "max_input_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_input_tokens") }, "Max Input")), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right", sortDirection: sortKey === "max_output_tokens" ? sortDirection : false }, /* @__PURE__ */ import_react11.default.createElement(import_TableSortLabel2.default, { active: sortKey === "max_output_tokens", direction: sortKey === "max_output_tokens" ? sortDirection : "asc", onClick: () => handleSort("max_output_tokens") }, "Max Output")), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, null, "Capabilities"))), /* @__PURE__ */ import_react11.default.createElement(import_TableBody5.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react11.default.createElement(import_TableRow5.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react11.default.createElement(import_Box10.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react11.default.createElement(import_Tooltip.default, { title: m.model_name, placement: "top" }, /* @__PURE__ */ import_react11.default.createElement(
3732
3772
  "span",
3733
3773
  {
3734
3774
  role: "button",
@@ -3738,8 +3778,8 @@ var init_ModelsTable = __esm({
3738
3778
  onKeyDown: (e) => e.key === "Enter" && handleCopyModelId(m.model_name),
3739
3779
  style: { cursor: "pointer", display: "inline-flex" }
3740
3780
  },
3741
- /* @__PURE__ */ import_react10.default.createElement(TagChip, { label: m.model_name, title: "Copy model ID" })
3742
- )), /* @__PURE__ */ import_react10.default.createElement(import_Tooltip.default, { title: "Copy model ID" }, /* @__PURE__ */ import_react10.default.createElement(
3781
+ /* @__PURE__ */ import_react11.default.createElement(TagChip, { label: m.model_name, title: "Copy model ID" })
3782
+ )), /* @__PURE__ */ import_react11.default.createElement(import_Tooltip.default, { title: "Copy model ID" }, /* @__PURE__ */ import_react11.default.createElement(
3743
3783
  import_Box10.default,
3744
3784
  {
3745
3785
  component: "span",
@@ -3750,8 +3790,8 @@ var init_ModelsTable = __esm({
3750
3790
  sx: quietIconButtonSx("accent"),
3751
3791
  style: { cursor: "pointer", display: "inline-flex" }
3752
3792
  },
3753
- /* @__PURE__ */ import_react10.default.createElement(import_ContentCopy.default, { sx: { fontSize: 14 } })
3754
- )))), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react10.default.createElement(
3793
+ /* @__PURE__ */ import_react11.default.createElement(import_ContentCopy.default, { sx: { fontSize: 14 } })
3794
+ )))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react11.default.createElement(
3755
3795
  import_Box10.default,
3756
3796
  {
3757
3797
  component: "span",
@@ -3768,8 +3808,8 @@ var init_ModelsTable = __esm({
3768
3808
  }
3769
3809
  },
3770
3810
  m.mode
3771
- )), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.input_cost_per_token))), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.output_cost_per_token))), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_input_tokens))), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react10.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_output_tokens))), /* @__PURE__ */ import_react10.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react10.default.createElement(import_Box10.default, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" } }, m.supports_function_calling && /* @__PURE__ */ import_react10.default.createElement(TagChip, { label: "Fn", title: "Function calling" }), m.supports_vision && /* @__PURE__ */ import_react10.default.createElement(TagChip, { label: "\u{1F441}", title: "Vision" })))))))),
3772
- /* @__PURE__ */ import_react10.default.createElement(
3811
+ )), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react11.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.input_cost_per_token))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react11.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtCostPerToken(m.output_cost_per_token))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react11.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_input_tokens))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, { align: "right" }, /* @__PURE__ */ import_react11.default.createElement(import_Typography10.default, { variant: "body2", sx: { fontVariantNumeric: "tabular-nums" } }, fmtTokens(m.max_output_tokens))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react11.default.createElement(import_Box10.default, { sx: { display: "flex", gap: 0.5, flexWrap: "wrap" } }, m.supports_function_calling && /* @__PURE__ */ import_react11.default.createElement(TagChip, { label: "Fn", title: "Function calling" }), m.supports_vision && /* @__PURE__ */ import_react11.default.createElement(TagChip, { label: "\u{1F441}", title: "Vision" })))))))),
3812
+ /* @__PURE__ */ import_react11.default.createElement(
3773
3813
  import_Snackbar.default,
3774
3814
  {
3775
3815
  open: copiedSnackbar,
@@ -3777,7 +3817,7 @@ var init_ModelsTable = __esm({
3777
3817
  onClose: () => setCopiedSnackbar(false),
3778
3818
  anchorOrigin: { vertical: "bottom", horizontal: "center" }
3779
3819
  },
3780
- /* @__PURE__ */ import_react10.default.createElement(import_Alert4.default, { severity: "success", variant: "filled", sx: { fontSize: 13 } }, "Model ID copied to clipboard")
3820
+ /* @__PURE__ */ import_react11.default.createElement(import_Alert4.default, { severity: "success", variant: "filled", sx: { fontSize: 13 } }, "Model ID copied to clipboard")
3781
3821
  )
3782
3822
  );
3783
3823
  };
@@ -3805,10 +3845,10 @@ function formatDateTime(iso) {
3805
3845
  }
3806
3846
  function renderAuditLogBody(loading, entries) {
3807
3847
  if (loading) {
3808
- return /* @__PURE__ */ import_react11.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ import_react11.default.createElement(import_Skeleton5.default, { variant: "rounded", height: 160 })));
3848
+ return /* @__PURE__ */ import_react12.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, { colSpan: 6, sx: { py: 2 } }, /* @__PURE__ */ import_react12.default.createElement(import_Skeleton5.default, { variant: "rounded", height: 160 })));
3809
3849
  }
3810
3850
  if (entries.length === 0) {
3811
- return /* @__PURE__ */ import_react11.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, { colSpan: 6 }, /* @__PURE__ */ import_react11.default.createElement(
3851
+ return /* @__PURE__ */ import_react12.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, { colSpan: 6 }, /* @__PURE__ */ import_react12.default.createElement(
3812
3852
  EmptyState,
3813
3853
  {
3814
3854
  message: "No audit events found",
@@ -3816,13 +3856,13 @@ function renderAuditLogBody(loading, entries) {
3816
3856
  }
3817
3857
  )));
3818
3858
  }
3819
- return entries.map((entry) => /* @__PURE__ */ import_react11.default.createElement(DetailRow, { key: entry.id, entry }));
3859
+ return entries.map((entry) => /* @__PURE__ */ import_react12.default.createElement(DetailRow, { key: entry.id, entry }));
3820
3860
  }
3821
- var import_react11, import_Box11, import_Typography11, import_Table6, import_TableBody6, import_TableCell6, import_TableContainer6, import_TableHead6, import_TableRow6, import_TablePagination, import_TextField6, import_MenuItem5, import_Skeleton5, import_Collapse3, import_IconButton6, import_Alert5, import_styles8, import_icons_material8, import_react_use2, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3861
+ var import_react12, import_Box11, import_Typography11, import_Table6, import_TableBody6, import_TableCell6, import_TableContainer6, import_TableHead6, import_TableRow6, import_TablePagination, import_TextField6, import_MenuItem5, import_Skeleton5, import_Collapse3, import_IconButton6, import_Alert5, import_styles8, import_icons_material8, import_react_use2, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
3822
3862
  var init_AuditLog = __esm({
3823
3863
  "src/components/AuditLog.tsx"() {
3824
3864
  "use strict";
3825
- import_react11 = __toESM(require("react"));
3865
+ import_react12 = __toESM(require("react"));
3826
3866
  import_Box11 = __toESM(require("@mui/material/Box"));
3827
3867
  import_Typography11 = __toESM(require("@mui/material/Typography"));
3828
3868
  import_Table6 = __toESM(require("@mui/material/Table"));
@@ -3857,9 +3897,9 @@ var init_AuditLog = __esm({
3857
3897
  LiteLLM_UserTable: "User"
3858
3898
  };
3859
3899
  DetailRow = ({ entry }) => {
3860
- const [open, setOpen] = (0, import_react11.useState)(false);
3900
+ const [open, setOpen] = (0, import_react12.useState)(false);
3861
3901
  const hasDetail = entry.before_value || entry.updated_values;
3862
- return /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, { sx: { width: 40, pr: 0 } }, hasDetail && /* @__PURE__ */ import_react11.default.createElement(
3902
+ return /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, /* @__PURE__ */ import_react12.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, { sx: { width: 40, pr: 0 } }, hasDetail && /* @__PURE__ */ import_react12.default.createElement(
3863
3903
  import_IconButton6.default,
3864
3904
  {
3865
3905
  size: "small",
@@ -3872,8 +3912,8 @@ var init_AuditLog = __esm({
3872
3912
  transition: theme.transitions.create("transform")
3873
3913
  })
3874
3914
  },
3875
- /* @__PURE__ */ import_react11.default.createElement(import_icons_material8.KeyboardArrowDown, { fontSize: "small" })
3876
- )), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ import_react11.default.createElement(import_Typography11.default, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, entry.action && /* @__PURE__ */ import_react11.default.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_Typography11.default, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react11.default.createElement(
3915
+ /* @__PURE__ */ import_react12.default.createElement(import_icons_material8.KeyboardArrowDown, { fontSize: "small" })
3916
+ )), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ import_react12.default.createElement(import_Typography11.default, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, entry.action && /* @__PURE__ */ import_react12.default.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_Typography11.default, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react12.default.createElement(
3877
3917
  import_Typography11.default,
3878
3918
  {
3879
3919
  variant: "body2",
@@ -3883,7 +3923,7 @@ var init_AuditLog = __esm({
3883
3923
  sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 12 }
3884
3924
  },
3885
3925
  entry.object_id ? entry.object_id.slice(0, 20) + (entry.object_id.length > 20 ? "\u2026" : "") : "\u2014"
3886
- )), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, entry.changed_by ?? "\u2014")), hasDetail && /* @__PURE__ */ import_react11.default.createElement(import_TableRow6.default, { sx: { "&&:hover": { bgcolor: "transparent" } } }, /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, { colSpan: 6, sx: { "&&": { py: 0, border: 0 } } }, /* @__PURE__ */ import_react11.default.createElement(import_Collapse3.default, { in: open, unmountOnExit: true }, /* @__PURE__ */ import_react11.default.createElement(
3926
+ )), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, entry.changed_by ?? "\u2014")), hasDetail && /* @__PURE__ */ import_react12.default.createElement(import_TableRow6.default, { sx: { "&&:hover": { bgcolor: "transparent" } } }, /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, { colSpan: 6, sx: { "&&": { py: 0, border: 0 } } }, /* @__PURE__ */ import_react12.default.createElement(import_Collapse3.default, { in: open, unmountOnExit: true }, /* @__PURE__ */ import_react12.default.createElement(
3887
3927
  import_Box11.default,
3888
3928
  {
3889
3929
  display: "flex",
@@ -3896,7 +3936,7 @@ var init_AuditLog = __esm({
3896
3936
  bgcolor: (0, import_styles8.alpha)(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.05 : 0.03)
3897
3937
  })
3898
3938
  },
3899
- entry.before_value && /* @__PURE__ */ import_react11.default.createElement(import_Box11.default, { flex: 1, minWidth: 200 }, /* @__PURE__ */ import_react11.default.createElement(
3939
+ entry.before_value && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { flex: 1, minWidth: 200 }, /* @__PURE__ */ import_react12.default.createElement(
3900
3940
  import_Typography11.default,
3901
3941
  {
3902
3942
  variant: "caption",
@@ -3906,8 +3946,8 @@ var init_AuditLog = __esm({
3906
3946
  sx: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase" }
3907
3947
  },
3908
3948
  "Before"
3909
- ), /* @__PURE__ */ import_react11.default.createElement(import_Typography11.default, { 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))),
3910
- entry.updated_values && /* @__PURE__ */ import_react11.default.createElement(import_Box11.default, { flex: 1, minWidth: 200 }, /* @__PURE__ */ import_react11.default.createElement(
3949
+ ), /* @__PURE__ */ import_react12.default.createElement(import_Typography11.default, { 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))),
3950
+ entry.updated_values && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { flex: 1, minWidth: 200 }, /* @__PURE__ */ import_react12.default.createElement(
3911
3951
  import_Typography11.default,
3912
3952
  {
3913
3953
  variant: "caption",
@@ -3917,14 +3957,14 @@ var init_AuditLog = __esm({
3917
3957
  sx: { fontSize: 10.5, fontWeight: 700, letterSpacing: "0.07em", textTransform: "uppercase" }
3918
3958
  },
3919
3959
  "After"
3920
- ), /* @__PURE__ */ import_react11.default.createElement(import_Typography11.default, { 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)))
3960
+ ), /* @__PURE__ */ import_react12.default.createElement(import_Typography11.default, { 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)))
3921
3961
  )))));
3922
3962
  };
3923
3963
  AuditLog = ({ api }) => {
3924
- const [page, setPage] = (0, import_react11.useState)(0);
3925
- const [pageSize, setPageSize] = (0, import_react11.useState)(25);
3926
- const [filters, setFilters] = (0, import_react11.useState)({});
3927
- const fetchParams = (0, import_react11.useMemo)(
3964
+ const [page, setPage] = (0, import_react12.useState)(0);
3965
+ const [pageSize, setPageSize] = (0, import_react12.useState)(25);
3966
+ const [filters, setFilters] = (0, import_react12.useState)({});
3967
+ const fetchParams = (0, import_react12.useMemo)(
3928
3968
  () => ({ page: page + 1, page_size: pageSize, ...filters }),
3929
3969
  [page, pageSize, filters]
3930
3970
  );
@@ -3934,13 +3974,13 @@ var init_AuditLog = __esm({
3934
3974
  );
3935
3975
  const entries = value?.audit_logs ?? [];
3936
3976
  const total = value?.total ?? 0;
3937
- return /* @__PURE__ */ import_react11.default.createElement(
3977
+ return /* @__PURE__ */ import_react12.default.createElement(
3938
3978
  SectionCard,
3939
3979
  {
3940
3980
  title: "Audit Log",
3941
3981
  subtitle: loading ? "Loading\u2026" : `${total.toLocaleString()} event${total === 1 ? "" : "s"}`,
3942
3982
  flush: true,
3943
- actions: /* @__PURE__ */ import_react11.default.createElement(import_react11.default.Fragment, null, /* @__PURE__ */ import_react11.default.createElement(
3983
+ actions: /* @__PURE__ */ import_react12.default.createElement(import_react12.default.Fragment, null, /* @__PURE__ */ import_react12.default.createElement(
3944
3984
  import_TextField6.default,
3945
3985
  {
3946
3986
  size: "small",
@@ -3953,12 +3993,12 @@ var init_AuditLog = __esm({
3953
3993
  },
3954
3994
  sx: { minWidth: 150 }
3955
3995
  },
3956
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "" }, "All actions"),
3957
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "created" }, "Created"),
3958
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "updated" }, "Updated"),
3959
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "deleted" }, "Deleted"),
3960
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "blocked" }, "Blocked")
3961
- ), /* @__PURE__ */ import_react11.default.createElement(
3996
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "" }, "All actions"),
3997
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "created" }, "Created"),
3998
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "updated" }, "Updated"),
3999
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "deleted" }, "Deleted"),
4000
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "blocked" }, "Blocked")
4001
+ ), /* @__PURE__ */ import_react12.default.createElement(
3962
4002
  import_TextField6.default,
3963
4003
  {
3964
4004
  size: "small",
@@ -3971,13 +4011,13 @@ var init_AuditLog = __esm({
3971
4011
  },
3972
4012
  sx: { minWidth: 150 }
3973
4013
  },
3974
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "" }, "All tables"),
3975
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "LiteLLM_VerificationToken" }, "Key"),
3976
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "LiteLLM_TeamTable" }, "Team"),
3977
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "LiteLLM_TeamMembership" }, "Team member"),
3978
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
3979
- /* @__PURE__ */ import_react11.default.createElement(import_MenuItem5.default, { value: "LiteLLM_UserTable" }, "User")
3980
- ), /* @__PURE__ */ import_react11.default.createElement(
4014
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "" }, "All tables"),
4015
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "LiteLLM_VerificationToken" }, "Key"),
4016
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "LiteLLM_TeamTable" }, "Team"),
4017
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "LiteLLM_TeamMembership" }, "Team member"),
4018
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
4019
+ /* @__PURE__ */ import_react12.default.createElement(import_MenuItem5.default, { value: "LiteLLM_UserTable" }, "User")
4020
+ ), /* @__PURE__ */ import_react12.default.createElement(
3981
4021
  import_TextField6.default,
3982
4022
  {
3983
4023
  size: "small",
@@ -3991,9 +4031,9 @@ var init_AuditLog = __esm({
3991
4031
  }
3992
4032
  ))
3993
4033
  },
3994
- error && /* @__PURE__ */ import_react11.default.createElement(import_Box11.default, { px: 2.5, pb: 2 }, /* @__PURE__ */ import_react11.default.createElement(import_Alert5.default, { severity: "error" }, error.message)),
3995
- /* @__PURE__ */ import_react11.default.createElement(import_TableContainer6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_Table6.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react11.default.createElement(import_TableHead6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, { sx: { width: 40 } }), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, "Time"), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, "Action"), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, "Table"), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, "Object ID"), /* @__PURE__ */ import_react11.default.createElement(import_TableCell6.default, null, "Changed By"))), /* @__PURE__ */ import_react11.default.createElement(import_TableBody6.default, null, renderAuditLogBody(loading, entries)))),
3996
- /* @__PURE__ */ import_react11.default.createElement(
4034
+ error && /* @__PURE__ */ import_react12.default.createElement(import_Box11.default, { px: 2.5, pb: 2 }, /* @__PURE__ */ import_react12.default.createElement(import_Alert5.default, { severity: "error" }, error.message)),
4035
+ /* @__PURE__ */ import_react12.default.createElement(import_TableContainer6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_Table6.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react12.default.createElement(import_TableHead6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_TableRow6.default, null, /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, { sx: { width: 40 } }), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, "Time"), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, "Action"), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, "Table"), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, "Object ID"), /* @__PURE__ */ import_react12.default.createElement(import_TableCell6.default, null, "Changed By"))), /* @__PURE__ */ import_react12.default.createElement(import_TableBody6.default, null, renderAuditLogBody(loading, entries)))),
4036
+ /* @__PURE__ */ import_react12.default.createElement(
3997
4037
  import_TablePagination.default,
3998
4038
  {
3999
4039
  component: "div",
@@ -4062,11 +4102,11 @@ function initDateRange() {
4062
4102
  else start.setDate(start.getDate() - 7);
4063
4103
  return { start, end };
4064
4104
  }
4065
- var import_react12, import_Box12, import_Snackbar2, import_Alert6, import_CircularProgress6, import_Typography12, import_Paper8, import_Tabs2, import_Tab2, import_Grid2, import_react_router_dom, import_react_use3, import_core_plugin_api4, import_plugin_permission_react, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
4105
+ var import_react13, import_Box12, import_Snackbar2, import_Alert6, import_CircularProgress6, import_Typography12, import_Paper8, import_Tabs2, import_Tab2, import_Grid2, import_react_router_dom, import_react_use3, import_core_plugin_api4, import_plugin_permission_react, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
4066
4106
  var init_LiteLLMPage = __esm({
4067
4107
  "src/components/LiteLLMPage.tsx"() {
4068
4108
  "use strict";
4069
- import_react12 = __toESM(require("react"));
4109
+ import_react13 = __toESM(require("react"));
4070
4110
  import_Box12 = __toESM(require("@mui/material/Box"));
4071
4111
  import_Snackbar2 = __toESM(require("@mui/material/Snackbar"));
4072
4112
  import_Alert6 = __toESM(require("@mui/material/Alert"));
@@ -4096,8 +4136,8 @@ var init_LiteLLMPage = __esm({
4096
4136
  isPageTab = (v) => !!v && PAGE_TABS.includes(v);
4097
4137
  LiteLLMPage = () => {
4098
4138
  const api = (0, import_core_plugin_api4.useApi)(liteLlmApiRef);
4099
- const [dateRange, setDateRange] = (0, import_react12.useState)(initDateRange);
4100
- const [currentPreset, setCurrentPreset] = (0, import_react12.useState)(() => {
4139
+ const [dateRange, setDateRange] = (0, import_react13.useState)(initDateRange);
4140
+ const [currentPreset, setCurrentPreset] = (0, import_react13.useState)(() => {
4101
4141
  try {
4102
4142
  return localStorage.getItem(PERIOD_LS_KEY2) ?? "7d";
4103
4143
  } catch {
@@ -4105,14 +4145,14 @@ var init_LiteLLMPage = __esm({
4105
4145
  }
4106
4146
  });
4107
4147
  const [searchParams, setSearchParams] = (0, import_react_router_dom.useSearchParams)();
4108
- const [activeTab, setActiveTab] = (0, import_react12.useState)(() => {
4148
+ const [activeTab, setActiveTab] = (0, import_react13.useState)(() => {
4109
4149
  const t = searchParams.get("tab");
4110
4150
  return isPageTab(t) ? t : "overview";
4111
4151
  });
4112
- const [generateDialogOpen, setGenerateDialogOpen] = (0, import_react12.useState)(
4152
+ const [generateDialogOpen, setGenerateDialogOpen] = (0, import_react13.useState)(
4113
4153
  () => searchParams.get("generate") === "1"
4114
4154
  );
4115
- (0, import_react12.useEffect)(() => {
4155
+ (0, import_react13.useEffect)(() => {
4116
4156
  if (searchParams.get("generate") !== "1") return;
4117
4157
  setGenerateDialogOpen(true);
4118
4158
  setSearchParams(
@@ -4124,7 +4164,7 @@ var init_LiteLLMPage = __esm({
4124
4164
  { replace: true }
4125
4165
  );
4126
4166
  }, [searchParams, setSearchParams]);
4127
- const selectTab = (0, import_react12.useCallback)(
4167
+ const selectTab = (0, import_react13.useCallback)(
4128
4168
  (tab) => {
4129
4169
  setActiveTab(tab);
4130
4170
  setSearchParams(
@@ -4138,12 +4178,12 @@ var init_LiteLLMPage = __esm({
4138
4178
  },
4139
4179
  [setSearchParams]
4140
4180
  );
4141
- const [snackbar, setSnackbar] = (0, import_react12.useState)(null);
4142
- const [manageTeam, setManageTeam] = (0, import_react12.useState)(null);
4143
- const [keyToEdit, setKeyToEdit] = (0, import_react12.useState)(null);
4181
+ const [snackbar, setSnackbar] = (0, import_react13.useState)(null);
4182
+ const [manageTeam, setManageTeam] = (0, import_react13.useState)(null);
4183
+ const [keyToEdit, setKeyToEdit] = (0, import_react13.useState)(null);
4144
4184
  const keyFormOpen = generateDialogOpen || !!keyToEdit;
4145
- const [teamUsageCache, setTeamUsageCache] = (0, import_react12.useState)({});
4146
- const [teamUsageLoading, setTeamUsageLoading] = (0, import_react12.useState)({});
4185
+ const [teamUsageCache, setTeamUsageCache] = (0, import_react13.useState)({});
4186
+ const [teamUsageLoading, setTeamUsageLoading] = (0, import_react13.useState)({});
4147
4187
  const { value: userInfo, loading: userLoading, error: userError } = (0, import_react_use3.useAsync)(
4148
4188
  () => api.getUserInfo(),
4149
4189
  [api]
@@ -4187,7 +4227,7 @@ var init_LiteLLMPage = __esm({
4187
4227
  async () => objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],
4188
4228
  [api, objectPermsEnabled]
4189
4229
  );
4190
- const teams = (0, import_react12.useMemo)(() => {
4230
+ const teams = (0, import_react13.useMemo)(() => {
4191
4231
  if (!allTeams?.length) return [];
4192
4232
  if (!userInfo) return allTeams;
4193
4233
  const userId = userInfo.user_id;
@@ -4204,7 +4244,7 @@ var init_LiteLLMPage = __esm({
4204
4244
  const endDate = dateRange.end.toISOString().split("T")[0];
4205
4245
  return api.getUsage(startDate, endDate);
4206
4246
  }, [api, dateRange]);
4207
- const handleDateRangeChange = (0, import_react12.useCallback)((range, preset) => {
4247
+ const handleDateRangeChange = (0, import_react13.useCallback)((range, preset) => {
4208
4248
  setDateRange(range);
4209
4249
  if (preset) {
4210
4250
  setCurrentPreset(preset);
@@ -4212,7 +4252,7 @@ var init_LiteLLMPage = __esm({
4212
4252
  setTeamUsageCache({});
4213
4253
  setTeamUsageLoading({});
4214
4254
  }, [setDateRange, setCurrentPreset]);
4215
- const loadTeamUsage = (0, import_react12.useCallback)(async (teamId) => {
4255
+ const loadTeamUsage = (0, import_react13.useCallback)(async (teamId) => {
4216
4256
  if (teamUsageCache[teamId] !== void 0 || teamUsageLoading[teamId]) return;
4217
4257
  setTeamUsageLoading((prev) => ({ ...prev, [teamId]: true }));
4218
4258
  try {
@@ -4226,7 +4266,7 @@ var init_LiteLLMPage = __esm({
4226
4266
  setTeamUsageLoading((prev) => ({ ...prev, [teamId]: false }));
4227
4267
  }
4228
4268
  }, [api, dateRange, teamUsageCache, teamUsageLoading]);
4229
- const allowedModels = (0, import_react12.useMemo)(() => {
4269
+ const allowedModels = (0, import_react13.useMemo)(() => {
4230
4270
  if (!allModels?.length) return [];
4231
4271
  const userModels = userInfo?.models;
4232
4272
  const teamModels = teams?.flatMap((t) => t.models ?? []);
@@ -4239,7 +4279,7 @@ var init_LiteLLMPage = __esm({
4239
4279
  ]);
4240
4280
  return allModels.filter((m) => allowed.has(m.model_name));
4241
4281
  }, [allModels, userInfo, teams]);
4242
- const handleGenerateKey = (0, import_react12.useCallback)(
4282
+ const handleGenerateKey = (0, import_react13.useCallback)(
4243
4283
  async (request) => {
4244
4284
  try {
4245
4285
  const response = await api.generateKey(request);
@@ -4253,7 +4293,7 @@ var init_LiteLLMPage = __esm({
4253
4293
  },
4254
4294
  [api, refreshKeys]
4255
4295
  );
4256
- const handleUpdateKey = (0, import_react12.useCallback)(
4296
+ const handleUpdateKey = (0, import_react13.useCallback)(
4257
4297
  async (keyId, request) => {
4258
4298
  try {
4259
4299
  await api.updateKey(keyId, request);
@@ -4266,7 +4306,7 @@ var init_LiteLLMPage = __esm({
4266
4306
  },
4267
4307
  [api, refreshKeys]
4268
4308
  );
4269
- const handleBlockKey = (0, import_react12.useCallback)(
4309
+ const handleBlockKey = (0, import_react13.useCallback)(
4270
4310
  async (keyId) => {
4271
4311
  try {
4272
4312
  await api.blockKey(keyId);
@@ -4278,7 +4318,7 @@ var init_LiteLLMPage = __esm({
4278
4318
  },
4279
4319
  [api, refreshKeys]
4280
4320
  );
4281
- const handleUnblockKey = (0, import_react12.useCallback)(
4321
+ const handleUnblockKey = (0, import_react13.useCallback)(
4282
4322
  async (keyId) => {
4283
4323
  try {
4284
4324
  await api.unblockKey(keyId);
@@ -4290,7 +4330,7 @@ var init_LiteLLMPage = __esm({
4290
4330
  },
4291
4331
  [api, refreshKeys]
4292
4332
  );
4293
- const handleResetKeySpend = (0, import_react12.useCallback)(
4333
+ const handleResetKeySpend = (0, import_react13.useCallback)(
4294
4334
  async (keyId) => {
4295
4335
  try {
4296
4336
  await api.resetKeySpend(keyId);
@@ -4302,7 +4342,7 @@ var init_LiteLLMPage = __esm({
4302
4342
  },
4303
4343
  [api, refreshKeys]
4304
4344
  );
4305
- const handleDeleteKey = (0, import_react12.useCallback)(
4345
+ const handleDeleteKey = (0, import_react13.useCallback)(
4306
4346
  async (keyId) => {
4307
4347
  try {
4308
4348
  await api.deleteKey(keyId);
@@ -4319,7 +4359,7 @@ var init_LiteLLMPage = __esm({
4319
4359
  },
4320
4360
  [api, refreshKeys]
4321
4361
  );
4322
- const handlePruneExpiredKeys = (0, import_react12.useCallback)(
4362
+ const handlePruneExpiredKeys = (0, import_react13.useCallback)(
4323
4363
  async () => {
4324
4364
  try {
4325
4365
  const result = await api.pruneExpiredKeys();
@@ -4334,14 +4374,14 @@ var init_LiteLLMPage = __esm({
4334
4374
  );
4335
4375
  const isInitialLoading = userLoading && !userInfo;
4336
4376
  if (isInitialLoading) {
4337
- return /* @__PURE__ */ import_react12.default.createElement(import_Box12.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ import_react12.default.createElement(import_CircularProgress6.default, null));
4377
+ return /* @__PURE__ */ import_react13.default.createElement(import_Box12.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "50vh" }, /* @__PURE__ */ import_react13.default.createElement(import_CircularProgress6.default, null));
4338
4378
  }
4339
4379
  if (userError || !userInfo) {
4340
4380
  const isProvisioningEnabled = userError?.body?.provisioning === true;
4341
4381
  const hint = userError?.body?.hint;
4342
- return /* @__PURE__ */ import_react12.default.createElement(import_Box12.default, { p: 3 }, /* @__PURE__ */ import_react12.default.createElement(import_Paper8.default, { sx: { p: 3 } }, /* @__PURE__ */ import_react12.default.createElement(import_Typography12.default, { variant: "h6", gutterBottom: true }, "Account not provisioned"), /* @__PURE__ */ import_react12.default.createElement(import_Typography12.default, { color: "text.secondary", paragraph: true }, "Your Backstage account is not linked to a LiteLLM user."), hint ? /* @__PURE__ */ import_react12.default.createElement(import_Typography12.default, { variant: "body2", color: "text.secondary" }, hint) : /* @__PURE__ */ import_react12.default.createElement(import_Typography12.default, { variant: "body2", color: "text.secondary" }, isProvisioningEnabled ? "Auto-provisioning is enabled but failed. Check the backend logs." : "Set litellm.provisioning.enabled: true in app-config.yaml to enable auto-provisioning, or ask your administrator to create the account manually.")));
4382
+ return /* @__PURE__ */ import_react13.default.createElement(import_Box12.default, { p: 3 }, /* @__PURE__ */ import_react13.default.createElement(import_Paper8.default, { sx: { p: 3 } }, /* @__PURE__ */ import_react13.default.createElement(import_Typography12.default, { variant: "h6", gutterBottom: true }, "Account not provisioned"), /* @__PURE__ */ import_react13.default.createElement(import_Typography12.default, { color: "text.secondary", paragraph: true }, "Your Backstage account is not linked to a LiteLLM user."), hint ? /* @__PURE__ */ import_react13.default.createElement(import_Typography12.default, { variant: "body2", color: "text.secondary" }, hint) : /* @__PURE__ */ import_react13.default.createElement(import_Typography12.default, { variant: "body2", color: "text.secondary" }, isProvisioningEnabled ? "Auto-provisioning is enabled but failed. Check the backend logs." : "Set litellm.provisioning.enabled: true in app-config.yaml to enable auto-provisioning, or ask your administrator to create the account manually.")));
4343
4383
  }
4344
- const pageTabs = /* @__PURE__ */ import_react12.default.createElement(
4384
+ const pageTabs = /* @__PURE__ */ import_react13.default.createElement(
4345
4385
  import_Tabs2.default,
4346
4386
  {
4347
4387
  value: activeTab,
@@ -4354,13 +4394,13 @@ var init_LiteLLMPage = __esm({
4354
4394
  '& [class*="MuiTab-root"]': { minHeight: 44, textTransform: "none", fontSize: 14 }
4355
4395
  }
4356
4396
  },
4357
- /* @__PURE__ */ import_react12.default.createElement(import_Tab2.default, { label: "Overview", value: "overview" }),
4358
- /* @__PURE__ */ import_react12.default.createElement(import_Tab2.default, { label: "Keys", value: "keys" }),
4359
- /* @__PURE__ */ import_react12.default.createElement(import_Tab2.default, { label: "Teams", value: "teams" }),
4360
- /* @__PURE__ */ import_react12.default.createElement(import_Tab2.default, { label: "Models", value: "models" }),
4361
- userInfo.can_view_audit && /* @__PURE__ */ import_react12.default.createElement(import_Tab2.default, { label: "Audit Log", value: "audit" })
4397
+ /* @__PURE__ */ import_react13.default.createElement(import_Tab2.default, { label: "Overview", value: "overview" }),
4398
+ /* @__PURE__ */ import_react13.default.createElement(import_Tab2.default, { label: "Keys", value: "keys" }),
4399
+ /* @__PURE__ */ import_react13.default.createElement(import_Tab2.default, { label: "Teams", value: "teams" }),
4400
+ /* @__PURE__ */ import_react13.default.createElement(import_Tab2.default, { label: "Models", value: "models" }),
4401
+ userInfo.can_view_audit && /* @__PURE__ */ import_react13.default.createElement(import_Tab2.default, { label: "Audit Log", value: "audit" })
4362
4402
  );
4363
- return /* @__PURE__ */ import_react12.default.createElement(import_Box12.default, { sx: { p: 3, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ import_react12.default.createElement(
4403
+ return /* @__PURE__ */ import_react13.default.createElement(import_Box12.default, { sx: { p: 3, display: "flex", flexDirection: "column", gap: 2 } }, /* @__PURE__ */ import_react13.default.createElement(
4364
4404
  DashboardHeader,
4365
4405
  {
4366
4406
  userInfo,
@@ -4370,7 +4410,7 @@ var init_LiteLLMPage = __esm({
4370
4410
  onGenerateKeyClick: () => setGenerateDialogOpen(true),
4371
4411
  tabs: pageTabs
4372
4412
  }
4373
- ), activeTab === "overview" && /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { container: true, spacing: 2, alignItems: "flex-start" }, /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 12, lg: 8 }, /* @__PURE__ */ import_react12.default.createElement(
4413
+ ), activeTab === "overview" && /* @__PURE__ */ import_react13.default.createElement(import_Grid2.default, { container: true, spacing: 2, alignItems: "flex-start" }, /* @__PURE__ */ import_react13.default.createElement(import_Grid2.default, { item: true, xs: 12, lg: 8 }, /* @__PURE__ */ import_react13.default.createElement(
4374
4414
  UsageStats,
4375
4415
  {
4376
4416
  usage: usage ?? null,
@@ -4381,7 +4421,7 @@ var init_LiteLLMPage = __esm({
4381
4421
  loading: usageLoading,
4382
4422
  userInfo
4383
4423
  }
4384
- )), /* @__PURE__ */ import_react12.default.createElement(import_Grid2.default, { item: true, xs: 12, lg: 4 }, /* @__PURE__ */ import_react12.default.createElement(LiteLLMBudgetWidget, { compact: true, collapsible: true }))), activeTab === "keys" && /* @__PURE__ */ import_react12.default.createElement(
4424
+ )), /* @__PURE__ */ import_react13.default.createElement(import_Grid2.default, { item: true, xs: 12, lg: 4 }, /* @__PURE__ */ import_react13.default.createElement(LiteLLMBudgetWidget, { compact: true, collapsible: true }))), activeTab === "keys" && /* @__PURE__ */ import_react13.default.createElement(
4385
4425
  KeysTable,
4386
4426
  {
4387
4427
  keys: keys ?? [],
@@ -4398,7 +4438,7 @@ var init_LiteLLMPage = __esm({
4398
4438
  for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);
4399
4439
  for (const t of teams ?? []) teamsById.set(t.team_id, t);
4400
4440
  const visibleTeams = Array.from(teamsById.values());
4401
- return /* @__PURE__ */ import_react12.default.createElement(
4441
+ return /* @__PURE__ */ import_react13.default.createElement(
4402
4442
  TeamUsage,
4403
4443
  {
4404
4444
  teams: visibleTeams,
@@ -4414,14 +4454,14 @@ var init_LiteLLMPage = __esm({
4414
4454
  onCreateTeam: () => setManageTeam({ mode: "create" })
4415
4455
  }
4416
4456
  );
4417
- })(), activeTab === "models" && /* @__PURE__ */ import_react12.default.createElement(
4457
+ })(), activeTab === "models" && /* @__PURE__ */ import_react13.default.createElement(
4418
4458
  ModelsTable,
4419
4459
  {
4420
4460
  allModels: allModels ?? [],
4421
4461
  teams: teams ?? [],
4422
4462
  loading: modelsLoading
4423
4463
  }
4424
- ), activeTab === "audit" && userInfo.can_view_audit && /* @__PURE__ */ import_react12.default.createElement(AuditLog, { api }), /* @__PURE__ */ import_react12.default.createElement(
4464
+ ), activeTab === "audit" && userInfo.can_view_audit && /* @__PURE__ */ import_react13.default.createElement(AuditLog, { api }), /* @__PURE__ */ import_react13.default.createElement(
4425
4465
  KeyFormDialog,
4426
4466
  {
4427
4467
  open: keyFormOpen,
@@ -4441,7 +4481,7 @@ var init_LiteLLMPage = __esm({
4441
4481
  onResetKeySpend: handleResetKeySpend,
4442
4482
  onGetConfig: () => api.getConfig()
4443
4483
  }
4444
- ), /* @__PURE__ */ import_react12.default.createElement(
4484
+ ), /* @__PURE__ */ import_react13.default.createElement(
4445
4485
  ManageTeamDialog,
4446
4486
  {
4447
4487
  open: !!manageTeam,
@@ -4503,7 +4543,7 @@ var init_LiteLLMPage = __esm({
4503
4543
  refreshTeams();
4504
4544
  }
4505
4545
  }
4506
- ), /* @__PURE__ */ import_react12.default.createElement(
4546
+ ), /* @__PURE__ */ import_react13.default.createElement(
4507
4547
  import_Snackbar2.default,
4508
4548
  {
4509
4549
  open: !!snackbar,
@@ -4511,7 +4551,7 @@ var init_LiteLLMPage = __esm({
4511
4551
  onClose: () => setSnackbar(null),
4512
4552
  anchorOrigin: { vertical: "bottom", horizontal: "right" }
4513
4553
  },
4514
- snackbar ? /* @__PURE__ */ import_react12.default.createElement(import_Alert6.default, { severity: snackbar.severity, onClose: () => setSnackbar(null) }, snackbar.message) : void 0
4554
+ snackbar ? /* @__PURE__ */ import_react13.default.createElement(import_Alert6.default, { severity: snackbar.severity, onClose: () => setSnackbar(null) }, snackbar.message) : void 0
4515
4555
  ));
4516
4556
  };
4517
4557
  }
@@ -4521,6 +4561,7 @@ var init_LiteLLMPage = __esm({
4521
4561
  var index_exports = {};
4522
4562
  __export(index_exports, {
4523
4563
  DashboardHeader: () => DashboardHeader,
4564
+ GenerateKeyButton: () => GenerateKeyButton,
4524
4565
  GenerateKeyDialog: () => GenerateKeyDialog,
4525
4566
  KeyFormDialog: () => KeyFormDialog,
4526
4567
  KeysTable: () => KeysTable,
@@ -4543,7 +4584,7 @@ __export(index_exports, {
4543
4584
  module.exports = __toCommonJS(index_exports);
4544
4585
 
4545
4586
  // src/plugin.tsx
4546
- var import_react13 = __toESM(require("react"));
4587
+ var import_react14 = __toESM(require("react"));
4547
4588
  var import_icons_material9 = require("@mui/icons-material");
4548
4589
  var import_frontend_plugin_api = require("@backstage/frontend-plugin-api");
4549
4590
  init_api();
@@ -4558,10 +4599,10 @@ var liteLlmPage = import_frontend_plugin_api.PageBlueprint.make({
4558
4599
  params: {
4559
4600
  path: "/litellm",
4560
4601
  title: "LiteLLM",
4561
- icon: /* @__PURE__ */ import_react13.default.createElement(import_icons_material9.TrendingUp, null),
4602
+ icon: /* @__PURE__ */ import_react14.default.createElement(import_icons_material9.TrendingUp, null),
4562
4603
  loader: async () => {
4563
4604
  const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
4564
- return /* @__PURE__ */ import_react13.default.createElement(LiteLLMPage2, null);
4605
+ return /* @__PURE__ */ import_react14.default.createElement(LiteLLMPage2, null);
4565
4606
  }
4566
4607
  }
4567
4608
  });
@@ -4578,7 +4619,7 @@ init_UsageStats();
4578
4619
  init_TeamUsage();
4579
4620
 
4580
4621
  // src/components/LiteLLMHomeWidget.tsx
4581
- var import_react14 = __toESM(require("react"));
4622
+ var import_react15 = __toESM(require("react"));
4582
4623
  var import_Paper9 = __toESM(require("@mui/material/Paper"));
4583
4624
  var import_Box13 = __toESM(require("@mui/material/Box"));
4584
4625
  var import_Typography13 = __toESM(require("@mui/material/Typography"));
@@ -4604,19 +4645,19 @@ function presetToDateRange(preset) {
4604
4645
  }
4605
4646
  return { start, end };
4606
4647
  }
4607
- var Kpi = ({ label, value }) => /* @__PURE__ */ import_react14.default.createElement(import_Box13.default, null, /* @__PURE__ */ import_react14.default.createElement(import_Typography13.default, { variant: "caption", color: "text.secondary", display: "block" }, label), /* @__PURE__ */ import_react14.default.createElement(import_Typography13.default, { variant: "subtitle1", fontWeight: 600 }, value));
4648
+ var Kpi = ({ label, value }) => /* @__PURE__ */ import_react15.default.createElement(import_Box13.default, null, /* @__PURE__ */ import_react15.default.createElement(import_Typography13.default, { variant: "caption", color: "text.secondary", display: "block" }, label), /* @__PURE__ */ import_react15.default.createElement(import_Typography13.default, { variant: "subtitle1", fontWeight: 600 }, value));
4608
4649
  var LiteLLMHomeWidget = ({
4609
4650
  defaultPeriod = "7d",
4610
4651
  title = "LiteLLM Usage"
4611
4652
  }) => {
4612
4653
  const api = (0, import_core_plugin_api5.useApi)(liteLlmApiRef);
4613
- const [period, setPeriod] = (0, import_react14.useState)(defaultPeriod);
4614
- const [loading, setLoading] = (0, import_react14.useState)(true);
4615
- const [usageError, setUsageError] = (0, import_react14.useState)(null);
4616
- const [keysError, setKeysError] = (0, import_react14.useState)(null);
4617
- const [usage, setUsage] = (0, import_react14.useState)(null);
4618
- const [keys, setKeys] = (0, import_react14.useState)([]);
4619
- (0, import_react14.useEffect)(() => {
4654
+ const [period, setPeriod] = (0, import_react15.useState)(defaultPeriod);
4655
+ const [loading, setLoading] = (0, import_react15.useState)(true);
4656
+ const [usageError, setUsageError] = (0, import_react15.useState)(null);
4657
+ const [keysError, setKeysError] = (0, import_react15.useState)(null);
4658
+ const [usage, setUsage] = (0, import_react15.useState)(null);
4659
+ const [keys, setKeys] = (0, import_react15.useState)([]);
4660
+ (0, import_react15.useEffect)(() => {
4620
4661
  let cancelled = false;
4621
4662
  setLoading(true);
4622
4663
  setUsageError(null);
@@ -4653,17 +4694,17 @@ var LiteLLMHomeWidget = ({
4653
4694
  spend: d.spend
4654
4695
  }));
4655
4696
  const hasSparkline = dailyData.length > 0;
4656
- return /* @__PURE__ */ import_react14.default.createElement(import_Paper9.default, { sx: { p: 2 } }, /* @__PURE__ */ import_react14.default.createElement(import_Box13.default, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ import_react14.default.createElement(import_Typography13.default, { variant: "h6" }, title), /* @__PURE__ */ import_react14.default.createElement(import_FormControl2.default, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ import_react14.default.createElement(
4697
+ return /* @__PURE__ */ import_react15.default.createElement(import_Paper9.default, { sx: { p: 2 } }, /* @__PURE__ */ import_react15.default.createElement(import_Box13.default, { display: "flex", justifyContent: "space-between", alignItems: "center", mb: 1.5 }, /* @__PURE__ */ import_react15.default.createElement(import_Typography13.default, { variant: "h6" }, title), /* @__PURE__ */ import_react15.default.createElement(import_FormControl2.default, { size: "small", sx: { minWidth: 90 } }, /* @__PURE__ */ import_react15.default.createElement(
4657
4698
  import_Select2.default,
4658
4699
  {
4659
4700
  value: period,
4660
4701
  onChange: (e) => setPeriod(e.target.value),
4661
4702
  displayEmpty: true
4662
4703
  },
4663
- /* @__PURE__ */ import_react14.default.createElement(import_MenuItem6.default, { value: "today" }, "Today"),
4664
- /* @__PURE__ */ import_react14.default.createElement(import_MenuItem6.default, { value: "7d" }, "7d"),
4665
- /* @__PURE__ */ import_react14.default.createElement(import_MenuItem6.default, { value: "30d" }, "30d")
4666
- ))), loading && /* @__PURE__ */ import_react14.default.createElement(import_Box13.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ import_react14.default.createElement(import_CircularProgress7.default, { size: 32 })), !loading && totalFailure && /* @__PURE__ */ import_react14.default.createElement(import_Alert7.default, { severity: "error", sx: { mt: 1 } }, usageError ?? "Failed to load usage data"), !loading && !totalFailure && /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, partialFailure && /* @__PURE__ */ import_react14.default.createElement(import_Alert7.default, { severity: "warning", sx: { mt: 1, mb: 1 } }, usageError ? `Usage data unavailable (${usageError}).` : "", keysError ? ` Key list unavailable (${keysError}).` : "", " Showing what loaded."), /* @__PURE__ */ import_react14.default.createElement(import_Grid3.default, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ import_react14.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react14.default.createElement(Kpi, { label: "USD Spent", value: fmtUsd(usage?.total_spend ?? 0) })), /* @__PURE__ */ import_react14.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react14.default.createElement(Kpi, { label: "Tokens In", value: fmtInt(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ import_react14.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react14.default.createElement(Kpi, { label: "Tokens Out", value: fmtInt(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ import_react14.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react14.default.createElement(Kpi, { label: "Keys", value: fmtInt(keys.length) }))), hasSparkline && /* @__PURE__ */ import_react14.default.createElement(import_Box13.default, { height: 120 }, /* @__PURE__ */ import_react14.default.createElement(import_recharts3.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react14.default.createElement(import_recharts3.AreaChart, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ import_react14.default.createElement(
4704
+ /* @__PURE__ */ import_react15.default.createElement(import_MenuItem6.default, { value: "today" }, "Today"),
4705
+ /* @__PURE__ */ import_react15.default.createElement(import_MenuItem6.default, { value: "7d" }, "7d"),
4706
+ /* @__PURE__ */ import_react15.default.createElement(import_MenuItem6.default, { value: "30d" }, "30d")
4707
+ ))), loading && /* @__PURE__ */ import_react15.default.createElement(import_Box13.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 120 }, /* @__PURE__ */ import_react15.default.createElement(import_CircularProgress7.default, { size: 32 })), !loading && totalFailure && /* @__PURE__ */ import_react15.default.createElement(import_Alert7.default, { severity: "error", sx: { mt: 1 } }, usageError ?? "Failed to load usage data"), !loading && !totalFailure && /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, partialFailure && /* @__PURE__ */ import_react15.default.createElement(import_Alert7.default, { severity: "warning", sx: { mt: 1, mb: 1 } }, usageError ? `Usage data unavailable (${usageError}).` : "", keysError ? ` Key list unavailable (${keysError}).` : "", " Showing what loaded."), /* @__PURE__ */ import_react15.default.createElement(import_Grid3.default, { container: true, spacing: 2, sx: { mb: hasSparkline ? 1.5 : 0 } }, /* @__PURE__ */ import_react15.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react15.default.createElement(Kpi, { label: "USD Spent", value: fmtUsd(usage?.total_spend ?? 0) })), /* @__PURE__ */ import_react15.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react15.default.createElement(Kpi, { label: "Tokens In", value: fmtInt(usage?.prompt_tokens ?? 0) })), /* @__PURE__ */ import_react15.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react15.default.createElement(Kpi, { label: "Tokens Out", value: fmtInt(usage?.completion_tokens ?? 0) })), /* @__PURE__ */ import_react15.default.createElement(import_Grid3.default, { item: true, xs: 6 }, /* @__PURE__ */ import_react15.default.createElement(Kpi, { label: "Keys", value: fmtInt(keys.length) }))), hasSparkline && /* @__PURE__ */ import_react15.default.createElement(import_Box13.default, { height: 120 }, /* @__PURE__ */ import_react15.default.createElement(import_recharts3.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react15.default.createElement(import_recharts3.AreaChart, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ import_react15.default.createElement(
4667
4708
  import_recharts3.Area,
4668
4709
  {
4669
4710
  type: "monotone",
@@ -4681,7 +4722,7 @@ var LiteLLMHomeWidget = ({
4681
4722
  init_LiteLLMBudgetWidget();
4682
4723
 
4683
4724
  // src/components/LiteLLMBudgetGauges.tsx
4684
- var import_react15 = __toESM(require("react"));
4725
+ var import_react16 = __toESM(require("react"));
4685
4726
  var import_Paper10 = __toESM(require("@mui/material/Paper"));
4686
4727
  var import_Box14 = __toESM(require("@mui/material/Box"));
4687
4728
  var import_Button6 = __toESM(require("@mui/material/Button"));
@@ -4690,11 +4731,13 @@ var import_CircularProgress8 = __toESM(require("@mui/material/CircularProgress")
4690
4731
  var import_Alert8 = __toESM(require("@mui/material/Alert"));
4691
4732
  var import_Collapse4 = __toESM(require("@mui/material/Collapse"));
4692
4733
  var import_icons_material10 = require("@mui/icons-material");
4734
+ var import_recharts4 = require("recharts");
4693
4735
  var import_core_plugin_api6 = require("@backstage/core-plugin-api");
4694
- var import_core_components2 = require("@backstage/core-components");
4736
+ var import_core_components3 = require("@backstage/core-components");
4695
4737
  init_api();
4696
4738
  init_format();
4697
4739
  init_ui();
4740
+ init_GenerateKeyButton();
4698
4741
  init_BudgetLimitList();
4699
4742
  init_budget();
4700
4743
  var MODULE_PATH = "/litellm";
@@ -4705,7 +4748,7 @@ var LEVEL = {
4705
4748
  };
4706
4749
  var DEFAULT_CTAS = ["new-key", "module", "all-limits"];
4707
4750
  var CTA_LABELS = {
4708
- "new-key": "New key",
4751
+ "new-key": "Generate New Key",
4709
4752
  module: "Open module",
4710
4753
  "all-limits": "All limits"
4711
4754
  };
@@ -4731,7 +4774,7 @@ var LevelGauge = ({
4731
4774
  const limit = gauge.limit;
4732
4775
  const tone = limit ? budgetTone2(limit.pct) : "neutral";
4733
4776
  const extra = gauge.kind === "key" ? Math.max(0, gauge.count - 1) : 0;
4734
- return /* @__PURE__ */ import_react15.default.createElement(
4777
+ return /* @__PURE__ */ import_react16.default.createElement(
4735
4778
  import_Box14.default,
4736
4779
  {
4737
4780
  sx: {
@@ -4742,7 +4785,7 @@ var LevelGauge = ({
4742
4785
  flex: 1
4743
4786
  }
4744
4787
  },
4745
- /* @__PURE__ */ import_react15.default.createElement(
4788
+ /* @__PURE__ */ import_react16.default.createElement(
4746
4789
  Gauge,
4747
4790
  {
4748
4791
  value: limit?.pct ?? 0,
@@ -4751,7 +4794,7 @@ var LevelGauge = ({
4751
4794
  label: limit ? `${Math.round(limit.pct)}%` : "\u2014"
4752
4795
  }
4753
4796
  ),
4754
- /* @__PURE__ */ import_react15.default.createElement(
4797
+ /* @__PURE__ */ import_react16.default.createElement(
4755
4798
  import_Typography14.default,
4756
4799
  {
4757
4800
  sx: (theme) => ({
@@ -4765,7 +4808,7 @@ var LevelGauge = ({
4765
4808
  },
4766
4809
  name
4767
4810
  ),
4768
- limit ? /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement(
4811
+ limit ? /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(
4769
4812
  import_Typography14.default,
4770
4813
  {
4771
4814
  variant: "caption",
@@ -4781,7 +4824,7 @@ var LevelGauge = ({
4781
4824
  }
4782
4825
  },
4783
4826
  limit.label
4784
- ), /* @__PURE__ */ import_react15.default.createElement(
4827
+ ), /* @__PURE__ */ import_react16.default.createElement(
4785
4828
  import_Typography14.default,
4786
4829
  {
4787
4830
  variant: "caption",
@@ -4793,10 +4836,10 @@ var LevelGauge = ({
4793
4836
  }
4794
4837
  },
4795
4838
  spendCaption(limit)
4796
- ), extra > 0 ? /* @__PURE__ */ import_react15.default.createElement(
4839
+ ), extra > 0 ? /* @__PURE__ */ import_react16.default.createElement(
4797
4840
  import_Typography14.default,
4798
4841
  {
4799
- component: import_core_components2.Link,
4842
+ component: import_core_components3.Link,
4800
4843
  to: keysHref,
4801
4844
  variant: "caption",
4802
4845
  sx: {
@@ -4809,7 +4852,7 @@ var LevelGauge = ({
4809
4852
  "+",
4810
4853
  extra,
4811
4854
  " more"
4812
- ) : /* @__PURE__ */ import_react15.default.createElement(import_Typography14.default, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, resetLabel(limit))) : /* @__PURE__ */ import_react15.default.createElement(
4855
+ ) : /* @__PURE__ */ import_react16.default.createElement(import_Typography14.default, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, resetLabel(limit))) : /* @__PURE__ */ import_react16.default.createElement(
4813
4856
  import_Typography14.default,
4814
4857
  {
4815
4858
  variant: "caption",
@@ -4820,6 +4863,125 @@ var LevelGauge = ({
4820
4863
  )
4821
4864
  );
4822
4865
  };
4866
+ function monthToDateRange(now = /* @__PURE__ */ new Date()) {
4867
+ const toDay = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(
4868
+ d.getDate()
4869
+ ).padStart(2, "0")}`;
4870
+ const start = new Date(now.getFullYear(), now.getMonth(), 1);
4871
+ return { startDate: toDay(start), endDate: toDay(now) };
4872
+ }
4873
+ var UsageMiniChart = ({ data, totalTokens, loading, height }) => {
4874
+ const renderPlot = () => {
4875
+ if (loading) {
4876
+ return /* @__PURE__ */ import_react16.default.createElement(import_Box14.default, { display: "flex", justifyContent: "center", alignItems: "center", height: "100%" }, /* @__PURE__ */ import_react16.default.createElement(import_CircularProgress8.default, { size: 20 }));
4877
+ }
4878
+ if (data.length === 0) {
4879
+ return /* @__PURE__ */ import_react16.default.createElement(
4880
+ import_Box14.default,
4881
+ {
4882
+ display: "flex",
4883
+ justifyContent: "center",
4884
+ alignItems: "center",
4885
+ height: "100%",
4886
+ sx: (theme) => ({ color: theme.palette.text.secondary, fontSize: 18 })
4887
+ },
4888
+ "\u2014"
4889
+ );
4890
+ }
4891
+ return /* @__PURE__ */ import_react16.default.createElement(import_recharts4.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react16.default.createElement(import_recharts4.AreaChart, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 } }, /* @__PURE__ */ import_react16.default.createElement(import_recharts4.Tooltip, { content: /* @__PURE__ */ import_react16.default.createElement(ChartTooltip, { valueFormatter: fmtInt }) }), /* @__PURE__ */ import_react16.default.createElement(
4892
+ import_recharts4.Area,
4893
+ {
4894
+ type: "monotone",
4895
+ dataKey: "input",
4896
+ name: "Input",
4897
+ stackId: "tok",
4898
+ stroke: SERIES.input,
4899
+ strokeWidth: 1.5,
4900
+ fill: SERIES.input,
4901
+ fillOpacity: 0.25,
4902
+ dot: false,
4903
+ isAnimationActive: false
4904
+ }
4905
+ ), /* @__PURE__ */ import_react16.default.createElement(
4906
+ import_recharts4.Area,
4907
+ {
4908
+ type: "monotone",
4909
+ dataKey: "output",
4910
+ name: "Output",
4911
+ stackId: "tok",
4912
+ stroke: SERIES.output,
4913
+ strokeWidth: 1.5,
4914
+ fill: SERIES.output,
4915
+ fillOpacity: 0.25,
4916
+ dot: false,
4917
+ isAnimationActive: false
4918
+ }
4919
+ )));
4920
+ };
4921
+ const renderCaption = () => {
4922
+ if (loading) {
4923
+ return /* @__PURE__ */ import_react16.default.createElement(import_Typography14.default, { variant: "caption", color: "text.secondary", sx: { mt: 0.25, fontSize: 11 } }, "\u2026");
4924
+ }
4925
+ if (data.length === 0) {
4926
+ return /* @__PURE__ */ import_react16.default.createElement(
4927
+ import_Typography14.default,
4928
+ {
4929
+ variant: "caption",
4930
+ color: "text.secondary",
4931
+ sx: { mt: 0.25, fontSize: 10.5, textAlign: "center" }
4932
+ },
4933
+ "No usage this month"
4934
+ );
4935
+ }
4936
+ return /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(
4937
+ import_Typography14.default,
4938
+ {
4939
+ variant: "caption",
4940
+ title: `${fmtInt(totalTokens)} tokens month to date`,
4941
+ sx: {
4942
+ mt: 0.25,
4943
+ fontSize: 11,
4944
+ fontWeight: 600,
4945
+ maxWidth: "100%",
4946
+ overflow: "hidden",
4947
+ textOverflow: "ellipsis",
4948
+ whiteSpace: "nowrap",
4949
+ fontVariantNumeric: "tabular-nums"
4950
+ }
4951
+ },
4952
+ fmtCompact(totalTokens),
4953
+ " tokens"
4954
+ ), /* @__PURE__ */ import_react16.default.createElement(import_Typography14.default, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 } }, "month to date"));
4955
+ };
4956
+ return /* @__PURE__ */ import_react16.default.createElement(
4957
+ import_Box14.default,
4958
+ {
4959
+ sx: {
4960
+ display: "flex",
4961
+ flexDirection: "column",
4962
+ alignItems: "center",
4963
+ minWidth: 0,
4964
+ flex: 1
4965
+ }
4966
+ },
4967
+ /* @__PURE__ */ import_react16.default.createElement(import_Box14.default, { sx: { height, width: "100%" } }, renderPlot()),
4968
+ /* @__PURE__ */ import_react16.default.createElement(
4969
+ import_Typography14.default,
4970
+ {
4971
+ sx: (theme) => ({
4972
+ mt: 0.75,
4973
+ fontSize: 10.5,
4974
+ fontWeight: 700,
4975
+ letterSpacing: "0.08em",
4976
+ textTransform: "uppercase",
4977
+ color: theme.palette.text.secondary
4978
+ })
4979
+ },
4980
+ "Usage"
4981
+ ),
4982
+ renderCaption()
4983
+ );
4984
+ };
4823
4985
  var LiteLLMBudgetGauges = ({
4824
4986
  title = "Budget",
4825
4987
  size = 72,
@@ -4834,60 +4996,83 @@ var LiteLLMBudgetGauges = ({
4834
4996
  action
4835
4997
  }) => {
4836
4998
  const api = (0, import_core_plugin_api6.useApi)(liteLlmApiRef);
4837
- const [loading, setLoading] = (0, import_react15.useState)(true);
4838
- const [error, setError] = (0, import_react15.useState)(null);
4839
- const [user, setUser] = (0, import_react15.useState)(null);
4840
- const [teams, setTeams] = (0, import_react15.useState)([]);
4841
- const [keys, setKeys] = (0, import_react15.useState)([]);
4999
+ const [loading, setLoading] = (0, import_react16.useState)(true);
5000
+ const [error, setError] = (0, import_react16.useState)(null);
5001
+ const [user, setUser] = (0, import_react16.useState)(null);
5002
+ const [teams, setTeams] = (0, import_react16.useState)([]);
5003
+ const [keys, setKeys] = (0, import_react16.useState)([]);
5004
+ const [usageLoading, setUsageLoading] = (0, import_react16.useState)(true);
5005
+ const [dailyTokens, setDailyTokens] = (0, import_react16.useState)([]);
5006
+ const [mtdTokens, setMtdTokens] = (0, import_react16.useState)(0);
4842
5007
  const isControlled = expanded !== void 0;
4843
- const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react15.useState)(defaultExpanded);
5008
+ const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react16.useState)(defaultExpanded);
4844
5009
  const isExpanded = isControlled ? expanded : uncontrolledExpanded;
4845
- const toggleExpanded = (0, import_react15.useCallback)(() => {
5010
+ const toggleExpanded = (0, import_react16.useCallback)(() => {
4846
5011
  const next = !isExpanded;
4847
5012
  if (!isControlled) setUncontrolledExpanded(next);
4848
5013
  onExpandedChange?.(next);
4849
5014
  }, [isControlled, isExpanded, onExpandedChange]);
4850
5015
  const keysTabHref = keysHref ?? `${moduleHref}?tab=keys`;
4851
- (0, import_react15.useEffect)(() => {
5016
+ (0, import_react16.useEffect)(() => {
4852
5017
  let cancelled = false;
4853
5018
  setLoading(true);
5019
+ setUsageLoading(true);
4854
5020
  setError(null);
4855
- Promise.allSettled([api.getUserInfo(), api.getTeams(), api.listKeys()]).then(
4856
- ([userResult, teamsResult, keysResult]) => {
4857
- if (cancelled) return;
4858
- if (userResult.status === "fulfilled") {
4859
- setUser(userResult.value);
4860
- } else {
4861
- setUser(null);
4862
- setError(
4863
- userResult.reason?.message ?? "Failed to load your LiteLLM profile"
4864
- );
4865
- }
4866
- setTeams(teamsResult.status === "fulfilled" ? teamsResult.value : []);
4867
- setKeys(keysResult.status === "fulfilled" ? keysResult.value : []);
4868
- setLoading(false);
5021
+ const { startDate, endDate } = monthToDateRange();
5022
+ Promise.allSettled([
5023
+ api.getUserInfo(),
5024
+ api.getTeams(),
5025
+ api.listKeys(),
5026
+ api.getUsage(startDate, endDate)
5027
+ ]).then(([userResult, teamsResult, keysResult, usageResult]) => {
5028
+ if (cancelled) return;
5029
+ if (userResult.status === "fulfilled") {
5030
+ setUser(userResult.value);
5031
+ } else {
5032
+ setUser(null);
5033
+ setError(
5034
+ userResult.reason?.message ?? "Failed to load your LiteLLM profile"
5035
+ );
4869
5036
  }
4870
- );
5037
+ setTeams(teamsResult.status === "fulfilled" ? teamsResult.value : []);
5038
+ setKeys(keysResult.status === "fulfilled" ? keysResult.value : []);
5039
+ setLoading(false);
5040
+ if (usageResult.status === "fulfilled") {
5041
+ const daily = usageResult.value.daily_usage ?? [];
5042
+ setDailyTokens(
5043
+ daily.map((d) => ({
5044
+ date: d.date,
5045
+ input: d.prompt_tokens,
5046
+ output: d.completion_tokens
5047
+ }))
5048
+ );
5049
+ setMtdTokens(usageResult.value.total_tokens ?? 0);
5050
+ } else {
5051
+ setDailyTokens([]);
5052
+ setMtdTokens(0);
5053
+ }
5054
+ setUsageLoading(false);
5055
+ });
4871
5056
  return () => {
4872
5057
  cancelled = true;
4873
5058
  };
4874
5059
  }, [api]);
4875
- const summary = (0, import_react15.useMemo)(
5060
+ const summary = (0, import_react16.useMemo)(
4876
5061
  () => buildBudgetSummary(user, teams, keys, keys.length),
4877
5062
  [user, teams, keys]
4878
5063
  );
4879
- const gauges = (0, import_react15.useMemo)(() => buildBudgetGauges(summary), [summary]);
4880
- const headline = (0, import_react15.useMemo)(() => budgetHeadline(summary), [summary]);
4881
- const expandedSummary = (0, import_react15.useMemo)(
5064
+ const gauges = (0, import_react16.useMemo)(() => buildBudgetGauges(summary), [summary]);
5065
+ const headline = (0, import_react16.useMemo)(() => budgetHeadline(summary), [summary]);
5066
+ const expandedSummary = (0, import_react16.useMemo)(
4882
5067
  () => buildBudgetSummary(user, teams, keys, maxExpandedKeys),
4883
5068
  [user, teams, keys, maxExpandedKeys]
4884
5069
  );
4885
- const expandedLimits = (0, import_react15.useMemo)(
5070
+ const expandedLimits = (0, import_react16.useMemo)(
4886
5071
  () => allBudgetLimits(expandedSummary),
4887
5072
  [expandedSummary]
4888
5073
  );
4889
5074
  const summaryText = headline.count === 0 ? "no limits apply" : `${headline.count} limit${headline.count === 1 ? "" : "s"}`;
4890
- const resolvedCtas = (0, import_react15.useMemo)(() => {
5075
+ const resolvedCtas = (0, import_react16.useMemo)(() => {
4891
5076
  const list = ctas ?? DEFAULT_CTAS;
4892
5077
  return list.map((cta) => typeof cta === "string" ? { kind: cta } : cta).filter((cta) => cta.kind !== "all-limits" || headline.count > 0);
4893
5078
  }, [ctas, headline.count]);
@@ -4896,28 +5081,18 @@ var LiteLLMBudgetGauges = ({
4896
5081
  const key = `${cta.kind}-${index}`;
4897
5082
  switch (cta.kind) {
4898
5083
  case "new-key":
4899
- return onCreateKey ? /* @__PURE__ */ import_react15.default.createElement(import_Button6.default, { key, size: "small", variant: "contained", onClick: onCreateKey }, label) : /* @__PURE__ */ import_react15.default.createElement(
4900
- import_Button6.default,
4901
- {
4902
- key,
4903
- size: "small",
4904
- variant: "contained",
4905
- component: import_core_components2.Link,
4906
- to: `${moduleHref}?generate=1`
4907
- },
4908
- label
4909
- );
5084
+ return onCreateKey ? /* @__PURE__ */ import_react16.default.createElement(GenerateKeyButton, { key, size: "small", label, onClick: onCreateKey }) : /* @__PURE__ */ import_react16.default.createElement(GenerateKeyButton, { key, size: "small", label, to: `${moduleHref}?generate=1` });
4910
5085
  case "module":
4911
- return /* @__PURE__ */ import_react15.default.createElement(import_Button6.default, { key, size: "small", variant: "outlined", component: import_core_components2.Link, to: moduleHref }, label);
5086
+ return /* @__PURE__ */ import_react16.default.createElement(import_Button6.default, { key, size: "small", variant: "outlined", component: import_core_components3.Link, to: moduleHref }, label);
4912
5087
  case "all-limits":
4913
- return /* @__PURE__ */ import_react15.default.createElement(
5088
+ return /* @__PURE__ */ import_react16.default.createElement(
4914
5089
  import_Button6.default,
4915
5090
  {
4916
5091
  key,
4917
5092
  size: "small",
4918
5093
  variant: "text",
4919
5094
  onClick: toggleExpanded,
4920
- endIcon: /* @__PURE__ */ import_react15.default.createElement(
5095
+ endIcon: /* @__PURE__ */ import_react16.default.createElement(
4921
5096
  import_icons_material10.ExpandMore,
4922
5097
  {
4923
5098
  sx: {
@@ -4935,14 +5110,22 @@ var LiteLLMBudgetGauges = ({
4935
5110
  }
4936
5111
  };
4937
5112
  const hasFooter = resolvedCtas.length > 0 || !!action;
4938
- return /* @__PURE__ */ import_react15.default.createElement(import_Paper10.default, { sx: { p: 2 } }, /* @__PURE__ */ import_react15.default.createElement(import_Box14.default, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1.5, minWidth: 0 } }, /* @__PURE__ */ import_react15.default.createElement(import_Typography14.default, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 } }, title), !loading && !error && /* @__PURE__ */ import_react15.default.createElement(
5113
+ return /* @__PURE__ */ import_react16.default.createElement(import_Paper10.default, { sx: { p: 2 } }, /* @__PURE__ */ import_react16.default.createElement(import_Box14.default, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1.5, minWidth: 0 } }, /* @__PURE__ */ import_react16.default.createElement(import_Typography14.default, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 } }, title), !loading && !error && /* @__PURE__ */ import_react16.default.createElement(
4939
5114
  StatusPill,
4940
5115
  {
4941
5116
  label: summaryText,
4942
5117
  tone: budgetTone2(headline.closest?.pct ?? 0),
4943
5118
  dot: headline.count > 0
4944
5119
  }
4945
- )), loading && /* @__PURE__ */ import_react15.default.createElement(import_Box14.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 110 }, /* @__PURE__ */ import_react15.default.createElement(import_CircularProgress8.default, { size: 28 })), !loading && error && /* @__PURE__ */ import_react15.default.createElement(import_Alert8.default, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && /* @__PURE__ */ import_react15.default.createElement(import_react15.default.Fragment, null, /* @__PURE__ */ import_react15.default.createElement(import_Box14.default, { sx: { display: "flex", alignItems: "flex-start", gap: 1 } }, gauges.map((gauge) => /* @__PURE__ */ import_react15.default.createElement(LevelGauge, { key: gauge.kind, gauge, size, keysHref: keysTabHref }))), /* @__PURE__ */ import_react15.default.createElement(import_Collapse4.default, { in: isExpanded, unmountOnExit: true }, /* @__PURE__ */ import_react15.default.createElement(
5120
+ )), loading && /* @__PURE__ */ import_react16.default.createElement(import_Box14.default, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: 110 }, /* @__PURE__ */ import_react16.default.createElement(import_CircularProgress8.default, { size: 28 })), !loading && error && /* @__PURE__ */ import_react16.default.createElement(import_Alert8.default, { severity: "error", sx: { mt: 0.5 } }, error), !loading && !error && /* @__PURE__ */ import_react16.default.createElement(import_react16.default.Fragment, null, /* @__PURE__ */ import_react16.default.createElement(import_Box14.default, { sx: { display: "flex", alignItems: "flex-start", gap: 1 } }, gauges.map((gauge) => /* @__PURE__ */ import_react16.default.createElement(LevelGauge, { key: gauge.kind, gauge, size, keysHref: keysTabHref })), /* @__PURE__ */ import_react16.default.createElement(
5121
+ UsageMiniChart,
5122
+ {
5123
+ data: dailyTokens,
5124
+ totalTokens: mtdTokens,
5125
+ loading: usageLoading,
5126
+ height: size
5127
+ }
5128
+ )), /* @__PURE__ */ import_react16.default.createElement(import_Collapse4.default, { in: isExpanded, unmountOnExit: true }, /* @__PURE__ */ import_react16.default.createElement(
4946
5129
  import_Box14.default,
4947
5130
  {
4948
5131
  sx: {
@@ -4953,7 +5136,7 @@ var LiteLLMBudgetGauges = ({
4953
5136
  overflowY: "auto"
4954
5137
  }
4955
5138
  },
4956
- /* @__PURE__ */ import_react15.default.createElement(LimitListPanel, null, /* @__PURE__ */ import_react15.default.createElement(
5139
+ /* @__PURE__ */ import_react16.default.createElement(LimitListPanel, null, /* @__PURE__ */ import_react16.default.createElement(
4957
5140
  BudgetLimitList,
4958
5141
  {
4959
5142
  limits: expandedLimits,
@@ -4961,7 +5144,7 @@ var LiteLLMBudgetGauges = ({
4961
5144
  keysHref: keysTabHref
4962
5145
  }
4963
5146
  ))
4964
- ))), hasFooter && /* @__PURE__ */ import_react15.default.createElement(
5147
+ ))), hasFooter && /* @__PURE__ */ import_react16.default.createElement(
4965
5148
  import_Box14.default,
4966
5149
  {
4967
5150
  sx: (theme) => ({
@@ -4981,11 +5164,12 @@ var LiteLLMBudgetGauges = ({
4981
5164
 
4982
5165
  // src/index.ts
4983
5166
  init_KeyFormDialog();
5167
+ init_GenerateKeyButton();
4984
5168
 
4985
5169
  // src/components/GenerateKeyDialog.tsx
4986
- var import_react16 = __toESM(require("react"));
5170
+ var import_react17 = __toESM(require("react"));
4987
5171
  init_KeyFormDialog();
4988
- var GenerateKeyDialog = (props) => /* @__PURE__ */ import_react16.default.createElement(
5172
+ var GenerateKeyDialog = (props) => /* @__PURE__ */ import_react17.default.createElement(
4989
5173
  KeyFormDialog,
4990
5174
  {
4991
5175
  open: props.open,