mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
fix(ui): gate the pass-through guardrail field inputs when the section is disabled (#37435)
PassThroughGuardrailsSection threads its `disabled` prop to the guardrail selector and to all three quick-add buttons, but not to the two `TagsInput` controls for request and response field targeting. Every other prop crossed, so the section greys out while a user can still type field names straight into both tag inputs. Latent rather than live: neither call site passes `disabled` today, so the prop is currently dead across the tree. This arms the gate for whoever passes it first. `TagsInput` already honours `disabled` end to end, measured rather than read: with it set, the input carries a real disabled attribute and all three commit paths, token separator, Enter and blur, are inert. So the fix belongs at the call sites and the primitive needs no change. The new test drives the control rather than asserting an attribute, since a Base UI control can paint a disabled state while still accepting input. The enabled cases are the liveness gate: they type the same text through the same gesture and assert it commits, so the disabled cases cannot pass vacuously.
This commit is contained in:
parent
0700b1e54e
commit
c696fdfb05
2 changed files with 63 additions and 0 deletions
|
|
@ -0,0 +1,61 @@
|
|||
import { render, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import PassThroughGuardrailsSection from "./PassThroughGuardrailsSection";
|
||||
|
||||
vi.mock("../networking", async (importOriginal) => ({
|
||||
...(await importOriginal<typeof import("../networking")>()),
|
||||
getGuardrailsList: vi.fn(async () => ({ guardrails: [{ guardrail_name: "pii-guard" }] })),
|
||||
}));
|
||||
|
||||
const FIELDS = [
|
||||
{ label: "Request Fields", matcher: /Request Fields/, payloadKey: "request_fields", typed: "query" },
|
||||
{ label: "Response Fields", matcher: /Response Fields/, payloadKey: "response_fields", typed: "choices.content" },
|
||||
] as const;
|
||||
|
||||
const renderSection = (disabled: boolean) => {
|
||||
const onChange = vi.fn();
|
||||
render(
|
||||
<PassThroughGuardrailsSection
|
||||
accessToken="test-token"
|
||||
value={{ "pii-guard": null }}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>,
|
||||
);
|
||||
return onChange;
|
||||
};
|
||||
|
||||
const fieldInput = (matcher: RegExp) => screen.getByLabelText(matcher) as HTMLInputElement;
|
||||
|
||||
describe("PassThroughGuardrailsSection field targeting", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it.each(FIELDS)(
|
||||
"commits a typed $label entry while the section is enabled",
|
||||
async ({ matcher, payloadKey, typed }) => {
|
||||
const user = userEvent.setup();
|
||||
const onChange = renderSection(false);
|
||||
|
||||
await user.type(fieldInput(matcher), `${typed},`);
|
||||
|
||||
expect(onChange.mock.calls.at(-1)?.[0]).toStrictEqual({ "pii-guard": { [payloadKey]: [typed] } });
|
||||
},
|
||||
);
|
||||
|
||||
it.each(FIELDS)("refuses typed $label input while the section is disabled", async ({ matcher, typed }) => {
|
||||
const user = userEvent.setup();
|
||||
const onChange = renderSection(true);
|
||||
const input = fieldInput(matcher);
|
||||
|
||||
await user.type(input, `${typed},`);
|
||||
await user.type(input, "sneaked-in{Enter}");
|
||||
await user.tab();
|
||||
|
||||
expect(input.value).toBe("");
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -174,6 +174,7 @@ const PassThroughGuardrailsSection: React.FC<PassThroughGuardrailsSectionProps>
|
|||
value={value[guardrailName]?.request_fields ?? []}
|
||||
onValueChange={(fields) => handleFieldChange(guardrailName, "request_fields", fields)}
|
||||
tokenSeparators={[","]}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Field>
|
||||
<Field>
|
||||
|
|
@ -212,6 +213,7 @@ const PassThroughGuardrailsSection: React.FC<PassThroughGuardrailsSectionProps>
|
|||
value={value[guardrailName]?.response_fields ?? []}
|
||||
onValueChange={(fields) => handleFieldChange(guardrailName, "response_fields", fields)}
|
||||
tokenSeparators={[","]}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue