Move search state into ToolControls and PromptControls, search response in history

- ToolControls and PromptControls now manage searchText as local state
  and filter their lists internally (matches on name + title/description)
- Removed searchText/onSearchChange props from ToolsScreen, PromptsScreen,
  and their associated stories
- HistoryListPanel search now also matches against stringified response
  payloads

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-04-04 16:45:36 -04:00
commit 064b807ea4
10 changed files with 18 additions and 41 deletions

View file

@ -59,8 +59,9 @@ function matchesFilters(
if (methodFilter && entry.method !== methodFilter) return false; if (methodFilter && entry.method !== methodFilter) return false;
if (searchText) { if (searchText) {
const term = searchText.toLowerCase(); const term = searchText.toLowerCase();
const responseText = entry.response ? JSON.stringify(entry.response) : "";
const searchable = const searchable =
`${entry.method} ${entry.target ?? ""} ${entry.timestamp}`.toLowerCase(); `${entry.method} ${entry.target ?? ""} ${entry.timestamp} ${responseText}`.toLowerCase();
if (!searchable.includes(term)) return false; if (!searchable.includes(term)) return false;
} }
return true; return true;

View file

@ -6,8 +6,6 @@ const meta: Meta<typeof PromptControls> = {
title: "Groups/PromptControls", title: "Groups/PromptControls",
component: PromptControls, component: PromptControls,
args: { args: {
searchText: "",
onSearchChange: fn(),
onRefreshList: fn(), onRefreshList: fn(),
onSelectPrompt: fn(), onSelectPrompt: fn(),
listChanged: false, listChanged: false,
@ -58,7 +56,6 @@ export const WithSelection: Story = {
export const WithSearch: Story = { export const WithSearch: Story = {
args: { args: {
prompts: samplePrompts, prompts: samplePrompts,
searchText: "sum",
}, },
}; };

View file

@ -1,3 +1,4 @@
import { useState } from "react";
import { Group, ScrollArea, Stack, TextInput, Title } from "@mantine/core"; import { Group, ScrollArea, Stack, TextInput, Title } from "@mantine/core";
import { ListChangedIndicator } from "../../elements/ListChangedIndicator/ListChangedIndicator"; import { ListChangedIndicator } from "../../elements/ListChangedIndicator/ListChangedIndicator";
import { PromptListItem } from "../PromptListItem/PromptListItem"; import { PromptListItem } from "../PromptListItem/PromptListItem";
@ -6,8 +7,6 @@ import type { PromptItem } from "../../screens/PromptsScreen/PromptsScreen";
export interface PromptControlsProps { export interface PromptControlsProps {
prompts: PromptItem[]; prompts: PromptItem[];
listChanged: boolean; listChanged: boolean;
searchText: string;
onSearchChange: (text: string) => void;
onRefreshList: () => void; onRefreshList: () => void;
onSelectPrompt: (name: string) => void; onSelectPrompt: (name: string) => void;
} }
@ -19,13 +18,15 @@ function listMaxHeight(): string {
export function PromptControls({ export function PromptControls({
prompts, prompts,
listChanged, listChanged,
searchText,
onSearchChange,
onRefreshList, onRefreshList,
onSelectPrompt, onSelectPrompt,
}: PromptControlsProps) { }: PromptControlsProps) {
const filteredPrompts = prompts.filter((p) => const [searchText, setSearchText] = useState("");
p.name.toLowerCase().includes(searchText.toLowerCase()), const query = searchText.toLowerCase();
const filteredPrompts = prompts.filter(
(p) =>
p.name.toLowerCase().includes(query) ||
(p.description?.toLowerCase().includes(query) ?? false),
); );
return ( return (
@ -37,7 +38,7 @@ export function PromptControls({
<TextInput <TextInput
placeholder="Search prompts..." placeholder="Search prompts..."
value={searchText} value={searchText}
onChange={(e) => onSearchChange(e.currentTarget.value)} onChange={(e) => setSearchText(e.currentTarget.value)}
/> />
<ScrollArea.Autosize mah={listMaxHeight()}> <ScrollArea.Autosize mah={listMaxHeight()}>
<Stack gap="xs"> <Stack gap="xs">

View file

@ -6,8 +6,6 @@ const meta: Meta<typeof ToolControls> = {
title: "Groups/ToolControls", title: "Groups/ToolControls",
component: ToolControls, component: ToolControls,
args: { args: {
searchText: "",
onSearchChange: fn(),
onRefreshList: fn(), onRefreshList: fn(),
onSelectTool: fn(), onSelectTool: fn(),
listChanged: false, listChanged: false,
@ -52,7 +50,6 @@ export const WithSelection: Story = {
export const WithSearch: Story = { export const WithSearch: Story = {
args: { args: {
tools: sampleTools, tools: sampleTools,
searchText: "send",
}, },
}; };

View file

@ -1,3 +1,4 @@
import { useState } from "react";
import { Group, ScrollArea, Stack, TextInput, Title } from "@mantine/core"; import { Group, ScrollArea, Stack, TextInput, Title } from "@mantine/core";
import { ListChangedIndicator } from "../../elements/ListChangedIndicator/ListChangedIndicator"; import { ListChangedIndicator } from "../../elements/ListChangedIndicator/ListChangedIndicator";
import { ToolListItem } from "../ToolListItem/ToolListItem"; import { ToolListItem } from "../ToolListItem/ToolListItem";
@ -6,8 +7,6 @@ import type { ToolListItemProps } from "../ToolListItem/ToolListItem";
export interface ToolControlsProps { export interface ToolControlsProps {
tools: ToolListItemProps[]; tools: ToolListItemProps[];
listChanged: boolean; listChanged: boolean;
searchText: string;
onSearchChange: (text: string) => void;
onRefreshList: () => void; onRefreshList: () => void;
onSelectTool: (name: string) => void; onSelectTool: (name: string) => void;
} }
@ -19,14 +18,16 @@ function listMaxHeight(): string {
export function ToolControls({ export function ToolControls({
tools, tools,
listChanged, listChanged,
searchText,
onSearchChange,
onRefreshList, onRefreshList,
onSelectTool, onSelectTool,
}: ToolControlsProps) { }: ToolControlsProps) {
const [searchText, setSearchText] = useState("");
const query = searchText.toLowerCase();
const filteredTools = searchText const filteredTools = searchText
? tools.filter((tool) => ? tools.filter(
tool.name.toLowerCase().includes(searchText.toLowerCase()), (tool) =>
tool.name.toLowerCase().includes(query) ||
(tool.title?.toLowerCase().includes(query) ?? false),
) )
: tools; : tools;
@ -39,7 +40,7 @@ export function ToolControls({
<TextInput <TextInput
placeholder="Search tools..." placeholder="Search tools..."
value={searchText} value={searchText}
onChange={(e) => onSearchChange(e.currentTarget.value)} onChange={(e) => setSearchText(e.currentTarget.value)}
/> />
<ScrollArea.Autosize mah={listMaxHeight()}> <ScrollArea.Autosize mah={listMaxHeight()}>
<Stack gap="xs"> <Stack gap="xs">

View file

@ -8,8 +8,6 @@ const meta: Meta<typeof PromptsScreen> = {
component: PromptsScreen, component: PromptsScreen,
parameters: { layout: "fullscreen" }, parameters: { layout: "fullscreen" },
args: { args: {
searchText: "",
onSearchChange: fn(),
onRefreshList: fn(), onRefreshList: fn(),
onSelectPrompt: fn(), onSelectPrompt: fn(),
onArgumentChange: fn(), onArgumentChange: fn(),

View file

@ -23,8 +23,6 @@ export interface PromptsScreenProps {
selectedPrompt?: SelectedPrompt; selectedPrompt?: SelectedPrompt;
messages?: PromptMessagesDisplayProps; messages?: PromptMessagesDisplayProps;
listChanged: boolean; listChanged: boolean;
searchText: string;
onSearchChange: (text: string) => void;
onRefreshList: () => void; onRefreshList: () => void;
onSelectPrompt: (name: string) => void; onSelectPrompt: (name: string) => void;
onArgumentChange: (name: string, value: string) => void; onArgumentChange: (name: string, value: string) => void;
@ -64,8 +62,6 @@ export function PromptsScreen({
selectedPrompt, selectedPrompt,
messages, messages,
listChanged, listChanged,
searchText,
onSearchChange,
onRefreshList, onRefreshList,
onSelectPrompt, onSelectPrompt,
onArgumentChange, onArgumentChange,
@ -78,8 +74,6 @@ export function PromptsScreen({
<PromptControls <PromptControls
prompts={prompts} prompts={prompts}
listChanged={listChanged} listChanged={listChanged}
searchText={searchText}
onSearchChange={onSearchChange}
onRefreshList={onRefreshList} onRefreshList={onRefreshList}
onSelectPrompt={onSelectPrompt} onSelectPrompt={onSelectPrompt}
/> />

View file

@ -10,9 +10,7 @@ const meta: Meta<typeof ToolsScreen> = {
component: ToolsScreen, component: ToolsScreen,
parameters: { layout: "fullscreen" }, parameters: { layout: "fullscreen" },
args: { args: {
searchText: "",
listChanged: false, listChanged: false,
onSearchChange: fn(),
onRefreshList: fn(), onRefreshList: fn(),
onSelectTool: fn(), onSelectTool: fn(),
}, },

View file

@ -11,8 +11,6 @@ export interface ToolsScreenProps {
selectedTool?: ToolDetailPanelProps; selectedTool?: ToolDetailPanelProps;
result?: ToolResultPanelProps; result?: ToolResultPanelProps;
listChanged: boolean; listChanged: boolean;
searchText: string;
onSearchChange: (text: string) => void;
onRefreshList: () => void; onRefreshList: () => void;
onSelectTool: (name: string) => void; onSelectTool: (name: string) => void;
} }
@ -51,8 +49,6 @@ export function ToolsScreen({
selectedTool, selectedTool,
result, result,
listChanged, listChanged,
searchText,
onSearchChange,
onRefreshList, onRefreshList,
onSelectTool, onSelectTool,
}: ToolsScreenProps) { }: ToolsScreenProps) {
@ -63,8 +59,6 @@ export function ToolsScreen({
<ToolControls <ToolControls
tools={tools} tools={tools}
listChanged={listChanged} listChanged={listChanged}
searchText={searchText}
onSearchChange={onSearchChange}
onRefreshList={onRefreshList} onRefreshList={onRefreshList}
onSelectTool={onSelectTool} onSelectTool={onSelectTool}
/> />

View file

@ -394,9 +394,7 @@ export const ToolsActive: Story = {
], ],
onClear: fn(), onClear: fn(),
}} }}
searchText=""
listChanged={true} listChanged={true}
onSearchChange={fn()}
onRefreshList={fn()} onRefreshList={fn()}
onSelectTool={fn()} onSelectTool={fn()}
/> />
@ -677,8 +675,6 @@ export const PromptsActive: Story = {
], ],
}} }}
listChanged={true} listChanged={true}
searchText=""
onSearchChange={fn()}
onRefreshList={fn()} onRefreshList={fn()}
onSelectPrompt={fn()} onSelectPrompt={fn()}
onArgumentChange={fn()} onArgumentChange={fn()}