@acarmisc/backstage-plugin-litellm 0.18.0 → 0.19.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 +58 -16
- package/dist/index.cjs.js.map +3 -3
- package/dist/index.esm.js +52 -10
- package/dist/index.esm.js.map +3 -3
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -3007,7 +3007,7 @@ function fmtTokens(n) {
|
|
|
3007
3007
|
if (n >= 1e3) return `${(n / 1e3).toFixed(0)}K`;
|
|
3008
3008
|
return String(n);
|
|
3009
3009
|
}
|
|
3010
|
-
var import_react8, import_Box8, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_Typography8, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert3, import_styles5, ALL_PROXY_MODELS2, ModelsTable;
|
|
3010
|
+
var import_react8, import_Box8, import_Table5, import_TableBody5, import_TableCell5, import_TableContainer5, import_TableHead5, import_TableRow5, import_Typography8, import_MenuItem4, import_Select, import_FormControl, import_InputLabel, import_TextField5, import_InputAdornment2, import_icons_material6, import_ContentCopy, import_Tooltip, import_Snackbar, import_Alert3, import_styles5, ALL_PROXY_MODELS2, ModelsTable;
|
|
3011
3011
|
var init_ModelsTable = __esm({
|
|
3012
3012
|
"src/components/ModelsTable.tsx"() {
|
|
3013
3013
|
"use strict";
|
|
@@ -3024,6 +3024,9 @@ var init_ModelsTable = __esm({
|
|
|
3024
3024
|
import_Select = __toESM(require("@mui/material/Select"));
|
|
3025
3025
|
import_FormControl = __toESM(require("@mui/material/FormControl"));
|
|
3026
3026
|
import_InputLabel = __toESM(require("@mui/material/InputLabel"));
|
|
3027
|
+
import_TextField5 = __toESM(require("@mui/material/TextField"));
|
|
3028
|
+
import_InputAdornment2 = __toESM(require("@mui/material/InputAdornment"));
|
|
3029
|
+
import_icons_material6 = require("@mui/icons-material");
|
|
3027
3030
|
import_ContentCopy = __toESM(require("@mui/icons-material/ContentCopy"));
|
|
3028
3031
|
import_Tooltip = __toESM(require("@mui/material/Tooltip"));
|
|
3029
3032
|
import_Snackbar = __toESM(require("@mui/material/Snackbar"));
|
|
@@ -3034,15 +3037,23 @@ var init_ModelsTable = __esm({
|
|
|
3034
3037
|
ModelsTable = ({ allModels, teams, loading }) => {
|
|
3035
3038
|
const theme = (0, import_styles5.useTheme)();
|
|
3036
3039
|
const [selectedTeamId, setSelectedTeamId] = (0, import_react8.useState)("");
|
|
3040
|
+
const [filterText, setFilterText] = (0, import_react8.useState)("");
|
|
3037
3041
|
const [copiedSnackbar, setCopiedSnackbar] = (0, import_react8.useState)(false);
|
|
3038
3042
|
const selectedTeam = (0, import_react8.useMemo)(
|
|
3039
3043
|
() => teams.find((t) => t.team_id === selectedTeamId) ?? null,
|
|
3040
3044
|
[teams, selectedTeamId]
|
|
3041
3045
|
);
|
|
3042
|
-
const
|
|
3046
|
+
const teamModels = (0, import_react8.useMemo)(() => {
|
|
3043
3047
|
if (!selectedTeam) return [];
|
|
3044
3048
|
return allModels.filter((model) => isModelAllowedByTeam2(model, selectedTeam.models));
|
|
3045
3049
|
}, [allModels, selectedTeam]);
|
|
3050
|
+
const filteredModels = (0, import_react8.useMemo)(() => {
|
|
3051
|
+
const q = filterText.trim().toLowerCase();
|
|
3052
|
+
if (!q) return teamModels;
|
|
3053
|
+
return teamModels.filter(
|
|
3054
|
+
(model) => model.model_name.toLowerCase().includes(q) || (model.access_groups || []).some((group) => group.toLowerCase().includes(q))
|
|
3055
|
+
);
|
|
3056
|
+
}, [teamModels, filterText]);
|
|
3046
3057
|
const handleCopyModelId = (0, import_react8.useCallback)((modelId) => {
|
|
3047
3058
|
navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));
|
|
3048
3059
|
}, []);
|
|
@@ -3064,9 +3075,9 @@ var init_ModelsTable = __esm({
|
|
|
3064
3075
|
SectionCard,
|
|
3065
3076
|
{
|
|
3066
3077
|
title: "Available Models",
|
|
3067
|
-
subtitle: selectedTeam ? `${filteredModels.length} model${filteredModels.length
|
|
3078
|
+
subtitle: selectedTeam ? `${filteredModels.length}${filterText.trim() ? ` of ${teamModels.length}` : ""} model${filteredModels.length === 1 ? "" : "s"}` : "Select a team to view its models"
|
|
3068
3079
|
},
|
|
3069
|
-
/* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { px: 2.5, pb: 2.5, pt: 1 } }, /* @__PURE__ */ import_react8.default.createElement(import_FormControl.default, { size: "small", sx: { minWidth: 240, mb: 2 } }, /* @__PURE__ */ import_react8.default.createElement(import_InputLabel.default, { id: "team-select-label" }, "Team"), /* @__PURE__ */ import_react8.default.createElement(
|
|
3080
|
+
/* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { px: 2.5, pb: 2.5, pt: 1, display: "flex", gap: 2, flexWrap: "wrap" } }, /* @__PURE__ */ import_react8.default.createElement(import_FormControl.default, { size: "small", sx: { minWidth: 240, mb: 2 } }, /* @__PURE__ */ import_react8.default.createElement(import_InputLabel.default, { id: "team-select-label" }, "Team"), /* @__PURE__ */ import_react8.default.createElement(
|
|
3070
3081
|
import_Select.default,
|
|
3071
3082
|
{
|
|
3072
3083
|
labelId: "team-select-label",
|
|
@@ -3075,7 +3086,20 @@ var init_ModelsTable = __esm({
|
|
|
3075
3086
|
onChange: (e) => setSelectedTeamId(e.target.value)
|
|
3076
3087
|
},
|
|
3077
3088
|
teams.map((t) => /* @__PURE__ */ import_react8.default.createElement(import_MenuItem4.default, { key: t.team_id, value: t.team_id }, t.team_alias ?? t.team_id))
|
|
3078
|
-
))
|
|
3089
|
+
)), /* @__PURE__ */ import_react8.default.createElement(
|
|
3090
|
+
import_TextField5.default,
|
|
3091
|
+
{
|
|
3092
|
+
label: "Filter Models",
|
|
3093
|
+
size: "small",
|
|
3094
|
+
value: filterText,
|
|
3095
|
+
onChange: (e) => setFilterText(e.target.value),
|
|
3096
|
+
disabled: !selectedTeamId,
|
|
3097
|
+
sx: { minWidth: 240, mb: 2 },
|
|
3098
|
+
InputProps: {
|
|
3099
|
+
startAdornment: /* @__PURE__ */ import_react8.default.createElement(import_InputAdornment2.default, { position: "start" }, /* @__PURE__ */ import_react8.default.createElement(import_icons_material6.Search, { fontSize: "small" }))
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
)),
|
|
3079
3103
|
loading && /* @__PURE__ */ import_react8.default.createElement(EmptyState, { message: "Loading models\u2026" }),
|
|
3080
3104
|
!loading && !selectedTeamId && /* @__PURE__ */ import_react8.default.createElement(
|
|
3081
3105
|
EmptyState,
|
|
@@ -3084,14 +3108,32 @@ var init_ModelsTable = __esm({
|
|
|
3084
3108
|
hint: "Each team may have a different set of models assigned"
|
|
3085
3109
|
}
|
|
3086
3110
|
),
|
|
3087
|
-
!loading && selectedTeamId &&
|
|
3111
|
+
!loading && selectedTeamId && teamModels.length === 0 && /* @__PURE__ */ import_react8.default.createElement(
|
|
3088
3112
|
EmptyState,
|
|
3089
3113
|
{
|
|
3090
3114
|
message: "No models available for this team",
|
|
3091
3115
|
hint: allModels.length === 0 ? "No models are configured in the system" : "None of the team's assigned models were found in the catalog"
|
|
3092
3116
|
}
|
|
3093
3117
|
),
|
|
3094
|
-
!loading &&
|
|
3118
|
+
!loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && /* @__PURE__ */ import_react8.default.createElement(
|
|
3119
|
+
EmptyState,
|
|
3120
|
+
{
|
|
3121
|
+
message: "No models match your search",
|
|
3122
|
+
hint: "Try a different search term"
|
|
3123
|
+
}
|
|
3124
|
+
),
|
|
3125
|
+
!loading && filteredModels.length > 0 && /* @__PURE__ */ import_react8.default.createElement(import_TableContainer5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Table5.default, { size: "small", sx: dataTableSx }, /* @__PURE__ */ import_react8.default.createElement(import_TableHead5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_TableRow5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, "Model ID"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, "Mode"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Input Cost"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Output Cost"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Max Input"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, { align: "right" }, "Max Output"), /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, "Capabilities"))), /* @__PURE__ */ import_react8.default.createElement(import_TableBody5.default, null, filteredModels.map((m) => /* @__PURE__ */ import_react8.default.createElement(import_TableRow5.default, { key: m.model_name, hover: true }, /* @__PURE__ */ import_react8.default.createElement(import_TableCell5.default, null, /* @__PURE__ */ import_react8.default.createElement(import_Box8.default, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ import_react8.default.createElement(import_Tooltip.default, { title: m.model_name, placement: "top" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
3126
|
+
"span",
|
|
3127
|
+
{
|
|
3128
|
+
role: "button",
|
|
3129
|
+
tabIndex: 0,
|
|
3130
|
+
"aria-label": "Copy model ID",
|
|
3131
|
+
onClick: () => handleCopyModelId(m.model_name),
|
|
3132
|
+
onKeyDown: (e) => e.key === "Enter" && handleCopyModelId(m.model_name),
|
|
3133
|
+
style: { cursor: "pointer", display: "inline-flex" }
|
|
3134
|
+
},
|
|
3135
|
+
/* @__PURE__ */ import_react8.default.createElement(TagChip, { label: m.model_name, title: "Copy model ID" })
|
|
3136
|
+
)), /* @__PURE__ */ import_react8.default.createElement(import_Tooltip.default, { title: "Copy model ID" }, /* @__PURE__ */ import_react8.default.createElement(
|
|
3095
3137
|
import_Box8.default,
|
|
3096
3138
|
{
|
|
3097
3139
|
component: "span",
|
|
@@ -3170,7 +3212,7 @@ function renderAuditLogBody(loading, entries) {
|
|
|
3170
3212
|
}
|
|
3171
3213
|
return entries.map((entry) => /* @__PURE__ */ import_react9.default.createElement(DetailRow, { key: entry.id, entry }));
|
|
3172
3214
|
}
|
|
3173
|
-
var import_react9, import_Box9, import_Typography9, import_Table6, import_TableBody6, import_TableCell6, import_TableContainer6, import_TableHead6, import_TableRow6, import_TablePagination,
|
|
3215
|
+
var import_react9, import_Box9, import_Typography9, import_Table6, import_TableBody6, import_TableCell6, import_TableContainer6, import_TableHead6, import_TableRow6, import_TablePagination, import_TextField6, import_MenuItem5, import_Skeleton5, import_Collapse2, import_IconButton5, import_Alert4, import_styles6, import_icons_material7, import_react_use2, ACTION_TONES, TABLE_LABELS, DetailRow, AuditLog;
|
|
3174
3216
|
var init_AuditLog = __esm({
|
|
3175
3217
|
"src/components/AuditLog.tsx"() {
|
|
3176
3218
|
"use strict";
|
|
@@ -3184,14 +3226,14 @@ var init_AuditLog = __esm({
|
|
|
3184
3226
|
import_TableHead6 = __toESM(require("@mui/material/TableHead"));
|
|
3185
3227
|
import_TableRow6 = __toESM(require("@mui/material/TableRow"));
|
|
3186
3228
|
import_TablePagination = __toESM(require("@mui/material/TablePagination"));
|
|
3187
|
-
|
|
3229
|
+
import_TextField6 = __toESM(require("@mui/material/TextField"));
|
|
3188
3230
|
import_MenuItem5 = __toESM(require("@mui/material/MenuItem"));
|
|
3189
3231
|
import_Skeleton5 = __toESM(require("@mui/material/Skeleton"));
|
|
3190
3232
|
import_Collapse2 = __toESM(require("@mui/material/Collapse"));
|
|
3191
3233
|
import_IconButton5 = __toESM(require("@mui/material/IconButton"));
|
|
3192
3234
|
import_Alert4 = __toESM(require("@mui/material/Alert"));
|
|
3193
3235
|
import_styles6 = require("@mui/material/styles");
|
|
3194
|
-
|
|
3236
|
+
import_icons_material7 = require("@mui/icons-material");
|
|
3195
3237
|
import_react_use2 = require("react-use");
|
|
3196
3238
|
init_ui();
|
|
3197
3239
|
ACTION_TONES = {
|
|
@@ -3224,7 +3266,7 @@ var init_AuditLog = __esm({
|
|
|
3224
3266
|
transition: theme.transitions.create("transform")
|
|
3225
3267
|
})
|
|
3226
3268
|
},
|
|
3227
|
-
/* @__PURE__ */ import_react9.default.createElement(
|
|
3269
|
+
/* @__PURE__ */ import_react9.default.createElement(import_icons_material7.KeyboardArrowDown, { fontSize: "small" })
|
|
3228
3270
|
)), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, { sx: { whiteSpace: "nowrap" } }, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2", color: "text.secondary" }, formatDateTime(entry.updated_at))), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, entry.action && /* @__PURE__ */ import_react9.default.createElement(StatusPill, { label: entry.action, tone: actionTone(entry.action) })), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react9.default.createElement(import_Typography9.default, { variant: "body2" }, prettyTableName(entry.table_name))), /* @__PURE__ */ import_react9.default.createElement(import_TableCell6.default, null, /* @__PURE__ */ import_react9.default.createElement(
|
|
3229
3271
|
import_Typography9.default,
|
|
3230
3272
|
{
|
|
@@ -3293,7 +3335,7 @@ var init_AuditLog = __esm({
|
|
|
3293
3335
|
subtitle: loading ? "Loading\u2026" : `${total.toLocaleString()} event${total === 1 ? "" : "s"}`,
|
|
3294
3336
|
flush: true,
|
|
3295
3337
|
actions: /* @__PURE__ */ import_react9.default.createElement(import_react9.default.Fragment, null, /* @__PURE__ */ import_react9.default.createElement(
|
|
3296
|
-
|
|
3338
|
+
import_TextField6.default,
|
|
3297
3339
|
{
|
|
3298
3340
|
size: "small",
|
|
3299
3341
|
label: "Action",
|
|
@@ -3311,7 +3353,7 @@ var init_AuditLog = __esm({
|
|
|
3311
3353
|
/* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "deleted" }, "Deleted"),
|
|
3312
3354
|
/* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "blocked" }, "Blocked")
|
|
3313
3355
|
), /* @__PURE__ */ import_react9.default.createElement(
|
|
3314
|
-
|
|
3356
|
+
import_TextField6.default,
|
|
3315
3357
|
{
|
|
3316
3358
|
size: "small",
|
|
3317
3359
|
label: "Table",
|
|
@@ -3330,7 +3372,7 @@ var init_AuditLog = __esm({
|
|
|
3330
3372
|
/* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_ObjectPermissionTable" }, "Team access (KB / MCP)"),
|
|
3331
3373
|
/* @__PURE__ */ import_react9.default.createElement(import_MenuItem5.default, { value: "LiteLLM_UserTable" }, "User")
|
|
3332
3374
|
), /* @__PURE__ */ import_react9.default.createElement(
|
|
3333
|
-
|
|
3375
|
+
import_TextField6.default,
|
|
3334
3376
|
{
|
|
3335
3377
|
size: "small",
|
|
3336
3378
|
label: "Changed by",
|
|
@@ -3849,7 +3891,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
3849
3891
|
|
|
3850
3892
|
// src/plugin.tsx
|
|
3851
3893
|
var import_react11 = __toESM(require("react"));
|
|
3852
|
-
var
|
|
3894
|
+
var import_icons_material8 = require("@mui/icons-material");
|
|
3853
3895
|
var import_frontend_plugin_api = require("@backstage/frontend-plugin-api");
|
|
3854
3896
|
init_api();
|
|
3855
3897
|
var liteLlmApi = import_frontend_plugin_api.ApiBlueprint.make({
|
|
@@ -3863,7 +3905,7 @@ var liteLlmPage = import_frontend_plugin_api.PageBlueprint.make({
|
|
|
3863
3905
|
params: {
|
|
3864
3906
|
path: "/litellm",
|
|
3865
3907
|
title: "LiteLLM",
|
|
3866
|
-
icon: /* @__PURE__ */ import_react11.default.createElement(
|
|
3908
|
+
icon: /* @__PURE__ */ import_react11.default.createElement(import_icons_material8.TrendingUp, null),
|
|
3867
3909
|
loader: async () => {
|
|
3868
3910
|
const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
|
|
3869
3911
|
return /* @__PURE__ */ import_react11.default.createElement(LiteLLMPage2, null);
|