@acarmisc/backstage-plugin-litellm 0.3.0 → 0.3.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.cjs.js +33 -41
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.esm.js +37 -45
- package/dist/index.esm.js.map +3 -3
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -143,7 +143,7 @@ var init_DashboardHeader = __esm({
|
|
|
143
143
|
});
|
|
144
144
|
|
|
145
145
|
// src/components/KeysTable.tsx
|
|
146
|
-
import React2, {
|
|
146
|
+
import React2, { useState } from "react";
|
|
147
147
|
import {
|
|
148
148
|
Paper as Paper2,
|
|
149
149
|
Table,
|
|
@@ -166,8 +166,8 @@ import {
|
|
|
166
166
|
CircularProgress,
|
|
167
167
|
Autocomplete
|
|
168
168
|
} from "@mui/material";
|
|
169
|
-
import { ContentCopy, Delete, Add, Edit
|
|
170
|
-
var maskKey, formatDate, emptyForm, keyToEditForm, KeysTable;
|
|
169
|
+
import { ContentCopy, Delete, Add, Edit } from "@mui/icons-material";
|
|
170
|
+
var maskKey, shortKeyId, formatDate, emptyForm, keyToEditForm, KeysTable;
|
|
171
171
|
var init_KeysTable = __esm({
|
|
172
172
|
"src/components/KeysTable.tsx"() {
|
|
173
173
|
"use strict";
|
|
@@ -175,6 +175,11 @@ var init_KeysTable = __esm({
|
|
|
175
175
|
if (key.length <= 8) return "***";
|
|
176
176
|
return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
|
177
177
|
};
|
|
178
|
+
shortKeyId = (token) => {
|
|
179
|
+
if (!token) return "-";
|
|
180
|
+
if (token.length <= 16) return token;
|
|
181
|
+
return `${token.slice(0, 12)}\u2026`;
|
|
182
|
+
};
|
|
178
183
|
formatDate = (dateStr) => {
|
|
179
184
|
try {
|
|
180
185
|
return new Date(dateStr).toLocaleDateString();
|
|
@@ -186,7 +191,7 @@ var init_KeysTable = __esm({
|
|
|
186
191
|
alias: "",
|
|
187
192
|
models: [],
|
|
188
193
|
duration: "30d",
|
|
189
|
-
max_budget:
|
|
194
|
+
max_budget: 100,
|
|
190
195
|
tpm_limit: void 0,
|
|
191
196
|
team_id: void 0,
|
|
192
197
|
key_type: "llm_api"
|
|
@@ -208,16 +213,9 @@ var init_KeysTable = __esm({
|
|
|
208
213
|
onDeleteKey
|
|
209
214
|
}) => {
|
|
210
215
|
const [generateModalOpen, setGenerateModalOpen] = useState(false);
|
|
211
|
-
const [showKeyValue, setShowKeyValue] = useState(null);
|
|
212
216
|
const [newKeyValue, setNewKeyValue] = useState(null);
|
|
213
217
|
const [formData, setFormData] = useState(emptyForm());
|
|
214
218
|
const [submitting, setSubmitting] = useState(false);
|
|
215
|
-
useEffect(() => {
|
|
216
|
-
if (!generateModalOpen) return;
|
|
217
|
-
if (!formData.team_id && teams.length > 0) {
|
|
218
|
-
setFormData((f) => ({ ...f, team_id: teams[0].team_id }));
|
|
219
|
-
}
|
|
220
|
-
}, [generateModalOpen, teams, formData.team_id]);
|
|
221
219
|
const canGenerate = true;
|
|
222
220
|
const [editingKey, setEditingKey] = useState(null);
|
|
223
221
|
const [editForm, setEditForm] = useState({});
|
|
@@ -231,10 +229,6 @@ var init_KeysTable = __esm({
|
|
|
231
229
|
const response = await onGenerateKey(formData);
|
|
232
230
|
setNewKeyValue(response.key);
|
|
233
231
|
setFormData(emptyForm());
|
|
234
|
-
setTimeout(() => {
|
|
235
|
-
setGenerateModalOpen(false);
|
|
236
|
-
setNewKeyValue(null);
|
|
237
|
-
}, 1500);
|
|
238
232
|
} catch (error) {
|
|
239
233
|
console.error("Failed to generate key:", error);
|
|
240
234
|
} finally {
|
|
@@ -278,32 +272,26 @@ var init_KeysTable = __esm({
|
|
|
278
272
|
onClick: () => setGenerateModalOpen(true)
|
|
279
273
|
},
|
|
280
274
|
"Generate New Key"
|
|
281
|
-
)), /* @__PURE__ */ React2.createElement(TableContainer, null, /* @__PURE__ */ React2.createElement(Table, null, /* @__PURE__ */ React2.createElement(TableHead, null, /* @__PURE__ */ React2.createElement(TableRow, null, /* @__PURE__ */ React2.createElement(TableCell, null, "Alias"), /* @__PURE__ */ React2.createElement(TableCell, null, "Key"), /* @__PURE__ */ React2.createElement(TableCell, null, "Created"), /* @__PURE__ */ React2.createElement(TableCell, null, "Spend"), /* @__PURE__ */ React2.createElement(TableCell, null, "Budget"), /* @__PURE__ */ React2.createElement(TableCell, null, "TPM Limit"), /* @__PURE__ */ React2.createElement(TableCell, null, "Models"), /* @__PURE__ */ React2.createElement(TableCell, { align: "right" }, "Actions"))), /* @__PURE__ */ React2.createElement(TableBody, null, loading ? /* @__PURE__ */ React2.createElement(TableRow, null, /* @__PURE__ */ React2.createElement(TableCell, { colSpan: 8, align: "center" }, /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }))) : keys.length === 0 ? /* @__PURE__ */ React2.createElement(TableRow, null, /* @__PURE__ */ React2.createElement(TableCell, { colSpan: 8, align: "center" }, /* @__PURE__ */ React2.createElement(Typography2, { color: "text.secondary" }, "No keys found"))) : keys.map((key) =>
|
|
282
|
-
|
|
283
|
-
{
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
{
|
|
302
|
-
size: "small",
|
|
303
|
-
onClick: () => setShowKeyValue(showKeyValue === key.key ? null : key.key)
|
|
304
|
-
},
|
|
305
|
-
showKeyValue === key.key ? /* @__PURE__ */ React2.createElement(VisibilityOff, null) : /* @__PURE__ */ React2.createElement(Visibility, null)
|
|
306
|
-
), /* @__PURE__ */ React2.createElement(IconButton, { size: "small", onClick: () => copyToClipboard(key.key) }, /* @__PURE__ */ React2.createElement(ContentCopy, { fontSize: "small" })))), /* @__PURE__ */ React2.createElement(TableCell, null, formatDate(key.created_at)), /* @__PURE__ */ React2.createElement(TableCell, null, "$", key.spend?.toFixed(4) || "0.00"), /* @__PURE__ */ React2.createElement(TableCell, null, key.max_budget ? `$${key.max_budget}` : "-"), /* @__PURE__ */ React2.createElement(TableCell, null, key.tpm_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) }, /* @__PURE__ */ React2.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React2.createElement(IconButton, { color: "error", onClick: () => onDeleteKey(key.key) }, /* @__PURE__ */ React2.createElement(Delete, null))))))))), /* @__PURE__ */ React2.createElement(Dialog, { open: generateModalOpen, onClose: handleCloseModal, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, newKeyValue ? "Key Generated" : "Generate New Key"), /* @__PURE__ */ React2.createElement(DialogContent, null, newKeyValue ? /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary", gutterBottom: true }, "Copy this key now. You won't be able to see it again."), /* @__PURE__ */ React2.createElement(
|
|
275
|
+
)), /* @__PURE__ */ React2.createElement(TableContainer, null, /* @__PURE__ */ React2.createElement(Table, null, /* @__PURE__ */ React2.createElement(TableHead, null, /* @__PURE__ */ React2.createElement(TableRow, null, /* @__PURE__ */ React2.createElement(TableCell, null, "Alias"), /* @__PURE__ */ React2.createElement(TableCell, null, "Key ID"), /* @__PURE__ */ React2.createElement(TableCell, null, "Created"), /* @__PURE__ */ React2.createElement(TableCell, null, "Spend"), /* @__PURE__ */ React2.createElement(TableCell, null, "Budget"), /* @__PURE__ */ React2.createElement(TableCell, null, "TPM Limit"), /* @__PURE__ */ React2.createElement(TableCell, null, "Models"), /* @__PURE__ */ React2.createElement(TableCell, { align: "right" }, "Actions"))), /* @__PURE__ */ React2.createElement(TableBody, null, loading ? /* @__PURE__ */ React2.createElement(TableRow, null, /* @__PURE__ */ React2.createElement(TableCell, { colSpan: 8, align: "center" }, /* @__PURE__ */ React2.createElement(CircularProgress, { size: 24 }))) : keys.length === 0 ? /* @__PURE__ */ React2.createElement(TableRow, null, /* @__PURE__ */ React2.createElement(TableCell, { colSpan: 8, align: "center" }, /* @__PURE__ */ React2.createElement(Typography2, { color: "text.secondary" }, "No keys found"))) : keys.map((key) => {
|
|
276
|
+
const keyId = key.token ?? key.key;
|
|
277
|
+
return /* @__PURE__ */ React2.createElement(TableRow, { key: keyId }, /* @__PURE__ */ React2.createElement(TableCell, null, key.key_alias || "-"), /* @__PURE__ */ React2.createElement(TableCell, null, /* @__PURE__ */ React2.createElement(Box2, { display: "flex", alignItems: "center", gap: 0.5 }, /* @__PURE__ */ React2.createElement(
|
|
278
|
+
Typography2,
|
|
279
|
+
{
|
|
280
|
+
variant: "body2",
|
|
281
|
+
component: "code",
|
|
282
|
+
color: "text.secondary",
|
|
283
|
+
title: keyId,
|
|
284
|
+
sx: {
|
|
285
|
+
fontFamily: "monospace",
|
|
286
|
+
backgroundColor: "background.default",
|
|
287
|
+
px: 1,
|
|
288
|
+
py: 0.5,
|
|
289
|
+
borderRadius: 1
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
shortKeyId(keyId)
|
|
293
|
+
), /* @__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, "$", key.spend?.toFixed(4) || "0.00"), /* @__PURE__ */ React2.createElement(TableCell, null, key.max_budget ? `$${key.max_budget}` : "-"), /* @__PURE__ */ React2.createElement(TableCell, null, key.tpm_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) }, /* @__PURE__ */ React2.createElement(Edit, { fontSize: "small" })), /* @__PURE__ */ React2.createElement(IconButton, { color: "error", onClick: () => onDeleteKey(key.key) }, /* @__PURE__ */ React2.createElement(Delete, null))));
|
|
294
|
+
}))))), /* @__PURE__ */ React2.createElement(Dialog, { open: generateModalOpen, onClose: handleCloseModal, maxWidth: "sm", fullWidth: true }, /* @__PURE__ */ React2.createElement(DialogTitle, null, newKeyValue ? "Key Generated" : "Generate New Key"), /* @__PURE__ */ React2.createElement(DialogContent, null, newKeyValue ? /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Typography2, { variant: "body2", color: "text.secondary", gutterBottom: true }, "Copy this key now. You won't be able to see it again."), /* @__PURE__ */ React2.createElement(
|
|
307
295
|
Box2,
|
|
308
296
|
{
|
|
309
297
|
display: "flex",
|
|
@@ -312,7 +300,9 @@ var init_KeysTable = __esm({
|
|
|
312
300
|
mt: 2,
|
|
313
301
|
p: 2,
|
|
314
302
|
sx: {
|
|
315
|
-
backgroundColor: "
|
|
303
|
+
backgroundColor: "action.hover",
|
|
304
|
+
border: "1px solid",
|
|
305
|
+
borderColor: "divider",
|
|
316
306
|
borderRadius: 1
|
|
317
307
|
}
|
|
318
308
|
},
|
|
@@ -332,6 +322,7 @@ var init_KeysTable = __esm({
|
|
|
332
322
|
label: "Alias",
|
|
333
323
|
value: formData.alias || "",
|
|
334
324
|
onChange: (e) => setFormData({ ...formData, alias: e.target.value }),
|
|
325
|
+
required: true,
|
|
335
326
|
fullWidth: true
|
|
336
327
|
}
|
|
337
328
|
), /* @__PURE__ */ React2.createElement(
|
|
@@ -375,7 +366,7 @@ var init_KeysTable = __esm({
|
|
|
375
366
|
value: selectedModels,
|
|
376
367
|
onChange: (_e, selected) => setFormData({ ...formData, models: selected.map((m) => m.model_name) }),
|
|
377
368
|
renderOption: (props, m) => /* @__PURE__ */ React2.createElement("li", { ...props }, m.model_name, m.supports_function_calling && " \u{1F527}", m.supports_vision && " \u{1F441}\uFE0F"),
|
|
378
|
-
renderInput: (params) => /* @__PURE__ */ React2.createElement(TextField, { ...params, label: "Models", fullWidth: true })
|
|
369
|
+
renderInput: (params) => /* @__PURE__ */ React2.createElement(TextField, { ...params, label: "Models", helperText: "Leave empty to allow all models", fullWidth: true })
|
|
379
370
|
}
|
|
380
371
|
), /* @__PURE__ */ React2.createElement(
|
|
381
372
|
TextField,
|
|
@@ -384,6 +375,7 @@ var init_KeysTable = __esm({
|
|
|
384
375
|
type: "number",
|
|
385
376
|
value: formData.max_budget ?? "",
|
|
386
377
|
onChange: (e) => setFormData({ ...formData, max_budget: e.target.value ? Number(e.target.value) : void 0 }),
|
|
378
|
+
required: true,
|
|
387
379
|
fullWidth: true
|
|
388
380
|
}
|
|
389
381
|
), /* @__PURE__ */ React2.createElement(
|
|
@@ -958,7 +950,7 @@ init_TeamUsage();
|
|
|
958
950
|
|
|
959
951
|
// src/components/LiteLLMHomeWidget.tsx
|
|
960
952
|
init_api();
|
|
961
|
-
import React7, { useState as useState5, useEffect
|
|
953
|
+
import React7, { useState as useState5, useEffect } from "react";
|
|
962
954
|
import {
|
|
963
955
|
Paper as Paper6,
|
|
964
956
|
Box as Box6,
|
|
@@ -997,7 +989,7 @@ var LiteLLMHomeWidget = ({
|
|
|
997
989
|
const [error, setError] = useState5(null);
|
|
998
990
|
const [usage, setUsage] = useState5(null);
|
|
999
991
|
const [keys, setKeys] = useState5([]);
|
|
1000
|
-
|
|
992
|
+
useEffect(() => {
|
|
1001
993
|
let cancelled = false;
|
|
1002
994
|
setLoading(true);
|
|
1003
995
|
setError(null);
|