Commit graph

24 commits

Author SHA1 Message Date
yuneng-jiang
b9a267c693
refactor(ui): migrate the teams form graph off antd Form onto react-hook-form (#37417)
* test(ui): pin the teams create and update payloads before the form migration

The teams graph (Teams.tsx, TeamInfo.tsx and the MetadataKeyValueFields child they
share) is next for the antd Form to react-hook-form migration, and its submit payload
is a function of which collapsible sections the user happened to open. Nine sections
across the two files use the shadcn Collapsible, none of them passes keepMounted, and
Base UI unmounts the closed branch, so a closed section registers nothing and its keys
never reach the request body.

That matters beyond parity. /team/update reads the body with exclude_unset, so an
omitted key is never written, while an explicitly null team member budget key reaches
clear_team_member_budget_fields and nulls max_budget, budget_duration, rpm_limit and
tpm_limit on the shared budget row. antd cannot reach that today because the field is
unregistered rather than null. A port that seeds those fields or coalesces on the way
into the payload would turn a save with the section never opened into a silent clear.

The coverage that shipped with the team modal reached one of the four gating sections
on the create side and asserted key sets rather than the request body, so a null where
antd sent undefined would have passed. These cases assert both the raw payload and its
JSON round trip with toStrictEqual, which is what separates absent from null from
undefined, and they cover every gating section on both screens.

Also pinned, because each is a live behaviour a port can quietly change:

- the create path sends max_budget, tpm_limit and rpm_limit as strings, while
  team_member_budget arrives as a number through its normalize prop
- an invalid secret manager config blocks the create with its rule message suppressed
  by the item's help prop, so nothing is shown to the user
- the disable global guardrails switch is inert for a non premium user
- a value typed into a section survives collapsing and re-expanding it

Verified by adding keepMounted to all nine panels, which is the change a porter reaches
for on noticing that fields go missing: 35 of 118 went red, including every one of these
cases. The files were restored byte identical afterwards.

No production file changes here. 145 tests pass across the three files.

* refactor(ui): migrate the teams form graph off antd Form onto react-hook-form

Teams.tsx and TeamInfo.tsx were the last large antd `Form` graph in the
dashboard. Both now use `useZodForm` + `FormField`, with the shared
`MetadataKeyValueFields` child converted to a `useFieldArray`.

antd only returns the mounted registered fields from `onFinish`, so a
closed collapsible contributed no keys at all. react-hook-form keeps
unmounted values in the store (and `shouldUnregister: true` would lose
them on re-expand), so both forms project the submitted values through
the currently mounted section list before handing them to the existing
payload builders. Closed sections therefore still produce absent keys
rather than nulls, which matters at /team/update where an explicit null
clears the shared budget row.

Widgets that had no shadcn equivalent are replaced with the existing
shared ones: SearchSelect for the organization pickers, MultiSelect for
default member models, TagsInput for guardrails/policies, and a new
GuardrailsSelect for the grouped global/other guardrail dropdown.

* refactor(ui): forward the field ref to NumericalInput in the teams forms

staging turned NumericalInput into a forwardRef, so the teams graph can stop
dropping the react-hook-form ref on the floor.

* test(ui): pin the capability gate, required rules and guardrail kill switch

A mutation run over the ported teams forms found five survivors the payload
cases did not reach: the viewPolicies gate on both forms, the team name rule
on both forms, the guardrail kill switch resync, and the number coercion on a
typed model rate limit. Six cases close them.
2026-08-18 22:37:04 -07:00
Yuneng Jiang
de25e199d4
fix(ui): de-duplicate the reset budget option and polish shadcn surfaces
Create Key offered two options labelled "Never resets" in the Reset Budget
dropdown. BudgetDurationDropdown renders its unset item using the caller's
placeholder, and create_key_button passed placeholder="Never resets" alongside
showNeverResets, so the omit option and the explicit-null option looked
identical while behaving differently. An omitted budget_duration picks up
default_key_generate_params and the linked budget tier's schedule, whereas the
"none" sentinel is converted to an explicit null and truly never resets. The
unset item now reads "Not set", matching getBudgetDurationLabel, and the
create-key test mock passes the placeholder through so a future collision fails
the suite

The rest is migration cleanup found during manual QA. The models and endpoints
tab strip hides its scrollbar and fades at the right edge using a vendored copy
of the shadcn scroll-fade utility, keeping the CLI package out of the build.
globals.css neutralises the @tailwindcss/forms resting-state rules for
combobox-chip-input, which lets twelve call sites drop the same copy-pasted
className workaround. Guardrails moves to the line tab variant and stops
clipping its textarea focus ring, the log drawer JSON tree takes the app
background, the audit log empty state centres, the caching page selects no
longer stretch to the row height, the usage page team filter shares its row
with the Export button through a new filterSlot prop, and the cost optimization
and vector store tab strips drop their leftover full-width divider
2026-08-15 00:33:20 -07:00
Yuneng Jiang
a0e5c7e818
fix(ui): anchor chips-combobox popups to the field instead of the inner input
Base UI positions a combobox popup against the Combobox.Input by default. In
chips mode the visible field is the ComboboxChips wrapper and the input is a
smaller box nested inside it, so every chips-combobox in the dashboard opened
its popup 11px right of the field and 17px past its right edge.

shadcn ships the wiring for this and their combobox-multiple example uses it:
useComboboxAnchor on the chips container, passed to ComboboxContent as anchor.
The anchor prop also drives data-chips, which cancels the extra min-width an
ordinary combobox wants. Every chips site in the dashboard omitted it.

The anchor is attached through Base UI's render prop rather than a plain ref,
because React 18 drops refs on function components and ComboboxChips is one.

Adds MultiSelect's first test, covering the anchor wiring plus selection,
chip rendering and custom values.
2026-08-14 17:51:54 -07:00
Yuneng Jiang
0ee47a0028
test(ui): cover appending a second model in ModelSelect
The rewritten suite only ever picked one ordinary model, so a
regression that replaced the selection instead of appending to it
would have gone unnoticed. The case passes against the antd version
too, so it pins behavior the migration preserves rather than adds.
2026-08-14 06:12:28 -07:00
Yuneng Jiang
3a537cce4d
refactor(ui): move the model hub and model select onto shadcn primitives
Rebuilds public_model_hub, MakeSkillPublicForm, ModelSelect and the
guardrail LogViewer on the in-repo shadcn layer, so they inherit the
dashboard's design tokens instead of styling themselves through Ant
Design and Tremor.

Public prop signatures are unchanged, so no caller moves. The two
teams e2e steps that reached into antd's Select internals now drive
the combobox through its test id, role and data-slot instead.
2026-08-14 04:48:49 -07:00
Yuneng Jiang
888f911133
refactor(ui): drop unreferenced locals from tests and narrow destructures
Third and fourth slices of the sweep, combined because they raise nearly the
same question and neither changes what runs.

Nine test files plus one source file lose symbols whose only mention was
their own declaration. Ten more narrow a destructure to the keys actually
read, so `const { accessToken, userRole, userId: userID, premiumUser } =
useAuthorized()` keeps only `accessToken`. Aliases are preserved as written.

ignoreRestSiblings stays on so the omit idiom `const { tags, ...rest } =
metadata` is left alone; dropping `tags` there would fold it back into rest.

ToolDetail is held back again. Its unread binding only looks like a plain
deletion on the first pass, because the dead useMemo still reads it; one more
pass exposes a useQuery that issues a real request. That belongs with the
slices that get QA'd.

Part of LIT-5162.
2026-08-05 17:46:39 -07:00
ryan-crabbe-berri
0171170fc7
fix(ui): validate default team values in Default User Settings (#34815)
* fix(ui): validate default team values in Default User Settings

The Default User Settings form accepted any free-text team id, and the
proxy persisted it without checking the team exists. New users were then
silently never added to the default team because the consume-time 404
from team_member_add was swallowed at debug level.

Backend: PATCH /update/internal_user_settings now rejects unknown and
duplicate team ids with a 400 naming them, before any persistence or
team budget side effects. Team-add failures in _add_user_to_team now log
at ERROR with user and team ids.

UI: DefaultUserSettings rewritten as a shadcn + react-hook-form + zod
form following the org-settings pattern. The team id free-text input is
replaced with a searchable server-backed team picker, so only existing
teams can be selected; zod blocks empty and duplicate rows. The shared
deriveErrorMessage helper now unwraps the HTTPException detail.error
shape so backend validation errors surface readably in toasts.

* fix(ui): restore read-only view with Edit Settings toggle on default user settings

Parity with the pre-migration form: the tab renders a read-only summary
of the saved defaults, Edit Settings opens the RHF form, Cancel discards
pending edits and returns to the summary, and a successful save returns
to the summary showing the new values. Model sentinel labels in the
summary are derived from ModelSelect's now-exported special values
instead of duplicating the strings.

* refactor(ui): rename MODEL_SELECT_SPECIAL_VALUES_ARRAY to MODEL_SENTINEL_OPTIONS

* fix(ui): move Edit Settings into the card header action slot
2026-07-27 15:05:51 -07:00
yuneng-jiang
0a4333580f
refactor(ui): migrate request logs table onto the shared DataTable (#34343)
* refactor(ui): migrate request logs table onto the shared DataTable

Moves the Request Logs tab off the local view_logs/table.tsx clone and onto the
shared DataTable in server sort, pagination, and filter mode. The container is
split into RequestLogsPanel (data owner: the spend-logs query, the session dedup
and composition pipeline, and the detail drawer), a thin RequestLogsTable, and
RequestLogsTableColumns. The clone itself stays for now because TopModelView and
TopKeyView still consume it

The advanced filter bar moves into the shared DataTableFilterDrawer, so filters
commit on Apply and render as removable chips. That makes the per-keystroke
debounce in the query hook redundant, and the hook now takes ColumnFiltersState,
PaginationState, and SortingState directly instead of carrying its own filter
shape. Reset still restores the default 24 hour window alongside the filters

Adds shared/PaginatedSearchSelect, a Base UI combobox with server-side search and
infinite scroll, and uses it for the Key Alias and Model filters. That retires the
three logs-only antd pickers (PaginatedKeyAliasSelect, PaginatedModelSelect,
FilterTeamDropdown) and the FilterComponent molecule they plugged into. The shared
TeamDropdown is deliberately untouched: six other surfaces still render it, five of
them as a bare child of an antd Form.Item that injects value/onChange implicitly

* test(ui): pin team-scoped key alias filtering in the logs filter drawer

The Key Alias filter narrows its options to the team selected in the same
drawer, a cross-filter dependency carried over from the antd picker it
replaced. Nothing covered it: the live QA pass explicitly did not exercise
it either, so it was the one behaviour in this migration that could regress
silently

Asserts the selected team id reaches useInfiniteKeyAliases, that the lookup
stays unscoped when no team is picked, and that the scope does not leak into
the Model lookup, which shares the same combobox but takes no team
2026-07-23 17:32:08 +00:00
ryan-crabbe-berri
aa9dcb43cf
refactor(ui): standardize debounce waits behind shared DEBOUNCE_WAIT_MS constant (#33040) 2026-07-13 12:19:57 -07:00
ryan-crabbe-berri
7edf3a9cb5
style(ui): run prettier --write across the dashboard (#29622)
Formatting-only pass; no logic changes. Brings the UI into compliance
with .prettierrc so the new format-check CI job passes
2026-06-04 11:37:54 -07:00
Rick
b799f94080
fix(ui): remove blank leading entry from access group model dropdown (#27521)
Squash-merged by litellm-agent from Bytechoreographer's PR.
2026-05-09 20:30:36 +00:00
Ishaan Jaffer
817de99177 UI build 2026-02-13 12:51:17 -08:00
yuneng-jiang
83f92d6ba5 Fixing content filter guardrail update 2026-02-11 15:37:57 -08:00
yuneng-jiang
3fe1c1ba24 fixing build 2026-02-10 12:53:51 -08:00
yuneng-jiang
7fd8c0e160 Searchable Paginated Model Select For Spend Logs 2026-02-10 12:44:38 -08:00
yuneng-jiang
cf734cb586 Migrate Default Team settings to use reusable Model Select 2026-02-02 17:57:35 -08:00
yuneng-jiang
9fe3e420e9 Fixing tests 2026-01-22 15:01:06 -08:00
yuneng-jiang
ca22e08eae Add reusable model select to update organization page 2026-01-22 14:53:53 -08:00
yuneng-jiang
e406ebf0dd Model Select for Create Team 2026-01-21 18:14:45 -08:00
yuneng-jiang
fba61f8e2a adding mocks 2026-01-15 21:57:19 -08:00
yuneng-jiang
f81aefd48a Team Settings Model Select 2026-01-15 21:57:11 -08:00
yuneng-jiang
08f316b26a fixing build 2 2026-01-15 15:48:25 -08:00
yuneng-jiang
4de05d1e8d fixing build 2026-01-15 15:41:35 -08:00
yuneng-jiang
812ac7e838 Reusable model select 2026-01-15 15:19:03 -08:00