@acarmisc/backstage-plugin-litellm 0.32.0 → 0.34.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/README.md +55 -66
- package/dist/components/KeyFormDialog.d.ts +0 -2
- package/dist/components/LiteLLMBudgetGauges.d.ts +0 -1
- package/dist/components/ManageTeamDialog.d.ts +10 -1
- package/dist/components/keyFormHelpers.d.ts +0 -1
- package/dist/hooks/useCopyToClipboard.d.ts +0 -5
- package/dist/index.cjs.js +272 -225
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.d.ts +2 -3
- package/dist/index.esm.js +283 -237
- package/dist/index.esm.js.map +4 -4
- package/package.json +4 -10
- package/dist/components/GenerateKeyDialog.d.ts +0 -21
- package/dist/permissions.d.ts +0 -1
package/dist/index.cjs.js
CHANGED
|
@@ -1843,8 +1843,6 @@ var init_KeysTable = __esm({
|
|
|
1843
1843
|
setPruneSubmitting(true);
|
|
1844
1844
|
try {
|
|
1845
1845
|
await onPruneExpiredKeys();
|
|
1846
|
-
} catch (error) {
|
|
1847
|
-
console.error("Failed to prune expired keys:", error);
|
|
1848
1846
|
} finally {
|
|
1849
1847
|
setPruneSubmitting(false);
|
|
1850
1848
|
setPruneConfirmCount(null);
|
|
@@ -1913,7 +1911,8 @@ var init_KeysTable = __esm({
|
|
|
1913
1911
|
bgcolor: (0, import_styles7.alpha)(theme.palette.text.primary, theme.palette.mode === "dark" ? 0.08 : 0.05),
|
|
1914
1912
|
px: 0.75,
|
|
1915
1913
|
py: 0.375,
|
|
1916
|
-
borderRadius: "5px"
|
|
1914
|
+
borderRadius: "5px",
|
|
1915
|
+
whiteSpace: "nowrap"
|
|
1917
1916
|
}),
|
|
1918
1917
|
children: shortKeyId(keyId)
|
|
1919
1918
|
}
|
|
@@ -3204,6 +3203,7 @@ var init_ManageTeamDialog = __esm({
|
|
|
3204
3203
|
const [memberBudget, setMemberBudget] = (0, import_react7.useState)("");
|
|
3205
3204
|
const [memberBusy, setMemberBusy] = (0, import_react7.useState)(false);
|
|
3206
3205
|
const [memberError, setMemberError] = (0, import_react7.useState)(null);
|
|
3206
|
+
const [pendingMembers, setPendingMembers] = (0, import_react7.useState)([]);
|
|
3207
3207
|
const [kbIds, setKbIds] = (0, import_react7.useState)([]);
|
|
3208
3208
|
const [kbBusy, setKbBusy] = (0, import_react7.useState)(false);
|
|
3209
3209
|
const [kbError, setKbError] = (0, import_react7.useState)(null);
|
|
@@ -3214,8 +3214,17 @@ var init_ManageTeamDialog = __esm({
|
|
|
3214
3214
|
const maxBudgetCeiling = config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;
|
|
3215
3215
|
const hideBudgetForManagers = config?.display?.hideTeamBudgetForManagers ?? false;
|
|
3216
3216
|
const budgetWriteOnly = hideBudgetForManagers && mode === "edit";
|
|
3217
|
-
const
|
|
3218
|
-
const
|
|
3217
|
+
const creating = mode === "create";
|
|
3218
|
+
const members = (0, import_react7.useMemo)(
|
|
3219
|
+
() => creating ? pendingMembers.map((p) => ({
|
|
3220
|
+
user_id: p.userEntityRef,
|
|
3221
|
+
user_email: p.label,
|
|
3222
|
+
role: "user"
|
|
3223
|
+
})) : team?.members_with_roles ?? [],
|
|
3224
|
+
[creating, pendingMembers, team]
|
|
3225
|
+
);
|
|
3226
|
+
const showMembers = !!canManageMembers || !!membersOnly;
|
|
3227
|
+
const wide = showMembers && !membersOnly;
|
|
3219
3228
|
const catalogApi = (0, import_core_plugin_api4.useApi)(import_plugin_catalog_react.catalogApiRef);
|
|
3220
3229
|
const [searchUsers, setSearchUsers] = (0, import_react7.useState)([]);
|
|
3221
3230
|
const [usersLoading, setUsersLoading] = (0, import_react7.useState)(false);
|
|
@@ -3260,8 +3269,8 @@ var init_ManageTeamDialog = __esm({
|
|
|
3260
3269
|
email,
|
|
3261
3270
|
label: email ? `${displayName} (${email})` : displayName
|
|
3262
3271
|
};
|
|
3263
|
-
}).filter((o) => !(o.email && existingEmails.has(o.email.toLowerCase()))).sort((a, b) => a.label.localeCompare(b.label));
|
|
3264
|
-
}, [searchUsers, members]);
|
|
3272
|
+
}).filter((o) => !(o.email && existingEmails.has(o.email.toLowerCase()))).filter((o) => !pendingMembers.some((p) => p.userEntityRef === o.ref)).sort((a, b) => a.label.localeCompare(b.label));
|
|
3273
|
+
}, [searchUsers, members, pendingMembers]);
|
|
3265
3274
|
(0, import_react7.useEffect)(() => {
|
|
3266
3275
|
return () => {
|
|
3267
3276
|
if (debounceTimerRef.current) {
|
|
@@ -3295,6 +3304,7 @@ var init_ManageTeamDialog = __esm({
|
|
|
3295
3304
|
setMemberRef("");
|
|
3296
3305
|
setMemberBudget("");
|
|
3297
3306
|
setMemberError(null);
|
|
3307
|
+
setPendingMembers([]);
|
|
3298
3308
|
setKbIds(team?.object_permission?.vector_stores ?? []);
|
|
3299
3309
|
setKbError(null);
|
|
3300
3310
|
setMcpIds(team?.object_permission?.mcp_servers ?? []);
|
|
@@ -3353,7 +3363,13 @@ var init_ManageTeamDialog = __esm({
|
|
|
3353
3363
|
...budgetDuration && { budget_duration: budgetDuration }
|
|
3354
3364
|
};
|
|
3355
3365
|
}
|
|
3356
|
-
await onSubmit(
|
|
3366
|
+
await onSubmit(
|
|
3367
|
+
payload,
|
|
3368
|
+
creating ? pendingMembers.map(({ userEntityRef, maxBudgetInTeam }) => ({
|
|
3369
|
+
userEntityRef,
|
|
3370
|
+
...maxBudgetInTeam !== void 0 && { maxBudgetInTeam }
|
|
3371
|
+
})) : void 0
|
|
3372
|
+
);
|
|
3357
3373
|
onClose();
|
|
3358
3374
|
} catch (err) {
|
|
3359
3375
|
setError(err instanceof Error ? err.message : "An error occurred");
|
|
@@ -3362,13 +3378,26 @@ var init_ManageTeamDialog = __esm({
|
|
|
3362
3378
|
}
|
|
3363
3379
|
};
|
|
3364
3380
|
const handleAddMember = async () => {
|
|
3365
|
-
if (!
|
|
3381
|
+
if (!memberRef.trim() || !creating && !onAddMember) return;
|
|
3366
3382
|
setMemberError(null);
|
|
3367
3383
|
const budget = !membersOnly && memberBudget ? parseFloat(memberBudget) : void 0;
|
|
3368
3384
|
if (budget !== void 0 && (isNaN(budget) || budget <= 0)) {
|
|
3369
3385
|
setMemberError("Max budget in team must be a positive number");
|
|
3370
3386
|
return;
|
|
3371
3387
|
}
|
|
3388
|
+
if (creating) {
|
|
3389
|
+
const ref = memberRef.trim();
|
|
3390
|
+
if (!pendingMembers.some((p) => p.userEntityRef === ref)) {
|
|
3391
|
+
setPendingMembers((list) => [
|
|
3392
|
+
...list,
|
|
3393
|
+
{ userEntityRef: ref, label: memberQuery.trim() || ref, maxBudgetInTeam: budget }
|
|
3394
|
+
]);
|
|
3395
|
+
}
|
|
3396
|
+
setMemberQuery("");
|
|
3397
|
+
setMemberRef("");
|
|
3398
|
+
setMemberBudget("");
|
|
3399
|
+
return;
|
|
3400
|
+
}
|
|
3372
3401
|
try {
|
|
3373
3402
|
setMemberBusy(true);
|
|
3374
3403
|
await onAddMember(memberRef.trim(), budget);
|
|
@@ -3382,6 +3411,10 @@ var init_ManageTeamDialog = __esm({
|
|
|
3382
3411
|
}
|
|
3383
3412
|
};
|
|
3384
3413
|
const handleRemoveMember = async (userId) => {
|
|
3414
|
+
if (creating) {
|
|
3415
|
+
setPendingMembers((list) => list.filter((p) => p.userEntityRef !== userId));
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3385
3418
|
if (!onRemoveMember) return;
|
|
3386
3419
|
setMemberError(null);
|
|
3387
3420
|
try {
|
|
@@ -3435,13 +3468,14 @@ var init_ManageTeamDialog = __esm({
|
|
|
3435
3468
|
}
|
|
3436
3469
|
return { disabled: false };
|
|
3437
3470
|
};
|
|
3471
|
+
const submitLabel = creating ? "Create team" : "Save";
|
|
3438
3472
|
const getDialogTitle = () => {
|
|
3439
3473
|
if (membersOnly) {
|
|
3440
3474
|
return `Manage members \u2014 ${team?.team_alias || "Untitled team"}`;
|
|
3441
3475
|
}
|
|
3442
3476
|
return mode === "create" ? "Create Team" : "Edit Team";
|
|
3443
3477
|
};
|
|
3444
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Dialog3.default, { open, onClose, maxWidth: "sm", fullWidth: true, children: [
|
|
3478
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Dialog3.default, { open, onClose, maxWidth: wide ? "md" : "sm", fullWidth: true, children: [
|
|
3445
3479
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_DialogTitle3.default, { children: getDialogTitle() }),
|
|
3446
3480
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_DialogContent3.default, { sx: { pt: 2, display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
3447
3481
|
error && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Alert2.default, { severity: "error", children: error }),
|
|
@@ -3450,186 +3484,215 @@ var init_ManageTeamDialog = __esm({
|
|
|
3450
3484
|
team?.members_with_roles?.find((m) => m.user_id === currentUserId)?.role || "member",
|
|
3451
3485
|
" you can add or remove members. Budgets and models are managed by your platform admins."
|
|
3452
3486
|
] }),
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
{
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
options: modelNames,
|
|
3469
|
-
value: models,
|
|
3470
|
-
onChange: (_, newValue) => setModels(newValue),
|
|
3471
|
-
disabled: submitting,
|
|
3472
|
-
renderInput: (params) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3473
|
-
import_TextField3.default,
|
|
3474
|
-
{
|
|
3475
|
-
...params,
|
|
3476
|
-
label: "Models",
|
|
3477
|
-
required: true,
|
|
3478
|
-
helperText: "At least one model is required here \u2014 this delegated flow only grants access to models your admin has allow-listed for team creation, not every proxy model. (Teams with no model restriction shown elsewhere were configured directly in LiteLLM.)"
|
|
3479
|
-
}
|
|
3480
|
-
)
|
|
3481
|
-
}
|
|
3482
|
-
),
|
|
3483
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3484
|
-
import_TextField3.default,
|
|
3485
|
-
{
|
|
3486
|
-
label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
|
|
3487
|
-
type: "number",
|
|
3488
|
-
value: maxBudget,
|
|
3489
|
-
onChange: (e) => setMaxBudget(e.target.value),
|
|
3490
|
-
disabled: submitting || unlimited,
|
|
3491
|
-
inputProps: { min: 0, max: maxBudgetCeiling },
|
|
3492
|
-
helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
|
|
3493
|
-
fullWidth: true
|
|
3494
|
-
}
|
|
3495
|
-
),
|
|
3496
|
-
allowUnlimitedBudget && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3497
|
-
import_FormControlLabel2.default,
|
|
3498
|
-
{
|
|
3499
|
-
control: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Checkbox2.default, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
|
|
3500
|
-
label: "Unlimited Budget"
|
|
3501
|
-
}
|
|
3502
|
-
),
|
|
3503
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3504
|
-
import_TextField3.default,
|
|
3505
|
-
{
|
|
3506
|
-
select: true,
|
|
3507
|
-
label: "Budget Duration",
|
|
3508
|
-
value: budgetDuration,
|
|
3509
|
-
onChange: (e) => setBudgetDuration(e.target.value),
|
|
3510
|
-
disabled: submitting || unlimited,
|
|
3511
|
-
helperText: "Spend-reset period for the team budget",
|
|
3512
|
-
fullWidth: true,
|
|
3513
|
-
children: durationOptions.map((o) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_MenuItem2.default, { value: o.value, children: o.label }, o.value))
|
|
3514
|
-
}
|
|
3515
|
-
)
|
|
3516
|
-
] }),
|
|
3517
|
-
showMembers && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Box10.default, { children: [
|
|
3518
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Divider2.default, { sx: { my: 1 } }),
|
|
3519
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "subtitle2", sx: { mb: 1 }, children: "Members" }),
|
|
3520
|
-
memberError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null), children: memberError }),
|
|
3521
|
-
members.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: "No members yet." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableContainer2.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Table2.default, { size: "small", sx: dataTableSx, children: [
|
|
3522
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableHead2.default, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_TableRow2.default, { children: [
|
|
3523
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { children: "User" }),
|
|
3524
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", children: "Role" }),
|
|
3525
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", sx: { width: 40 } })
|
|
3526
|
-
] }) }),
|
|
3527
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableBody2.default, { children: members.map((m) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_TableRow2.default, { children: [
|
|
3528
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { children: m.user_email ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3529
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "body2", children: m.user_email }),
|
|
3487
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
3488
|
+
import_Box10.default,
|
|
3489
|
+
{
|
|
3490
|
+
sx: {
|
|
3491
|
+
display: "grid",
|
|
3492
|
+
gridTemplateColumns: {
|
|
3493
|
+
xs: "1fr",
|
|
3494
|
+
md: wide ? "minmax(0, 1fr) minmax(0, 1fr)" : "1fr"
|
|
3495
|
+
},
|
|
3496
|
+
gap: 3,
|
|
3497
|
+
alignItems: "start"
|
|
3498
|
+
},
|
|
3499
|
+
children: [
|
|
3500
|
+
!membersOnly && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Box10.default, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
|
|
3501
|
+
wide && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "subtitle2", children: "Settings" }),
|
|
3530
3502
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3531
|
-
|
|
3503
|
+
import_TextField3.default,
|
|
3532
3504
|
{
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3505
|
+
label: "Team Alias",
|
|
3506
|
+
value: alias,
|
|
3507
|
+
onChange: (e) => setAlias(e.target.value),
|
|
3508
|
+
disabled: submitting,
|
|
3509
|
+
fullWidth: true
|
|
3537
3510
|
}
|
|
3538
|
-
)
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
{
|
|
3542
|
-
variant: "body2",
|
|
3543
|
-
sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" },
|
|
3544
|
-
children: m.user_id
|
|
3545
|
-
}
|
|
3546
|
-
) }),
|
|
3547
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false }) }),
|
|
3548
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", children: (() => {
|
|
3549
|
-
const { disabled, reason } = isRemovalDisabled(m.user_id, m.role);
|
|
3550
|
-
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Tooltip4.default, { title: reason ?? "", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3551
|
-
import_IconButton4.default,
|
|
3511
|
+
),
|
|
3512
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3513
|
+
import_Autocomplete2.default,
|
|
3552
3514
|
{
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
{
|
|
3568
|
-
freeSolo: true,
|
|
3569
|
-
autoHighlight: true,
|
|
3570
|
-
options: userOptions,
|
|
3571
|
-
loading: usersLoading,
|
|
3572
|
-
inputValue: memberQuery,
|
|
3573
|
-
onInputChange: (_, newInputValue, reason) => {
|
|
3574
|
-
setMemberQuery(newInputValue);
|
|
3575
|
-
if (reason === "input" || reason === "clear") {
|
|
3576
|
-
setMemberRef(newInputValue);
|
|
3577
|
-
handleUserSearch(newInputValue);
|
|
3515
|
+
multiple: true,
|
|
3516
|
+
options: modelNames,
|
|
3517
|
+
value: models,
|
|
3518
|
+
onChange: (_, newValue) => setModels(newValue),
|
|
3519
|
+
disabled: submitting,
|
|
3520
|
+
renderInput: (params) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3521
|
+
import_TextField3.default,
|
|
3522
|
+
{
|
|
3523
|
+
...params,
|
|
3524
|
+
label: "Models",
|
|
3525
|
+
required: true,
|
|
3526
|
+
helperText: "Only models your admin allow-listed for teams. At least one is required."
|
|
3527
|
+
}
|
|
3528
|
+
)
|
|
3578
3529
|
}
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3530
|
+
),
|
|
3531
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
3532
|
+
import_Box10.default,
|
|
3533
|
+
{
|
|
3534
|
+
sx: {
|
|
3535
|
+
display: "grid",
|
|
3536
|
+
gridTemplateColumns: { xs: "1fr", sm: "1fr 1fr" },
|
|
3537
|
+
gap: 2
|
|
3538
|
+
},
|
|
3539
|
+
children: [
|
|
3540
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3541
|
+
import_TextField3.default,
|
|
3542
|
+
{
|
|
3543
|
+
label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
|
|
3544
|
+
type: "number",
|
|
3545
|
+
value: maxBudget,
|
|
3546
|
+
onChange: (e) => setMaxBudget(e.target.value),
|
|
3547
|
+
disabled: submitting || unlimited,
|
|
3548
|
+
inputProps: { min: 0, max: maxBudgetCeiling },
|
|
3549
|
+
helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
|
|
3550
|
+
fullWidth: true
|
|
3551
|
+
}
|
|
3552
|
+
),
|
|
3553
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3554
|
+
import_TextField3.default,
|
|
3555
|
+
{
|
|
3556
|
+
select: true,
|
|
3557
|
+
label: "Budget Duration",
|
|
3558
|
+
value: budgetDuration,
|
|
3559
|
+
onChange: (e) => setBudgetDuration(e.target.value),
|
|
3560
|
+
disabled: submitting || unlimited,
|
|
3561
|
+
helperText: "Spend-reset period for the team budget",
|
|
3562
|
+
fullWidth: true,
|
|
3563
|
+
children: durationOptions.map((o) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_MenuItem2.default, { value: o.value, children: o.label }, o.value))
|
|
3564
|
+
}
|
|
3565
|
+
)
|
|
3566
|
+
]
|
|
3584
3567
|
}
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
disabled: memberBusy,
|
|
3589
|
-
sx: { flex: 1, minWidth: 260 },
|
|
3590
|
-
renderInput: (params) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3591
|
-
import_TextField3.default,
|
|
3568
|
+
),
|
|
3569
|
+
allowUnlimitedBudget && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3570
|
+
import_FormControlLabel2.default,
|
|
3592
3571
|
{
|
|
3593
|
-
|
|
3594
|
-
label: "
|
|
3595
|
-
placeholder: "Search by name or email\u2026",
|
|
3596
|
-
size: "small",
|
|
3597
|
-
helperText: "Pick a catalog user, or paste a user entity ref",
|
|
3598
|
-
InputProps: {
|
|
3599
|
-
...params.InputProps,
|
|
3600
|
-
endAdornment: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3601
|
-
usersLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_CircularProgress3.default, { color: "inherit", size: 14 }) : null,
|
|
3602
|
-
params.InputProps.endAdornment
|
|
3603
|
-
] })
|
|
3604
|
-
}
|
|
3572
|
+
control: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Checkbox2.default, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
|
|
3573
|
+
label: "Unlimited Budget"
|
|
3605
3574
|
}
|
|
3606
3575
|
)
|
|
3607
|
-
}
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3576
|
+
] }),
|
|
3577
|
+
showMembers && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Box10.default, { children: [
|
|
3578
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "subtitle2", sx: { mb: creating ? 0.25 : 1 }, children: creating ? "Initial members" : "Members" }),
|
|
3579
|
+
creating && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: "Added as team users right after the team is created." }),
|
|
3580
|
+
memberError && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Alert2.default, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null), children: memberError }),
|
|
3581
|
+
members.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: creating ? "No members picked yet \u2014 you can also add them later." : "No members yet." }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableContainer2.default, { component: import_Paper4.default, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Table2.default, { size: "small", sx: dataTableSx, children: [
|
|
3582
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableHead2.default, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_TableRow2.default, { children: [
|
|
3583
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { children: "User" }),
|
|
3584
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", children: "Role" }),
|
|
3585
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", sx: { width: 40 } })
|
|
3586
|
+
] }) }),
|
|
3587
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableBody2.default, { children: members.map((m) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_TableRow2.default, { children: [
|
|
3588
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { children: m.user_email ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3589
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "body2", children: m.user_email }),
|
|
3590
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3591
|
+
import_Typography8.default,
|
|
3592
|
+
{
|
|
3593
|
+
variant: "caption",
|
|
3594
|
+
color: "text.secondary",
|
|
3595
|
+
sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 },
|
|
3596
|
+
children: m.user_id
|
|
3597
|
+
}
|
|
3598
|
+
)
|
|
3599
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3600
|
+
import_Typography8.default,
|
|
3601
|
+
{
|
|
3602
|
+
variant: "body2",
|
|
3603
|
+
sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" },
|
|
3604
|
+
children: m.user_id
|
|
3605
|
+
}
|
|
3606
|
+
) }),
|
|
3607
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false }) }),
|
|
3608
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_TableCell2.default, { align: "right", children: (() => {
|
|
3609
|
+
const { disabled, reason } = isRemovalDisabled(m.user_id, m.role);
|
|
3610
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Tooltip4.default, { title: reason ?? "", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3611
|
+
import_IconButton4.default,
|
|
3612
|
+
{
|
|
3613
|
+
edge: "end",
|
|
3614
|
+
size: "small",
|
|
3615
|
+
"aria-label": `remove ${m.user_id}`,
|
|
3616
|
+
disabled: memberBusy || disabled,
|
|
3617
|
+
onClick: () => handleRemoveMember(m.user_id),
|
|
3618
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_icons_material5.Delete, { fontSize: "small" })
|
|
3619
|
+
}
|
|
3620
|
+
) }) });
|
|
3621
|
+
})() })
|
|
3622
|
+
] }, m.user_id)) })
|
|
3623
|
+
] }) }),
|
|
3624
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Box10.default, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" }, children: [
|
|
3625
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3626
|
+
import_Autocomplete2.default,
|
|
3627
|
+
{
|
|
3628
|
+
freeSolo: true,
|
|
3629
|
+
autoHighlight: true,
|
|
3630
|
+
options: userOptions,
|
|
3631
|
+
loading: usersLoading,
|
|
3632
|
+
inputValue: memberQuery,
|
|
3633
|
+
onInputChange: (_, newInputValue, reason) => {
|
|
3634
|
+
setMemberQuery(newInputValue);
|
|
3635
|
+
if (reason === "input" || reason === "clear") {
|
|
3636
|
+
setMemberRef(newInputValue);
|
|
3637
|
+
handleUserSearch(newInputValue);
|
|
3638
|
+
}
|
|
3639
|
+
},
|
|
3640
|
+
onChange: (_, newValue) => {
|
|
3641
|
+
if (newValue && typeof newValue !== "string") {
|
|
3642
|
+
setMemberQuery(newValue.label);
|
|
3643
|
+
setMemberRef(newValue.ref);
|
|
3644
|
+
}
|
|
3645
|
+
},
|
|
3646
|
+
getOptionLabel: (o) => typeof o === "string" ? o : o.label,
|
|
3647
|
+
isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
|
|
3648
|
+
disabled: memberBusy,
|
|
3649
|
+
sx: { flex: "1 1 240px" },
|
|
3650
|
+
renderInput: (params) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3651
|
+
import_TextField3.default,
|
|
3652
|
+
{
|
|
3653
|
+
...params,
|
|
3654
|
+
label: "Add member",
|
|
3655
|
+
placeholder: "Search by name or email\u2026",
|
|
3656
|
+
size: "small",
|
|
3657
|
+
helperText: "Pick a catalog user, or paste a user entity ref",
|
|
3658
|
+
InputProps: {
|
|
3659
|
+
...params.InputProps,
|
|
3660
|
+
endAdornment: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
|
|
3661
|
+
usersLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_CircularProgress3.default, { color: "inherit", size: 14 }) : null,
|
|
3662
|
+
params.InputProps.endAdornment
|
|
3663
|
+
] })
|
|
3664
|
+
}
|
|
3665
|
+
}
|
|
3666
|
+
)
|
|
3667
|
+
}
|
|
3668
|
+
),
|
|
3669
|
+
!membersOnly && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3670
|
+
import_TextField3.default,
|
|
3671
|
+
{
|
|
3672
|
+
label: "Max budget in team ($)",
|
|
3673
|
+
type: "number",
|
|
3674
|
+
value: memberBudget,
|
|
3675
|
+
onChange: (e) => setMemberBudget(e.target.value),
|
|
3676
|
+
disabled: memberBusy,
|
|
3677
|
+
size: "small",
|
|
3678
|
+
sx: { width: 150 }
|
|
3679
|
+
}
|
|
3680
|
+
),
|
|
3681
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
3682
|
+
import_Button4.default,
|
|
3683
|
+
{
|
|
3684
|
+
onClick: handleAddMember,
|
|
3685
|
+
disabled: memberBusy || !memberRef.trim(),
|
|
3686
|
+
variant: "outlined",
|
|
3687
|
+
sx: { mt: 0.5 },
|
|
3688
|
+
children: "Add"
|
|
3689
|
+
}
|
|
3690
|
+
)
|
|
3691
|
+
] })
|
|
3692
|
+
] })
|
|
3693
|
+
]
|
|
3694
|
+
}
|
|
3695
|
+
),
|
|
3633
3696
|
!membersOnly && showKnowledgeBases && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_Box10.default, { children: [
|
|
3634
3697
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Divider2.default, { sx: { my: 1 } }),
|
|
3635
3698
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Typography8.default, { variant: "subtitle2", sx: { mb: 1 }, children: "Knowledge Bases" }),
|
|
@@ -3687,7 +3750,7 @@ var init_ManageTeamDialog = __esm({
|
|
|
3687
3750
|
] }),
|
|
3688
3751
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_DialogActions3.default, { children: [
|
|
3689
3752
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Button4.default, { onClick: onClose, disabled: submitting, children: membersOnly ? "Done" : "Cancel" }),
|
|
3690
|
-
!membersOnly && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Button4.default, { onClick: handleSubmit, disabled: submitting, variant: "contained", children: submitting ? "Saving..." :
|
|
3753
|
+
!membersOnly && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_Button4.default, { onClick: handleSubmit, disabled: submitting, variant: "contained", children: submitting ? "Saving..." : submitLabel })
|
|
3691
3754
|
] })
|
|
3692
3755
|
] });
|
|
3693
3756
|
};
|
|
@@ -5833,15 +5896,6 @@ var init_dates = __esm({
|
|
|
5833
5896
|
}
|
|
5834
5897
|
});
|
|
5835
5898
|
|
|
5836
|
-
// src/permissions.ts
|
|
5837
|
-
var import_backstage_plugin_litellm_common5;
|
|
5838
|
-
var init_permissions = __esm({
|
|
5839
|
-
"src/permissions.ts"() {
|
|
5840
|
-
"use strict";
|
|
5841
|
-
import_backstage_plugin_litellm_common5 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
5842
|
-
}
|
|
5843
|
-
});
|
|
5844
|
-
|
|
5845
5899
|
// src/feedback.ts
|
|
5846
5900
|
function toastFor(kind, errorMsg) {
|
|
5847
5901
|
switch (kind) {
|
|
@@ -5950,7 +6004,7 @@ function initDateRange() {
|
|
|
5950
6004
|
else start.setDate(start.getDate() - 7);
|
|
5951
6005
|
return { start, end };
|
|
5952
6006
|
}
|
|
5953
|
-
var import_react13, import_Box17, import_Alert6, import_Button7, import_Typography15, import_Tabs2, import_Tab2, import_Grid2, import_Accordion2, import_AccordionSummary2, import_AccordionDetails2, import_ExpandMore, import_react_router_dom, import_react_use2, import_core_plugin_api5, import_core_components3, import_plugin_permission_react3, import_jsx_runtime18, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
|
|
6007
|
+
var import_react13, import_Box17, import_Alert6, import_Button7, import_Typography15, import_Tabs2, import_Tab2, import_Grid2, import_Accordion2, import_AccordionSummary2, import_AccordionDetails2, import_ExpandMore, import_react_router_dom, import_react_use2, import_core_plugin_api5, import_core_components3, import_plugin_permission_react3, import_backstage_plugin_litellm_common5, import_jsx_runtime18, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
|
|
5954
6008
|
var init_LiteLLMPage = __esm({
|
|
5955
6009
|
"src/components/LiteLLMPage.tsx"() {
|
|
5956
6010
|
"use strict";
|
|
@@ -5982,7 +6036,7 @@ var init_LiteLLMPage = __esm({
|
|
|
5982
6036
|
init_AuditLog();
|
|
5983
6037
|
init_api();
|
|
5984
6038
|
init_dates();
|
|
5985
|
-
|
|
6039
|
+
import_backstage_plugin_litellm_common5 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
5986
6040
|
init_feedback();
|
|
5987
6041
|
init_teamMemberManager();
|
|
5988
6042
|
init_unprovisionedCopy();
|
|
@@ -6505,7 +6559,7 @@ var init_LiteLLMPage = __esm({
|
|
|
6505
6559
|
membersOnly: manageTeam?.mode === "members",
|
|
6506
6560
|
currentUserId: userInfo?.user_id,
|
|
6507
6561
|
memberManagerRoles: liteLlmConfig?.teamManagement?.memberManagerRoles,
|
|
6508
|
-
onSubmit: async (payload) => {
|
|
6562
|
+
onSubmit: async (payload, initialMembers) => {
|
|
6509
6563
|
try {
|
|
6510
6564
|
if (manageTeam?.mode === "edit" && manageTeam.team) {
|
|
6511
6565
|
const loadedAt = manageTeam.team.metadata?.updated_at_iso;
|
|
@@ -6515,7 +6569,23 @@ var init_LiteLLMPage = __esm({
|
|
|
6515
6569
|
...typeof loadedAt === "string" ? { expectedUpdatedAtIso: loadedAt } : {}
|
|
6516
6570
|
});
|
|
6517
6571
|
} else {
|
|
6518
|
-
await api.createTeam(payload);
|
|
6572
|
+
const created = await api.createTeam(payload);
|
|
6573
|
+
const failed = [];
|
|
6574
|
+
for (const m of initialMembers ?? []) {
|
|
6575
|
+
try {
|
|
6576
|
+
await api.addTeamMember(created.team_id, m);
|
|
6577
|
+
} catch (e) {
|
|
6578
|
+
failed.push(`${m.userEntityRef} (${e.message})`);
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6581
|
+
if (failed.length) {
|
|
6582
|
+
alertApi.post({
|
|
6583
|
+
message: `Team created, but some members could not be added: ${failed.join(", ")}`,
|
|
6584
|
+
severity: "warning"
|
|
6585
|
+
});
|
|
6586
|
+
refreshTeams();
|
|
6587
|
+
return;
|
|
6588
|
+
}
|
|
6519
6589
|
}
|
|
6520
6590
|
const alert = toastFor("teamSaveSuccess");
|
|
6521
6591
|
if (alert) alertApi.post(alert);
|
|
@@ -6592,7 +6662,6 @@ var index_exports = {};
|
|
|
6592
6662
|
__export(index_exports, {
|
|
6593
6663
|
DashboardHeader: () => DashboardHeader,
|
|
6594
6664
|
GenerateKeyButton: () => GenerateKeyButton,
|
|
6595
|
-
GenerateKeyDialog: () => GenerateKeyDialog,
|
|
6596
6665
|
KeyFormDialog: () => KeyFormDialog,
|
|
6597
6666
|
KeysTable: () => KeysTable,
|
|
6598
6667
|
LiteLLMBudgetGauges: () => LiteLLMBudgetGauges,
|
|
@@ -6603,13 +6672,14 @@ __export(index_exports, {
|
|
|
6603
6672
|
ManageTeamDialog: () => ManageTeamDialog,
|
|
6604
6673
|
TeamUsage: () => TeamUsage,
|
|
6605
6674
|
UsageStats: () => UsageStats,
|
|
6675
|
+
default: () => litellmPlugin,
|
|
6606
6676
|
liteLlmApiRef: () => liteLlmApiRef,
|
|
6607
6677
|
litellmPlugin: () => litellmPlugin,
|
|
6608
|
-
litellmTeamCreatePermission: () =>
|
|
6609
|
-
litellmTeamKnowledgebaseManagePermission: () =>
|
|
6610
|
-
litellmTeamManagePermission: () =>
|
|
6611
|
-
litellmTeamMcpManagePermission: () =>
|
|
6612
|
-
litellmTeamMembersManagePermission: () =>
|
|
6678
|
+
litellmTeamCreatePermission: () => import_backstage_plugin_litellm_common6.litellmTeamCreatePermission,
|
|
6679
|
+
litellmTeamKnowledgebaseManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamKnowledgebaseManagePermission,
|
|
6680
|
+
litellmTeamManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamManagePermission,
|
|
6681
|
+
litellmTeamMcpManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamMcpManagePermission,
|
|
6682
|
+
litellmTeamMembersManagePermission: () => import_backstage_plugin_litellm_common6.litellmTeamMembersManagePermission
|
|
6613
6683
|
});
|
|
6614
6684
|
module.exports = __toCommonJS(index_exports);
|
|
6615
6685
|
|
|
@@ -7540,30 +7610,7 @@ var LiteLLMBudgetGauges = ({
|
|
|
7540
7610
|
// src/index.ts
|
|
7541
7611
|
init_KeyFormDialog();
|
|
7542
7612
|
init_GenerateKeyButton();
|
|
7543
|
-
|
|
7544
|
-
// src/components/GenerateKeyDialog.tsx
|
|
7545
|
-
init_KeyFormDialog();
|
|
7546
|
-
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
7547
|
-
var GenerateKeyDialog = (props) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
7548
|
-
KeyFormDialog,
|
|
7549
|
-
{
|
|
7550
|
-
open: props.open,
|
|
7551
|
-
onClose: props.onClose,
|
|
7552
|
-
mode: "create",
|
|
7553
|
-
keys: props.keys,
|
|
7554
|
-
models: props.models,
|
|
7555
|
-
teams: props.teams,
|
|
7556
|
-
username: props.username,
|
|
7557
|
-
keyGenerationSettings: props.keyGenerationSettings,
|
|
7558
|
-
onCreateKey: props.onGenerateKey,
|
|
7559
|
-
onUpdateKey: async () => {
|
|
7560
|
-
},
|
|
7561
|
-
onGetConfig: props.onGetConfig
|
|
7562
|
-
}
|
|
7563
|
-
);
|
|
7564
|
-
|
|
7565
|
-
// src/index.ts
|
|
7566
7613
|
init_ManageTeamDialog();
|
|
7567
7614
|
init_api();
|
|
7568
|
-
|
|
7615
|
+
var import_backstage_plugin_litellm_common6 = require("@acarmisc/backstage-plugin-litellm-common");
|
|
7569
7616
|
//# sourceMappingURL=index.cjs.js.map
|