@acarmisc/backstage-plugin-litellm 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.esm.js CHANGED
@@ -50,7 +50,8 @@ var init_api = __esm({
50
50
  } catch {
51
51
  body = await response.text().catch(() => "");
52
52
  }
53
- throw new ApiError(`${response.status} ${response.statusText}`, response.status, body);
53
+ const message = (typeof body === "object" && body && typeof body.error === "string" ? body.error : void 0) ?? `${response.status} ${response.statusText}`;
54
+ throw new ApiError(message, response.status, body);
54
55
  }
55
56
  }
56
57
  async get(path, params) {
@@ -96,9 +97,6 @@ var init_api = __esm({
96
97
  async deleteKey(keyId) {
97
98
  return this.del(`/keys/${encodeURIComponent(keyId)}`);
98
99
  }
99
- async rotateKey(keyId) {
100
- return this.post(`/keys/${encodeURIComponent(keyId)}/regenerate`, {});
101
- }
102
100
  async blockKey(keyId) {
103
101
  await this.post(`/keys/${encodeURIComponent(keyId)}/block`, {});
104
102
  }
@@ -316,9 +314,7 @@ var init_KeysTable = __esm({
316
314
  tpm_limit: void 0,
317
315
  rpm_limit: void 0,
318
316
  team_id: void 0,
319
- key_type: "llm_api",
320
- auto_rotate: false,
321
- rotation_interval_days: void 0
317
+ key_type: "llm_api"
322
318
  });
323
319
  keyToEditForm = (k) => ({
324
320
  key_alias: k.key_alias ?? "",
@@ -334,7 +330,6 @@ var init_KeysTable = __esm({
334
330
  loading,
335
331
  onGenerateKey,
336
332
  onUpdateKey,
337
- onRotateKey,
338
333
  onBlockKey,
339
334
  onUnblockKey,
340
335
  onResetKeySpend,
@@ -352,8 +347,6 @@ var init_KeysTable = __esm({
352
347
  const [editingKey, setEditingKey] = useState(null);
353
348
  const [editForm, setEditForm] = useState({});
354
349
  const [editSubmitting, setEditSubmitting] = useState(false);
355
- const [rotatingKeyId, setRotatingKeyId] = useState(null);
356
- const [rotatedKeyValue, setRotatedKeyValue] = useState(null);
357
350
  const [blockingKeyId, setBlockingKeyId] = useState(null);
358
351
  const [deleteConfirmId, setDeleteConfirmId] = useState(null);
359
352
  const [deleteSubmitting, setDeleteSubmitting] = useState(false);
@@ -433,17 +426,6 @@ var init_KeysTable = __esm({
433
426
  setEditSubmitting(false);
434
427
  }
435
428
  };
436
- const handleRotate = async (keyId) => {
437
- setRotatingKeyId(keyId);
438
- try {
439
- const response = await onRotateKey(keyId);
440
- setRotatedKeyValue(response.key);
441
- } catch (error) {
442
- console.error("Failed to rotate key:", error);
443
- } finally {
444
- setRotatingKeyId(null);
445
- }
446
- };
447
429
  const handleToggleBlock = async (key) => {
448
430
  const keyId = key.token ?? key.key;
449
431
  setBlockingKeyId(keyId);
@@ -548,7 +530,6 @@ var init_KeysTable = __esm({
548
530
  "Generate Your First Key"
549
531
  )))) : filteredKeys.map((key) => {
550
532
  const keyId = key.token ?? key.key;
551
- const isRotating = rotatingKeyId === keyId;
552
533
  const isBlocking = blockingKeyId === keyId;
553
534
  return /* @__PURE__ */ React2.createElement(TableRow, { key: keyId, sx: key.blocked ? { bgcolor: "action.disabledBackground" } : void 0 }, /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", alignItems: "center", gap: 0.5 }, key.key_alias || "-", key.blocked && /* @__PURE__ */ React2.createElement(Chip2, { label: "Blocked", color: "error", size: "small" }))), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React2.createElement(
554
535
  Typography2,
@@ -567,14 +548,6 @@ var init_KeysTable = __esm({
567
548
  },
568
549
  shortKeyId(keyId)
569
550
  ), /* @__PURE__ */ React2.createElement(IconButton, { size: "small", onClick: () => copyToClipboard(keyId), title: "Copy Key ID" }, /* @__PURE__ */ React2.createElement(ContentCopy, { fontSize: "small" })))), /* @__PURE__ */ React2.createElement(TableCell, null, formatDate(key.created_at)), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(ExpiryChip, { expiresAt: key.expires_at })), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(BudgetCell, { spend: key.spend ?? 0, maxBudget: key.max_budget })), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2" }, key.tpm_limit ?? "-", " / ", key.rpm_limit ?? "-")), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", gap: 0.5, flexWrap: "wrap" }, key.models?.slice(0, 2).map((model) => /* @__PURE__ */ React2.createElement(Chip2, { key: model, label: model, size: "small" })), (key.models?.length || 0) > 2 && /* @__PURE__ */ React2.createElement(Chip2, { label: `+${(key.models?.length || 0) - 2}`, size: "small", variant: "outlined" }))), /* @__PURE__ */ React2.createElement(TableCell, { align: "right" }, /* @__PURE__ */ React2.createElement(IconButton, { onClick: () => handleOpenEdit(key), title: "Edit key" }, /* @__PURE__ */ React2.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React2.createElement(
570
- IconButton,
571
- {
572
- onClick: () => handleRotate(keyId),
573
- disabled: isRotating,
574
- title: "Rotate key \u2014 generates a new secret, same settings"
575
- },
576
- isRotating ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 18 }) : /* @__PURE__ */ React2.createElement(Autorenew, { fontSize: "small" })
577
- ), /* @__PURE__ */ React2.createElement(
578
551
  IconButton,
579
552
  {
580
553
  onClick: () => handleToggleBlock(key),
@@ -721,36 +694,7 @@ var init_KeysTable = __esm({
721
694
  onChange: (e) => setFormData({ ...formData, rpm_limit: e.target.value ? Number(e.target.value) : void 0 }),
722
695
  fullWidth: true
723
696
  }
724
- ), /* @__PURE__ */ React2.createElement(
725
- FormControlLabel,
726
- {
727
- control: /* @__PURE__ */ React2.createElement(
728
- Checkbox,
729
- {
730
- checked: !!formData.auto_rotate,
731
- onChange: (e) => setFormData({
732
- ...formData,
733
- auto_rotate: e.target.checked,
734
- rotation_interval_days: e.target.checked ? formData.rotation_interval_days ?? 90 : void 0
735
- })
736
- }
737
- ),
738
- label: "Auto-rotate (LiteLLM rotates the secret on a schedule)"
739
- }
740
- ), formData.auto_rotate && /* @__PURE__ */ React2.createElement(
741
- TextField,
742
- {
743
- label: "Rotate every (days)",
744
- type: "number",
745
- value: formData.rotation_interval_days ?? "",
746
- onChange: (e) => setFormData({
747
- ...formData,
748
- rotation_interval_days: e.target.value ? Number(e.target.value) : void 0
749
- }),
750
- helperText: "LiteLLM enforces this interval server-side; the old secret stops working the moment it rotates.",
751
- fullWidth: true
752
- }
753
- ))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal }, newKeyValue ? "Done" : "Cancel"), !newKeyValue && /* @__PURE__ */ React2.createElement(
697
+ ))), /* @__PURE__ */ React2.createElement(DialogActions, null, newKeyValue ? /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal, variant: "contained", color: "success" }, "Done") : /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal }, "Cancel"), /* @__PURE__ */ React2.createElement(
754
698
  Button,
755
699
  {
756
700
  onClick: handleGenerate,
@@ -759,7 +703,7 @@ var init_KeysTable = __esm({
759
703
  disabled: !canGenerate
760
704
  },
761
705
  submitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }) : "Generate"
762
- ), newKeyValue && /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseModal, variant: "contained", color: "success" }, "Done"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!editingKey, onClose: handleCloseEdit, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Edit Key"), /* @__PURE__ */ React2.createElement(DialogContent, null, editingKey && /* @__PURE__ */ React2.createElement(Box2, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ React2.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editingKey.key))), /* @__PURE__ */ React2.createElement(
706
+ )))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!editingKey, onClose: handleCloseEdit, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Edit Key"), /* @__PURE__ */ React2.createElement(DialogContent, null, editingKey && /* @__PURE__ */ React2.createElement(Box2, { display: "flex", flexDirection: "column", gap: 2, mt: 1 }, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary" }, /* @__PURE__ */ React2.createElement("code", { style: { fontFamily: "monospace", color: "inherit" } }, maskKey(editingKey.key))), /* @__PURE__ */ React2.createElement(
763
707
  TextField,
764
708
  {
765
709
  label: "Alias",
@@ -825,26 +769,7 @@ var init_KeysTable = __esm({
825
769
  onClick: handleResetSpend
826
770
  },
827
771
  resetSpendSubmitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 16 }) : "Confirm"
828
- ), /* @__PURE__ */ React2.createElement(Button, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel"))))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseEdit }, "Cancel"), /* @__PURE__ */ React2.createElement(Button, { onClick: handleUpdate, variant: "contained", color: "primary", disabled: editSubmitting }, editSubmitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }) : "Save"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!rotatedKeyValue, onClose: () => setRotatedKeyValue(null), maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Key Rotated"), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary", gutterBottom: true }, "The old secret is now invalid. Copy the new one \u2014 you won't see it again."), /* @__PURE__ */ React2.createElement(
829
- Box2,
830
- {
831
- display: "flex",
832
- alignItems: "center",
833
- gap: 1,
834
- mt: 2,
835
- p: 2,
836
- sx: { backgroundColor: "action.hover", border: "1px solid", borderColor: "divider", borderRadius: 1 }
837
- },
838
- /* @__PURE__ */ React2.createElement(
839
- Typography2,
840
- {
841
- component: "code",
842
- sx: { fontFamily: "monospace", wordBreak: "break-all", flex: 1 }
843
- },
844
- rotatedKeyValue
845
- ),
846
- /* @__PURE__ */ React2.createElement(IconButton, { onClick: () => copyToClipboard(rotatedKeyValue) }, /* @__PURE__ */ React2.createElement(ContentCopy, null))
847
- )), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: () => setRotatedKeyValue(null), variant: "contained", color: "success" }, "Done"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Typography2, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ React2.createElement(
772
+ ), /* @__PURE__ */ React2.createElement(Button, { size: "small", onClick: () => setResetSpendConfirm(false) }, "Cancel"))))), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: handleCloseEdit }, "Cancel"), /* @__PURE__ */ React2.createElement(Button, { onClick: handleUpdate, variant: "contained", color: "primary", disabled: editSubmitting }, editSubmitting ? /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }) : "Save"))), /* @__PURE__ */ React2.createElement(Dialog, { open: !!deleteConfirmId, onClose: () => setDeleteConfirmId(null), maxWidth: "xs", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, "Revoke Key?"), /* @__PURE__ */ React2.createElement(DialogContent, null, /* @__PURE__ */ React2.createElement(Typography2, null, "This will permanently revoke the key. Any integrations using it will stop working immediately.")), /* @__PURE__ */ React2.createElement(DialogActions, null, /* @__PURE__ */ React2.createElement(Button, { onClick: () => setDeleteConfirmId(null), disabled: deleteSubmitting }, "Cancel"), /* @__PURE__ */ React2.createElement(
848
773
  Button,
849
774
  {
850
775
  onClick: handleConfirmDelete,
@@ -1246,7 +1171,15 @@ var init_TeamUsage = __esm({
1246
1171
  color: isOver ? "error" : isNear ? "warning" : "primary",
1247
1172
  sx: { height: 6, borderRadius: 1 }
1248
1173
  }
1249
- )), /* @__PURE__ */ React4.createElement(Collapse, { in: expanded }, /* @__PURE__ */ React4.createElement(Box4, { mt: 2 }, /* @__PURE__ */ React4.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ React4.createElement(Speed, { fontSize: "small", color: "action" }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary" }, "Rate limits")), /* @__PURE__ */ React4.createElement(Stack, { direction: "row", spacing: 3, flexWrap: "wrap", useFlexGap: true, gap: 1.5, mb: 2 }, /* @__PURE__ */ React4.createElement(Stat, { label: "TPM limit", value: team.tpm_limit != null && team.tpm_limit > 0 ? String(team.tpm_limit) : "Unlimited" }), /* @__PURE__ */ React4.createElement(Stat, { label: "RPM limit", value: team.rpm_limit != null && team.rpm_limit > 0 ? String(team.rpm_limit) : "Unlimited" }), /* @__PURE__ */ React4.createElement(Stat, { label: "Max budget", value: budget > 0 ? `$${budget.toFixed(2)}` : "Unlimited" })), /* @__PURE__ */ React4.createElement(Divider, { sx: { mb: 2 } }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Models"), team.models?.length ? /* @__PURE__ */ React4.createElement(Box4, { display: "flex", gap: 0.5, flexWrap: "wrap", mb: 2 }, team.models.map((m) => /* @__PURE__ */ React4.createElement(Chip4, { key: m, label: m, size: "small", variant: "outlined" }))) : /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", color: "text.secondary", mb: 2 }, "All models allowed"), /* @__PURE__ */ React4.createElement(Divider, { sx: { mb: 2 } }), usageLoading ? /* @__PURE__ */ React4.createElement(Box4, { display: "flex", justifyContent: "center", p: 2 }, /* @__PURE__ */ React4.createElement(CircularProgress2, { size: 24 })) : dailyData.length > 0 ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Spend"), /* @__PURE__ */ React4.createElement(Box4, { height: 160, mb: 2 }, /* @__PURE__ */ React4.createElement(ResponsiveContainer2, { width: "100%", height: "100%" }, /* @__PURE__ */ React4.createElement(AreaChart2, { data: dailyData }, /* @__PURE__ */ React4.createElement(CartesianGrid2, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ React4.createElement(XAxis2, { dataKey: "date", tick: { fontSize: 11, fill: tickFill } }), /* @__PURE__ */ React4.createElement(YAxis2, { tick: { fontSize: 11, fill: tickFill }, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ React4.createElement(Tooltip2, { formatter: (v) => [`$${v.toFixed(4)}`, "Spend"] }), /* @__PURE__ */ React4.createElement(Area2, { type: "monotone", dataKey: "spend", stroke: "#8884d8", fill: "#8884d8", fillOpacity: 0.3 })))), /* @__PURE__ */ React4.createElement(Divider, { sx: { mb: 2 } })) : null, /* @__PURE__ */ React4.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ React4.createElement(Memory, { fontSize: "small", color: "action" }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary" }, "Members")), team.members_with_roles?.length ? /* @__PURE__ */ React4.createElement(TableContainer3, null, /* @__PURE__ */ React4.createElement(Table3, { size: "small" }, /* @__PURE__ */ React4.createElement(TableHead3, null, /* @__PURE__ */ React4.createElement(TableRow3, null, /* @__PURE__ */ React4.createElement(TableCell3, null, "User"), /* @__PURE__ */ React4.createElement(TableCell3, null, "Role"))), /* @__PURE__ */ React4.createElement(TableBody3, null, team.members_with_roles.map((m) => /* @__PURE__ */ React4.createElement(TableRow3, { key: m.user_id }, /* @__PURE__ */ React4.createElement(TableCell3, { sx: { fontFamily: "monospace", fontSize: 12 } }, m.user_id), /* @__PURE__ */ React4.createElement(TableCell3, null, /* @__PURE__ */ React4.createElement(
1174
+ )), /* @__PURE__ */ React4.createElement(Collapse, { in: expanded }, /* @__PURE__ */ React4.createElement(Box4, { mt: 2 }, /* @__PURE__ */ React4.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ React4.createElement(Speed, { fontSize: "small", color: "action" }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary" }, "Rate limits")), /* @__PURE__ */ React4.createElement(Stack, { direction: "row", spacing: 3, flexWrap: "wrap", useFlexGap: true, gap: 1.5, mb: 2 }, /* @__PURE__ */ React4.createElement(Stat, { label: "TPM limit", value: team.tpm_limit != null && team.tpm_limit > 0 ? String(team.tpm_limit) : "Unlimited" }), /* @__PURE__ */ React4.createElement(Stat, { label: "RPM limit", value: team.rpm_limit != null && team.rpm_limit > 0 ? String(team.rpm_limit) : "Unlimited" }), /* @__PURE__ */ React4.createElement(Stat, { label: "Max budget", value: budget > 0 ? `$${budget.toFixed(2)}` : "Unlimited" })), /* @__PURE__ */ React4.createElement(Divider, { sx: { mb: 2 } }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Models"), team.models?.length ? /* @__PURE__ */ React4.createElement(Box4, { display: "flex", gap: 0.5, flexWrap: "wrap", mb: 2 }, team.models.map((m) => /* @__PURE__ */ React4.createElement(Chip4, { key: m, label: m, size: "small", variant: "outlined" }))) : /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", color: "text.secondary", mb: 2 }, "All models allowed"), /* @__PURE__ */ React4.createElement(Divider, { sx: { mb: 2 } }), usageLoading ? /* @__PURE__ */ React4.createElement(Box4, { display: "flex", justifyContent: "center", p: 2 }, /* @__PURE__ */ React4.createElement(CircularProgress2, { size: 24 })) : dailyData.length > 0 ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Spend"), /* @__PURE__ */ React4.createElement(Box4, { height: 160, mb: 2 }, /* @__PURE__ */ React4.createElement(ResponsiveContainer2, { width: "100%", height: "100%" }, /* @__PURE__ */ React4.createElement(AreaChart2, { data: dailyData }, /* @__PURE__ */ React4.createElement(CartesianGrid2, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ React4.createElement(XAxis2, { dataKey: "date", tick: { fontSize: 11, fill: tickFill } }), /* @__PURE__ */ React4.createElement(YAxis2, { tick: { fontSize: 11, fill: tickFill }, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ React4.createElement(Tooltip2, { formatter: (v) => [`$${v.toFixed(4)}`, "Spend"] }), /* @__PURE__ */ React4.createElement(Area2, { type: "monotone", dataKey: "spend", stroke: "#8884d8", fill: "#8884d8", fillOpacity: 0.3 })))), /* @__PURE__ */ React4.createElement(Divider, { sx: { mb: 2 } })) : null, /* @__PURE__ */ React4.createElement(Box4, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ React4.createElement(Memory, { fontSize: "small", color: "action" }), /* @__PURE__ */ React4.createElement(Typography4, { variant: "subtitle2", color: "text.secondary" }, "Members")), team.members_with_roles?.length ? /* @__PURE__ */ React4.createElement(TableContainer3, null, /* @__PURE__ */ React4.createElement(Table3, { size: "small" }, /* @__PURE__ */ React4.createElement(TableHead3, null, /* @__PURE__ */ React4.createElement(TableRow3, null, /* @__PURE__ */ React4.createElement(TableCell3, null, "User"), /* @__PURE__ */ React4.createElement(TableCell3, null, "Role"))), /* @__PURE__ */ React4.createElement(TableBody3, null, team.members_with_roles.map((m) => /* @__PURE__ */ React4.createElement(TableRow3, { key: m.user_id }, /* @__PURE__ */ React4.createElement(TableCell3, null, m.user_email ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2" }, m.user_email), /* @__PURE__ */ React4.createElement(
1175
+ Typography4,
1176
+ {
1177
+ variant: "caption",
1178
+ color: "text.secondary",
1179
+ sx: { fontFamily: "monospace" }
1180
+ },
1181
+ m.user_id
1182
+ )) : /* @__PURE__ */ React4.createElement(Typography4, { variant: "body2", sx: { fontFamily: "monospace" } }, m.user_id)), /* @__PURE__ */ React4.createElement(TableCell3, null, /* @__PURE__ */ React4.createElement(
1250
1183
  Chip4,
1251
1184
  {
1252
1185
  label: m.role,
@@ -1528,10 +1461,15 @@ var init_LiteLLMPage = __esm({
1528
1461
  }, [allModels, userInfo, teams]);
1529
1462
  const handleGenerateKey = useCallback2(
1530
1463
  async (request) => {
1531
- const response = await api.generateKey(request);
1532
- setSnackbar({ message: "Key generated successfully", severity: "success" });
1533
- refreshKeys();
1534
- return response;
1464
+ try {
1465
+ const response = await api.generateKey(request);
1466
+ setSnackbar({ message: "Key generated successfully", severity: "success" });
1467
+ refreshKeys();
1468
+ return response;
1469
+ } catch (e) {
1470
+ setSnackbar({ message: `Failed to generate key: ${e.message}`, severity: "error" });
1471
+ throw e;
1472
+ }
1535
1473
  },
1536
1474
  [api, refreshKeys]
1537
1475
  );
@@ -1584,15 +1522,6 @@ var init_LiteLLMPage = __esm({
1584
1522
  },
1585
1523
  [api, refreshKeys]
1586
1524
  );
1587
- const handleRotateKey = useCallback2(
1588
- async (keyId) => {
1589
- const response = await api.rotateKey(keyId);
1590
- setSnackbar({ message: "Key rotated \u2014 copy the new secret now", severity: "success" });
1591
- refreshKeys();
1592
- return response;
1593
- },
1594
- [api, refreshKeys]
1595
- );
1596
1525
  const handleDeleteKey = useCallback2(
1597
1526
  async (keyId) => {
1598
1527
  try {
@@ -1662,7 +1591,6 @@ var init_LiteLLMPage = __esm({
1662
1591
  loading: keysLoading || modelsLoading,
1663
1592
  onGenerateKey: handleGenerateKey,
1664
1593
  onUpdateKey: handleUpdateKey,
1665
- onRotateKey: handleRotateKey,
1666
1594
  onBlockKey: handleBlockKey,
1667
1595
  onUnblockKey: handleUnblockKey,
1668
1596
  onResetKeySpend: handleResetKeySpend,