@acarmisc/backstage-plugin-litellm 0.32.0 → 0.33.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.esm.js CHANGED
@@ -3184,6 +3184,7 @@ var init_ManageTeamDialog = __esm({
3184
3184
  const [memberBudget, setMemberBudget] = useState6("");
3185
3185
  const [memberBusy, setMemberBusy] = useState6(false);
3186
3186
  const [memberError, setMemberError] = useState6(null);
3187
+ const [pendingMembers, setPendingMembers] = useState6([]);
3187
3188
  const [kbIds, setKbIds] = useState6([]);
3188
3189
  const [kbBusy, setKbBusy] = useState6(false);
3189
3190
  const [kbError, setKbError] = useState6(null);
@@ -3194,8 +3195,17 @@ var init_ManageTeamDialog = __esm({
3194
3195
  const maxBudgetCeiling = config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;
3195
3196
  const hideBudgetForManagers = config?.display?.hideTeamBudgetForManagers ?? false;
3196
3197
  const budgetWriteOnly = hideBudgetForManagers && mode === "edit";
3197
- const members = useMemo4(() => team?.members_with_roles ?? [], [team]);
3198
- const showMembers = mode === "edit" && !!canManageMembers || membersOnly;
3198
+ const creating = mode === "create";
3199
+ const members = useMemo4(
3200
+ () => creating ? pendingMembers.map((p) => ({
3201
+ user_id: p.userEntityRef,
3202
+ user_email: p.label,
3203
+ role: "user"
3204
+ })) : team?.members_with_roles ?? [],
3205
+ [creating, pendingMembers, team]
3206
+ );
3207
+ const showMembers = !!canManageMembers || !!membersOnly;
3208
+ const wide = showMembers && !membersOnly;
3199
3209
  const catalogApi = useApi3(catalogApiRef);
3200
3210
  const [searchUsers, setSearchUsers] = useState6([]);
3201
3211
  const [usersLoading, setUsersLoading] = useState6(false);
@@ -3240,8 +3250,8 @@ var init_ManageTeamDialog = __esm({
3240
3250
  email,
3241
3251
  label: email ? `${displayName} (${email})` : displayName
3242
3252
  };
3243
- }).filter((o) => !(o.email && existingEmails.has(o.email.toLowerCase()))).sort((a, b) => a.label.localeCompare(b.label));
3244
- }, [searchUsers, members]);
3253
+ }).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));
3254
+ }, [searchUsers, members, pendingMembers]);
3245
3255
  useEffect4(() => {
3246
3256
  return () => {
3247
3257
  if (debounceTimerRef.current) {
@@ -3275,6 +3285,7 @@ var init_ManageTeamDialog = __esm({
3275
3285
  setMemberRef("");
3276
3286
  setMemberBudget("");
3277
3287
  setMemberError(null);
3288
+ setPendingMembers([]);
3278
3289
  setKbIds(team?.object_permission?.vector_stores ?? []);
3279
3290
  setKbError(null);
3280
3291
  setMcpIds(team?.object_permission?.mcp_servers ?? []);
@@ -3333,7 +3344,13 @@ var init_ManageTeamDialog = __esm({
3333
3344
  ...budgetDuration && { budget_duration: budgetDuration }
3334
3345
  };
3335
3346
  }
3336
- await onSubmit(payload);
3347
+ await onSubmit(
3348
+ payload,
3349
+ creating ? pendingMembers.map(({ userEntityRef, maxBudgetInTeam }) => ({
3350
+ userEntityRef,
3351
+ ...maxBudgetInTeam !== void 0 && { maxBudgetInTeam }
3352
+ })) : void 0
3353
+ );
3337
3354
  onClose();
3338
3355
  } catch (err) {
3339
3356
  setError(err instanceof Error ? err.message : "An error occurred");
@@ -3342,13 +3359,26 @@ var init_ManageTeamDialog = __esm({
3342
3359
  }
3343
3360
  };
3344
3361
  const handleAddMember = async () => {
3345
- if (!onAddMember || !memberRef.trim()) return;
3362
+ if (!memberRef.trim() || !creating && !onAddMember) return;
3346
3363
  setMemberError(null);
3347
3364
  const budget = !membersOnly && memberBudget ? parseFloat(memberBudget) : void 0;
3348
3365
  if (budget !== void 0 && (isNaN(budget) || budget <= 0)) {
3349
3366
  setMemberError("Max budget in team must be a positive number");
3350
3367
  return;
3351
3368
  }
3369
+ if (creating) {
3370
+ const ref = memberRef.trim();
3371
+ if (!pendingMembers.some((p) => p.userEntityRef === ref)) {
3372
+ setPendingMembers((list) => [
3373
+ ...list,
3374
+ { userEntityRef: ref, label: memberQuery.trim() || ref, maxBudgetInTeam: budget }
3375
+ ]);
3376
+ }
3377
+ setMemberQuery("");
3378
+ setMemberRef("");
3379
+ setMemberBudget("");
3380
+ return;
3381
+ }
3352
3382
  try {
3353
3383
  setMemberBusy(true);
3354
3384
  await onAddMember(memberRef.trim(), budget);
@@ -3362,6 +3392,10 @@ var init_ManageTeamDialog = __esm({
3362
3392
  }
3363
3393
  };
3364
3394
  const handleRemoveMember = async (userId) => {
3395
+ if (creating) {
3396
+ setPendingMembers((list) => list.filter((p) => p.userEntityRef !== userId));
3397
+ return;
3398
+ }
3365
3399
  if (!onRemoveMember) return;
3366
3400
  setMemberError(null);
3367
3401
  try {
@@ -3415,13 +3449,14 @@ var init_ManageTeamDialog = __esm({
3415
3449
  }
3416
3450
  return { disabled: false };
3417
3451
  };
3452
+ const submitLabel = creating ? "Create team" : "Save";
3418
3453
  const getDialogTitle = () => {
3419
3454
  if (membersOnly) {
3420
3455
  return `Manage members \u2014 ${team?.team_alias || "Untitled team"}`;
3421
3456
  }
3422
3457
  return mode === "create" ? "Create Team" : "Edit Team";
3423
3458
  };
3424
- return /* @__PURE__ */ jsxs10(Dialog3, { open, onClose, maxWidth: "sm", fullWidth: true, children: [
3459
+ return /* @__PURE__ */ jsxs10(Dialog3, { open, onClose, maxWidth: wide ? "md" : "sm", fullWidth: true, children: [
3425
3460
  /* @__PURE__ */ jsx11(DialogTitle3, { children: getDialogTitle() }),
3426
3461
  /* @__PURE__ */ jsxs10(DialogContent3, { sx: { pt: 2, display: "flex", flexDirection: "column", gap: 2 }, children: [
3427
3462
  error && /* @__PURE__ */ jsx11(Alert2, { severity: "error", children: error }),
@@ -3430,186 +3465,215 @@ var init_ManageTeamDialog = __esm({
3430
3465
  team?.members_with_roles?.find((m) => m.user_id === currentUserId)?.role || "member",
3431
3466
  " you can add or remove members. Budgets and models are managed by your platform admins."
3432
3467
  ] }),
3433
- !membersOnly && /* @__PURE__ */ jsxs10(Fragment4, { children: [
3434
- /* @__PURE__ */ jsx11(
3435
- TextField3,
3436
- {
3437
- label: "Team Alias",
3438
- value: alias,
3439
- onChange: (e) => setAlias(e.target.value),
3440
- disabled: submitting,
3441
- fullWidth: true
3442
- }
3443
- ),
3444
- /* @__PURE__ */ jsx11(
3445
- Autocomplete2,
3446
- {
3447
- multiple: true,
3448
- options: modelNames,
3449
- value: models,
3450
- onChange: (_, newValue) => setModels(newValue),
3451
- disabled: submitting,
3452
- renderInput: (params) => /* @__PURE__ */ jsx11(
3453
- TextField3,
3454
- {
3455
- ...params,
3456
- label: "Models",
3457
- required: true,
3458
- 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.)"
3459
- }
3460
- )
3461
- }
3462
- ),
3463
- /* @__PURE__ */ jsx11(
3464
- TextField3,
3465
- {
3466
- label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
3467
- type: "number",
3468
- value: maxBudget,
3469
- onChange: (e) => setMaxBudget(e.target.value),
3470
- disabled: submitting || unlimited,
3471
- inputProps: { min: 0, max: maxBudgetCeiling },
3472
- helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
3473
- fullWidth: true
3474
- }
3475
- ),
3476
- allowUnlimitedBudget && /* @__PURE__ */ jsx11(
3477
- FormControlLabel2,
3478
- {
3479
- control: /* @__PURE__ */ jsx11(Checkbox2, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
3480
- label: "Unlimited Budget"
3481
- }
3482
- ),
3483
- /* @__PURE__ */ jsx11(
3484
- TextField3,
3485
- {
3486
- select: true,
3487
- label: "Budget Duration",
3488
- value: budgetDuration,
3489
- onChange: (e) => setBudgetDuration(e.target.value),
3490
- disabled: submitting || unlimited,
3491
- helperText: "Spend-reset period for the team budget",
3492
- fullWidth: true,
3493
- children: durationOptions.map((o) => /* @__PURE__ */ jsx11(MenuItem2, { value: o.value, children: o.label }, o.value))
3494
- }
3495
- )
3496
- ] }),
3497
- showMembers && /* @__PURE__ */ jsxs10(Box10, { children: [
3498
- /* @__PURE__ */ jsx11(Divider2, { sx: { my: 1 } }),
3499
- /* @__PURE__ */ jsx11(Typography8, { variant: "subtitle2", sx: { mb: 1 }, children: "Members" }),
3500
- memberError && /* @__PURE__ */ jsx11(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null), children: memberError }),
3501
- members.length === 0 ? /* @__PURE__ */ jsx11(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: "No members yet." }) : /* @__PURE__ */ jsx11(TableContainer2, { component: Paper4, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 }, children: /* @__PURE__ */ jsxs10(Table2, { size: "small", sx: dataTableSx, children: [
3502
- /* @__PURE__ */ jsx11(TableHead2, { children: /* @__PURE__ */ jsxs10(TableRow2, { children: [
3503
- /* @__PURE__ */ jsx11(TableCell2, { children: "User" }),
3504
- /* @__PURE__ */ jsx11(TableCell2, { align: "right", children: "Role" }),
3505
- /* @__PURE__ */ jsx11(TableCell2, { align: "right", sx: { width: 40 } })
3506
- ] }) }),
3507
- /* @__PURE__ */ jsx11(TableBody2, { children: members.map((m) => /* @__PURE__ */ jsxs10(TableRow2, { children: [
3508
- /* @__PURE__ */ jsx11(TableCell2, { children: m.user_email ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
3509
- /* @__PURE__ */ jsx11(Typography8, { variant: "body2", children: m.user_email }),
3468
+ /* @__PURE__ */ jsxs10(
3469
+ Box10,
3470
+ {
3471
+ sx: {
3472
+ display: "grid",
3473
+ gridTemplateColumns: {
3474
+ xs: "1fr",
3475
+ md: wide ? "minmax(0, 1fr) minmax(0, 1fr)" : "1fr"
3476
+ },
3477
+ gap: 3,
3478
+ alignItems: "start"
3479
+ },
3480
+ children: [
3481
+ !membersOnly && /* @__PURE__ */ jsxs10(Box10, { sx: { display: "flex", flexDirection: "column", gap: 2 }, children: [
3482
+ wide && /* @__PURE__ */ jsx11(Typography8, { variant: "subtitle2", children: "Settings" }),
3510
3483
  /* @__PURE__ */ jsx11(
3511
- Typography8,
3484
+ TextField3,
3512
3485
  {
3513
- variant: "caption",
3514
- color: "text.secondary",
3515
- sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 },
3516
- children: m.user_id
3486
+ label: "Team Alias",
3487
+ value: alias,
3488
+ onChange: (e) => setAlias(e.target.value),
3489
+ disabled: submitting,
3490
+ fullWidth: true
3517
3491
  }
3518
- )
3519
- ] }) : /* @__PURE__ */ jsx11(
3520
- Typography8,
3521
- {
3522
- variant: "body2",
3523
- sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" },
3524
- children: m.user_id
3525
- }
3526
- ) }),
3527
- /* @__PURE__ */ jsx11(TableCell2, { align: "right", children: /* @__PURE__ */ jsx11(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false }) }),
3528
- /* @__PURE__ */ jsx11(TableCell2, { align: "right", children: (() => {
3529
- const { disabled, reason } = isRemovalDisabled(m.user_id, m.role);
3530
- return /* @__PURE__ */ jsx11(Tooltip4, { title: reason ?? "", children: /* @__PURE__ */ jsx11("span", { children: /* @__PURE__ */ jsx11(
3531
- IconButton4,
3492
+ ),
3493
+ /* @__PURE__ */ jsx11(
3494
+ Autocomplete2,
3532
3495
  {
3533
- edge: "end",
3534
- size: "small",
3535
- "aria-label": `remove ${m.user_id}`,
3536
- disabled: memberBusy || disabled,
3537
- onClick: () => handleRemoveMember(m.user_id),
3538
- children: /* @__PURE__ */ jsx11(DeleteIcon, { fontSize: "small" })
3539
- }
3540
- ) }) });
3541
- })() })
3542
- ] }, m.user_id)) })
3543
- ] }) }),
3544
- /* @__PURE__ */ jsxs10(Box10, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" }, children: [
3545
- /* @__PURE__ */ jsx11(
3546
- Autocomplete2,
3547
- {
3548
- freeSolo: true,
3549
- autoHighlight: true,
3550
- options: userOptions,
3551
- loading: usersLoading,
3552
- inputValue: memberQuery,
3553
- onInputChange: (_, newInputValue, reason) => {
3554
- setMemberQuery(newInputValue);
3555
- if (reason === "input" || reason === "clear") {
3556
- setMemberRef(newInputValue);
3557
- handleUserSearch(newInputValue);
3496
+ multiple: true,
3497
+ options: modelNames,
3498
+ value: models,
3499
+ onChange: (_, newValue) => setModels(newValue),
3500
+ disabled: submitting,
3501
+ renderInput: (params) => /* @__PURE__ */ jsx11(
3502
+ TextField3,
3503
+ {
3504
+ ...params,
3505
+ label: "Models",
3506
+ required: true,
3507
+ helperText: "Only models your admin allow-listed for teams. At least one is required."
3508
+ }
3509
+ )
3558
3510
  }
3559
- },
3560
- onChange: (_, newValue) => {
3561
- if (newValue && typeof newValue !== "string") {
3562
- setMemberQuery(newValue.label);
3563
- setMemberRef(newValue.ref);
3511
+ ),
3512
+ /* @__PURE__ */ jsxs10(
3513
+ Box10,
3514
+ {
3515
+ sx: {
3516
+ display: "grid",
3517
+ gridTemplateColumns: { xs: "1fr", sm: "1fr 1fr" },
3518
+ gap: 2
3519
+ },
3520
+ children: [
3521
+ /* @__PURE__ */ jsx11(
3522
+ TextField3,
3523
+ {
3524
+ label: budgetWriteOnly ? "New Max Budget ($)" : "Max Budget ($)",
3525
+ type: "number",
3526
+ value: maxBudget,
3527
+ onChange: (e) => setMaxBudget(e.target.value),
3528
+ disabled: submitting || unlimited,
3529
+ inputProps: { min: 0, max: maxBudgetCeiling },
3530
+ helperText: budgetWriteOnly ? "Current budget is hidden \u2014 leave blank to keep it, or enter a new value" : `Maximum: $${maxBudgetCeiling}`,
3531
+ fullWidth: true
3532
+ }
3533
+ ),
3534
+ /* @__PURE__ */ jsx11(
3535
+ TextField3,
3536
+ {
3537
+ select: true,
3538
+ label: "Budget Duration",
3539
+ value: budgetDuration,
3540
+ onChange: (e) => setBudgetDuration(e.target.value),
3541
+ disabled: submitting || unlimited,
3542
+ helperText: "Spend-reset period for the team budget",
3543
+ fullWidth: true,
3544
+ children: durationOptions.map((o) => /* @__PURE__ */ jsx11(MenuItem2, { value: o.value, children: o.label }, o.value))
3545
+ }
3546
+ )
3547
+ ]
3564
3548
  }
3565
- },
3566
- getOptionLabel: (o) => typeof o === "string" ? o : o.label,
3567
- isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
3568
- disabled: memberBusy,
3569
- sx: { flex: 1, minWidth: 260 },
3570
- renderInput: (params) => /* @__PURE__ */ jsx11(
3571
- TextField3,
3549
+ ),
3550
+ allowUnlimitedBudget && /* @__PURE__ */ jsx11(
3551
+ FormControlLabel2,
3572
3552
  {
3573
- ...params,
3574
- label: "Add member",
3575
- placeholder: "Search by name or email\u2026",
3576
- size: "small",
3577
- helperText: "Pick a catalog user, or paste a user entity ref",
3578
- InputProps: {
3579
- ...params.InputProps,
3580
- endAdornment: /* @__PURE__ */ jsxs10(Fragment4, { children: [
3581
- usersLoading ? /* @__PURE__ */ jsx11(CircularProgress3, { color: "inherit", size: 14 }) : null,
3582
- params.InputProps.endAdornment
3583
- ] })
3584
- }
3553
+ control: /* @__PURE__ */ jsx11(Checkbox2, { checked: unlimited, onChange: (e) => setUnlimited(e.target.checked), disabled: submitting }),
3554
+ label: "Unlimited Budget"
3585
3555
  }
3586
3556
  )
3587
- }
3588
- ),
3589
- !membersOnly && /* @__PURE__ */ jsx11(
3590
- TextField3,
3591
- {
3592
- label: "Max budget in team ($)",
3593
- type: "number",
3594
- value: memberBudget,
3595
- onChange: (e) => setMemberBudget(e.target.value),
3596
- disabled: memberBusy,
3597
- size: "small",
3598
- sx: { width: 160 }
3599
- }
3600
- ),
3601
- /* @__PURE__ */ jsx11(
3602
- Button4,
3603
- {
3604
- onClick: handleAddMember,
3605
- disabled: memberBusy || !memberRef.trim(),
3606
- variant: "outlined",
3607
- sx: { mt: 0.5 },
3608
- children: "Add"
3609
- }
3610
- )
3611
- ] })
3612
- ] }),
3557
+ ] }),
3558
+ showMembers && /* @__PURE__ */ jsxs10(Box10, { children: [
3559
+ /* @__PURE__ */ jsx11(Typography8, { variant: "subtitle2", sx: { mb: creating ? 0.25 : 1 }, children: creating ? "Initial members" : "Members" }),
3560
+ creating && /* @__PURE__ */ jsx11(Typography8, { variant: "body2", color: "text.secondary", sx: { mb: 1 }, children: "Added as team users right after the team is created." }),
3561
+ memberError && /* @__PURE__ */ jsx11(Alert2, { severity: "error", sx: { mb: 1 }, onClose: () => setMemberError(null), children: memberError }),
3562
+ members.length === 0 ? /* @__PURE__ */ jsx11(Typography8, { 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__ */ jsx11(TableContainer2, { component: Paper4, variant: "outlined", sx: { borderRadius: 1.5, mb: 1.5 }, children: /* @__PURE__ */ jsxs10(Table2, { size: "small", sx: dataTableSx, children: [
3563
+ /* @__PURE__ */ jsx11(TableHead2, { children: /* @__PURE__ */ jsxs10(TableRow2, { children: [
3564
+ /* @__PURE__ */ jsx11(TableCell2, { children: "User" }),
3565
+ /* @__PURE__ */ jsx11(TableCell2, { align: "right", children: "Role" }),
3566
+ /* @__PURE__ */ jsx11(TableCell2, { align: "right", sx: { width: 40 } })
3567
+ ] }) }),
3568
+ /* @__PURE__ */ jsx11(TableBody2, { children: members.map((m) => /* @__PURE__ */ jsxs10(TableRow2, { children: [
3569
+ /* @__PURE__ */ jsx11(TableCell2, { children: m.user_email ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
3570
+ /* @__PURE__ */ jsx11(Typography8, { variant: "body2", children: m.user_email }),
3571
+ /* @__PURE__ */ jsx11(
3572
+ Typography8,
3573
+ {
3574
+ variant: "caption",
3575
+ color: "text.secondary",
3576
+ sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", fontSize: 11 },
3577
+ children: m.user_id
3578
+ }
3579
+ )
3580
+ ] }) : /* @__PURE__ */ jsx11(
3581
+ Typography8,
3582
+ {
3583
+ variant: "body2",
3584
+ sx: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" },
3585
+ children: m.user_id
3586
+ }
3587
+ ) }),
3588
+ /* @__PURE__ */ jsx11(TableCell2, { align: "right", children: /* @__PURE__ */ jsx11(StatusPill, { label: m.role, tone: m.role === "admin" ? "accent" : "neutral", dot: false }) }),
3589
+ /* @__PURE__ */ jsx11(TableCell2, { align: "right", children: (() => {
3590
+ const { disabled, reason } = isRemovalDisabled(m.user_id, m.role);
3591
+ return /* @__PURE__ */ jsx11(Tooltip4, { title: reason ?? "", children: /* @__PURE__ */ jsx11("span", { children: /* @__PURE__ */ jsx11(
3592
+ IconButton4,
3593
+ {
3594
+ edge: "end",
3595
+ size: "small",
3596
+ "aria-label": `remove ${m.user_id}`,
3597
+ disabled: memberBusy || disabled,
3598
+ onClick: () => handleRemoveMember(m.user_id),
3599
+ children: /* @__PURE__ */ jsx11(DeleteIcon, { fontSize: "small" })
3600
+ }
3601
+ ) }) });
3602
+ })() })
3603
+ ] }, m.user_id)) })
3604
+ ] }) }),
3605
+ /* @__PURE__ */ jsxs10(Box10, { sx: { display: "flex", gap: 1, alignItems: "flex-start", flexWrap: "wrap" }, children: [
3606
+ /* @__PURE__ */ jsx11(
3607
+ Autocomplete2,
3608
+ {
3609
+ freeSolo: true,
3610
+ autoHighlight: true,
3611
+ options: userOptions,
3612
+ loading: usersLoading,
3613
+ inputValue: memberQuery,
3614
+ onInputChange: (_, newInputValue, reason) => {
3615
+ setMemberQuery(newInputValue);
3616
+ if (reason === "input" || reason === "clear") {
3617
+ setMemberRef(newInputValue);
3618
+ handleUserSearch(newInputValue);
3619
+ }
3620
+ },
3621
+ onChange: (_, newValue) => {
3622
+ if (newValue && typeof newValue !== "string") {
3623
+ setMemberQuery(newValue.label);
3624
+ setMemberRef(newValue.ref);
3625
+ }
3626
+ },
3627
+ getOptionLabel: (o) => typeof o === "string" ? o : o.label,
3628
+ isOptionEqualToValue: (o, v) => o.ref === (typeof v === "string" ? v : v.ref),
3629
+ disabled: memberBusy,
3630
+ sx: { flex: "1 1 240px" },
3631
+ renderInput: (params) => /* @__PURE__ */ jsx11(
3632
+ TextField3,
3633
+ {
3634
+ ...params,
3635
+ label: "Add member",
3636
+ placeholder: "Search by name or email\u2026",
3637
+ size: "small",
3638
+ helperText: "Pick a catalog user, or paste a user entity ref",
3639
+ InputProps: {
3640
+ ...params.InputProps,
3641
+ endAdornment: /* @__PURE__ */ jsxs10(Fragment4, { children: [
3642
+ usersLoading ? /* @__PURE__ */ jsx11(CircularProgress3, { color: "inherit", size: 14 }) : null,
3643
+ params.InputProps.endAdornment
3644
+ ] })
3645
+ }
3646
+ }
3647
+ )
3648
+ }
3649
+ ),
3650
+ !membersOnly && /* @__PURE__ */ jsx11(
3651
+ TextField3,
3652
+ {
3653
+ label: "Max budget in team ($)",
3654
+ type: "number",
3655
+ value: memberBudget,
3656
+ onChange: (e) => setMemberBudget(e.target.value),
3657
+ disabled: memberBusy,
3658
+ size: "small",
3659
+ sx: { width: 150 }
3660
+ }
3661
+ ),
3662
+ /* @__PURE__ */ jsx11(
3663
+ Button4,
3664
+ {
3665
+ onClick: handleAddMember,
3666
+ disabled: memberBusy || !memberRef.trim(),
3667
+ variant: "outlined",
3668
+ sx: { mt: 0.5 },
3669
+ children: "Add"
3670
+ }
3671
+ )
3672
+ ] })
3673
+ ] })
3674
+ ]
3675
+ }
3676
+ ),
3613
3677
  !membersOnly && showKnowledgeBases && /* @__PURE__ */ jsxs10(Box10, { children: [
3614
3678
  /* @__PURE__ */ jsx11(Divider2, { sx: { my: 1 } }),
3615
3679
  /* @__PURE__ */ jsx11(Typography8, { variant: "subtitle2", sx: { mb: 1 }, children: "Knowledge Bases" }),
@@ -3667,7 +3731,7 @@ var init_ManageTeamDialog = __esm({
3667
3731
  ] }),
3668
3732
  /* @__PURE__ */ jsxs10(DialogActions3, { children: [
3669
3733
  /* @__PURE__ */ jsx11(Button4, { onClick: onClose, disabled: submitting, children: membersOnly ? "Done" : "Cancel" }),
3670
- !membersOnly && /* @__PURE__ */ jsx11(Button4, { onClick: handleSubmit, disabled: submitting, variant: "contained", children: submitting ? "Saving..." : "Save" })
3734
+ !membersOnly && /* @__PURE__ */ jsx11(Button4, { onClick: handleSubmit, disabled: submitting, variant: "contained", children: submitting ? "Saving..." : submitLabel })
3671
3735
  ] })
3672
3736
  ] });
3673
3737
  };
@@ -6521,7 +6585,7 @@ var init_LiteLLMPage = __esm({
6521
6585
  membersOnly: manageTeam?.mode === "members",
6522
6586
  currentUserId: userInfo?.user_id,
6523
6587
  memberManagerRoles: liteLlmConfig?.teamManagement?.memberManagerRoles,
6524
- onSubmit: async (payload) => {
6588
+ onSubmit: async (payload, initialMembers) => {
6525
6589
  try {
6526
6590
  if (manageTeam?.mode === "edit" && manageTeam.team) {
6527
6591
  const loadedAt = manageTeam.team.metadata?.updated_at_iso;
@@ -6531,7 +6595,23 @@ var init_LiteLLMPage = __esm({
6531
6595
  ...typeof loadedAt === "string" ? { expectedUpdatedAtIso: loadedAt } : {}
6532
6596
  });
6533
6597
  } else {
6534
- await api.createTeam(payload);
6598
+ const created = await api.createTeam(payload);
6599
+ const failed = [];
6600
+ for (const m of initialMembers ?? []) {
6601
+ try {
6602
+ await api.addTeamMember(created.team_id, m);
6603
+ } catch (e) {
6604
+ failed.push(`${m.userEntityRef} (${e.message})`);
6605
+ }
6606
+ }
6607
+ if (failed.length) {
6608
+ alertApi.post({
6609
+ message: `Team created, but some members could not be added: ${failed.join(", ")}`,
6610
+ severity: "warning"
6611
+ });
6612
+ refreshTeams();
6613
+ return;
6614
+ }
6535
6615
  }
6536
6616
  const alert = toastFor("teamSaveSuccess");
6537
6617
  if (alert) alertApi.post(alert);