Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clients/web/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ describe("App pending server-initiated request modal", () => {

// Resolving via the modal calls the queued request's respond() — this is
// what unblocks the originating call (the "spinner clears" criterion).
await user.click(screen.getByRole("button", { name: "Auto-respond" }));
await user.click(screen.getByRole("button", { name: "Send Response" }));
expect(respond).toHaveBeenCalledTimes(1);

// The client clearing its queue (empty event) closes the modal.
Expand Down
10 changes: 10 additions & 0 deletions clients/web/src/components/groups/AppControls/AppControls.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
CloseButton,
Group,
ScrollArea,
Stack,
Expand Down Expand Up @@ -61,6 +62,15 @@ export function AppControls({
placeholder="Search apps..."
value={searchText}
onChange={(e) => onSearchChange(e.currentTarget.value)}
rightSectionPointerEvents="auto"
rightSection={
searchText ? (
<CloseButton
aria-label="Clear"
onClick={() => onSearchChange("")}
/>
) : null
}
/>
<ScrollArea.Autosize viewportRef={viewportRef} mah={LIST_MAX_HEIGHT}>
<Stack gap="xs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Button,
Card,
Checkbox,
CloseButton,
Divider,
Group,
Stack,
Expand Down Expand Up @@ -244,13 +245,31 @@ export function ExperimentalFeaturesPanel({
onChange={(e) =>
onHeaderChange(index, e.currentTarget.value, header.value)
}
rightSectionPointerEvents="auto"
rightSection={
header.key ? (
<CloseButton
aria-label="Clear"
onClick={() => onHeaderChange(index, "", header.value)}
/>
) : null
}
/>
<TextInput
placeholder="Header value"
value={header.value}
onChange={(e) =>
onHeaderChange(index, header.key, e.currentTarget.value)
}
rightSectionPointerEvents="auto"
rightSection={
header.value ? (
<CloseButton
aria-label="Clear"
onClick={() => onHeaderChange(index, header.key, "")}
/>
) : null
}
/>
<RemoveIcon onClick={() => onRemoveHeader(index)}>
<Text size="xs">✕</Text>
Expand All @@ -269,6 +288,15 @@ export function ExperimentalFeaturesPanel({
onChange={(e) => onRequestChange(e.currentTarget.value)}
autosize
minRows={6}
rightSectionPointerEvents="auto"
rightSection={
requestDraft ? (
<CloseButton
aria-label="Clear"
onClick={() => onRequestChange("")}
/>
) : null
}
/>

<Button onClick={onSendRequest}>Send Request</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ describe("HistoryControls", () => {
expect(onSearchChange).toHaveBeenCalledWith("a");
});

it("clears the search input when the Clear button is clicked", async () => {
const user = userEvent.setup();
const onSearchChange = vi.fn();
renderWithMantine(
<HistoryControls
{...baseProps}
searchText="abc"
onSearchChange={onSearchChange}
/>,
);
await user.click(screen.getByRole("button", { name: "Clear" }));
expect(onSearchChange).toHaveBeenCalledWith("");
});

it("renders the method filter placeholder", () => {
renderWithMantine(<HistoryControls {...baseProps} />);
expect(screen.getByPlaceholderText("All methods")).toBeInTheDocument();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Select, Stack, TextInput, Title } from "@mantine/core";
import { CloseButton, Select, Stack, TextInput, Title } from "@mantine/core";
import type {
MessageMethod,
MessageOrigin,
Expand Down Expand Up @@ -33,6 +33,15 @@ export function HistoryControls({
placeholder="Search..."
value={searchText}
onChange={(event) => onSearchChange(event.currentTarget.value)}
rightSectionPointerEvents="auto"
rightSection={
searchText ? (
<CloseButton
aria-label="Clear"
onClick={() => onSearchChange("")}
/>
) : null
}
/>

<Title order={6}>Filter by Method</Title>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,40 @@ describe("ImportServerJsonPanel", () => {
expect(onServerNameChange).toHaveBeenCalledWith("X");
});

it("clears the paste textarea, env-var, and name-override fields via Clear buttons", async () => {
const user = userEvent.setup();
const onJsonChange = vi.fn();
const onEnvVarChange = vi.fn();
const onServerNameChange = vi.fn();
const envVars: EnvVarInfo[] = [
{ name: "DEBUG", required: false, value: "true" },
];
renderWithMantine(
<ImportServerJsonPanel
{...baseHandlers}
onJsonChange={onJsonChange}
onEnvVarChange={onEnvVarChange}
onServerNameChange={onServerNameChange}
draft={{
rawText: "{}",
envOverrides: {},
nameOverride: "Custom Name",
}}
validation={[]}
envVars={envVars}
/>,
);
// DOM order: paste textarea, env-var input, name-override input.
const clearButtons = screen.getAllByRole("button", { name: "Clear" });
expect(clearButtons).toHaveLength(3);
await user.click(clearButtons[0]);
expect(onJsonChange).toHaveBeenCalledWith("");
await user.click(clearButtons[1]);
expect(onEnvVarChange).toHaveBeenCalledWith("DEBUG", "");
await user.click(clearButtons[2]);
expect(onServerNameChange).toHaveBeenCalledWith("");
});

it("renders the existing nameOverride value", () => {
renderWithMantine(
<ImportServerJsonPanel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Button,
CloseButton,
Divider,
Group,
Radio,
Expand Down Expand Up @@ -88,6 +89,12 @@ export function ImportServerJsonPanel({
autosize
minRows={8}
maxRows={15}
rightSectionPointerEvents="auto"
rightSection={
draft.rawText ? (
<CloseButton aria-label="Clear" onClick={() => onJsonChange("")} />
) : null
}
/>

<Divider />
Expand Down Expand Up @@ -139,6 +146,15 @@ export function ImportServerJsonPanel({
onChange={(e) =>
onEnvVarChange(envVar.name, e.currentTarget.value)
}
rightSectionPointerEvents="auto"
rightSection={
envVar.value ? (
<CloseButton
aria-label="Clear"
onClick={() => onEnvVarChange(envVar.name, "")}
/>
) : null
}
/>
))}
</>
Expand All @@ -150,6 +166,15 @@ export function ImportServerJsonPanel({
label="Server Name (optional override)"
value={draft.nameOverride ?? ""}
onChange={(e) => onServerNameChange(e.currentTarget.value)}
rightSectionPointerEvents="auto"
rightSection={
draft.nameOverride ? (
<CloseButton
aria-label="Clear"
onClick={() => onServerNameChange("")}
/>
) : null
}
/>

<Group justify="flex-end">
Expand Down
10 changes: 10 additions & 0 deletions clients/web/src/components/groups/LogControls/LogControls.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Button,
CloseButton,
Group,
Select,
Stack,
Expand Down Expand Up @@ -64,6 +65,15 @@ export function LogControls({
placeholder="Search..."
value={filterText}
onChange={(e) => onFilterChange(e.currentTarget.value)}
rightSectionPointerEvents="auto"
rightSection={
filterText ? (
<CloseButton
aria-label="Clear"
onClick={() => onFilterChange("")}
/>
) : null
}
/>

<Title order={5}>Set Active Level</Title>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Button,
CloseButton,
Group,
Stack,
Text,
Expand Down Expand Up @@ -45,6 +46,15 @@ export function NetworkControls({
placeholder="Search..."
value={filterText}
onChange={(e) => onFilterChange(e.currentTarget.value)}
rightSectionPointerEvents="auto"
rightSection={
filterText ? (
<CloseButton
aria-label="Clear"
onClick={() => onFilterChange("")}
/>
) : null
}
/>

<Group justify="space-between">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export const Sampling: Story = {
expect(
body.getByText("The server is requesting an LLM completion."),
).toBeInTheDocument();
await userEvent.click(body.getByRole("button", { name: "Auto-respond" }));
await userEvent.click(body.getByRole("button", { name: "Send Response" }));
expect(args.onSamplingRespond).toHaveBeenCalled();
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ describe("PendingClientRequestModal", () => {
).toBeInTheDocument();
});

it("auto-responds with a stub sampling result", async () => {
it("sends the default stub sampling result when the draft is untouched", async () => {
const user = userEvent.setup();
renderWithMantine(
<PendingClientRequestModal {...baseProps} request={samplingContent} />,
);
await user.click(screen.getByRole("button", { name: "Auto-respond" }));
await user.click(screen.getByRole("button", { name: "Send Response" }));
expect(baseProps.onSamplingRespond).toHaveBeenCalledWith({
model: "stub-model",
stopReason: "endTurn",
Expand Down Expand Up @@ -124,10 +124,10 @@ describe("PendingClientRequestModal", () => {
renderWithMantine(
<PendingClientRequestModal {...baseProps} request={samplingContent} />,
);
const autoRespond = screen.getByRole("button", { name: "Auto-respond" });
await user.click(autoRespond);
const sendResponse = screen.getByRole("button", { name: "Send Response" });
await user.click(sendResponse);
// After the first dispatch the actions lock (busy); a second click no-ops.
await user.click(autoRespond);
await user.click(sendResponse);
expect(baseProps.onSamplingRespond).toHaveBeenCalledTimes(1);
expect(
screen.getByRole("button", { name: "Send Response" }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ const TitleText = Text.withProps({ fw: 600 });
const QueueLabel = Text.withProps({ size: "xs", c: "dimmed" });

/**
* The stub result pre-filled into a sampling draft. "Auto-respond" sends this
* as-is; "Send Response" sends whatever the user edited it into.
* The stub result pre-filled into a sampling draft. "Send Response" sends this
* as-is when untouched, or whatever the user edited it into.
*/
function createDefaultSamplingResult(): CreateMessageResult {
return {
Expand Down Expand Up @@ -119,7 +119,6 @@ function SamplingModalBody({
request={request}
draftResult={draftResult}
onResultChange={setDraftResult}
onAutoRespond={once(() => onRespond(createDefaultSamplingResult()))}
onSend={once(() => onRespond(draftResult))}
onReject={once(onReject)}
busy={responded}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,23 @@ describe("PromptArgumentsForm", () => {
expect(onArgumentChange).toHaveBeenCalledWith("text", "h");
});

it("clears an argument via its Clear button (onArgumentChange with empty value)", async () => {
const user = userEvent.setup();
const onArgumentChange = vi.fn();
renderWithMantine(
<PromptArgumentsForm
prompt={promptWithArgs}
argumentValues={{ text: "Hello" }}
onArgumentChange={onArgumentChange}
onGetPrompt={vi.fn()}
/>,
);
// Non-autocomplete branch (completions unsupported) renders a TextInput
// with a Clear button whenever the value is non-empty.
await user.click(screen.getByRole("button", { name: "Clear" }));
expect(onArgumentChange).toHaveBeenCalledWith("text", "");
});

it("invokes onGetPrompt when Get Prompt is clicked", async () => {
const user = userEvent.setup();
const onGetPrompt = vi.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import {
Autocomplete,
Button,
CloseButton,
Group,
Stack,
Text,
Expand Down Expand Up @@ -221,6 +222,15 @@ export function PromptArgumentsForm({
onChange={(event) =>
handleChange(arg.name, event.currentTarget.value)
}
rightSectionPointerEvents="auto"
rightSection={
argumentValues[arg.name] ? (
<CloseButton
aria-label="Clear"
onClick={() => handleChange(arg.name, "")}
/>
) : null
}
/>
),
)}
Expand Down
Loading
Loading