@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/api.d.ts +0 -2
- package/dist/components/KeysTable.d.ts +0 -1
- package/dist/index.cjs.js +24 -96
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.esm.js +24 -96
- package/dist/index.esm.js.map +2 -2
- package/dist/types.d.ts +1 -4
- package/package.json +1 -1
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
|
-
|
|
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
|
-
)
|
|
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: !!
|
|
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,
|
|
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
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
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,
|