From 9f452807f694a1ef3260241164a3e117f0a0e767 Mon Sep 17 00:00:00 2001 From: Cliff Hall Date: Mon, 27 Apr 2026 15:43:54 -0400 Subject: [PATCH] fix(history): clear stale methodFilter on clear-all (#1237) (#1247) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the user clicked Clear in the History screen with a method filter applied, the filter persisted across the entry reset. Subsequent entries of a different method then displayed as zero results because the now- orphaned filter still applied. Wraps onClearAll at the screen level to also reset methodFilter to undefined (Option C from the issue) — narrow, no effects, no render-time divergence between the displayed and applied filter. Adds a play-driven story exercising the interaction. Co-authored-by: Claude Opus 4.7 (1M context) --- .../HistoryScreen/HistoryScreen.stories.tsx | 24 ++++++++++++++++++- .../screens/HistoryScreen/HistoryScreen.tsx | 9 +++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/clients/web/src/components/screens/HistoryScreen/HistoryScreen.stories.tsx b/clients/web/src/components/screens/HistoryScreen/HistoryScreen.stories.tsx index 592ffbad..24f745ed 100644 --- a/clients/web/src/components/screens/HistoryScreen/HistoryScreen.stories.tsx +++ b/clients/web/src/components/screens/HistoryScreen/HistoryScreen.stories.tsx @@ -1,6 +1,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; import type { MessageEntry } from "../../../../../../core/mcp/types.js"; -import { fn } from "storybook/test"; +import { expect, fn, screen, userEvent, within } from "storybook/test"; import { HistoryScreen } from "./HistoryScreen"; const meta: Meta = { @@ -124,3 +124,25 @@ export const Empty: Story = { entries: [], }, }; + +export const MethodFilterClearedOnClearAll: Story = { + args: { + entries: sampleEntries, + pinnedIds: new Set(), + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + const filter = canvas.getByPlaceholderText( + "All methods", + ) as HTMLInputElement; + + await userEvent.click(filter); + await userEvent.click( + await screen.findByRole("option", { name: "tools/call" }), + ); + await expect(filter).toHaveValue("tools/call"); + + await userEvent.click(canvas.getByRole("button", { name: /^clear$/i })); + await expect(filter).toHaveValue(""); + }, +}; diff --git a/clients/web/src/components/screens/HistoryScreen/HistoryScreen.tsx b/clients/web/src/components/screens/HistoryScreen/HistoryScreen.tsx index 1e1a499e..26aff28e 100644 --- a/clients/web/src/components/screens/HistoryScreen/HistoryScreen.tsx +++ b/clients/web/src/components/screens/HistoryScreen/HistoryScreen.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { Card, Flex, Stack } from "@mantine/core"; import type { MessageEntry, MessageMethod } from "@inspector/core/mcp/types.js"; import { HistoryControls } from "../../groups/HistoryControls/HistoryControls"; @@ -47,6 +47,11 @@ export function HistoryScreen({ [entries], ); + const handleClearAll = useCallback(() => { + setMethodFilter(undefined); + onClearAll(); + }, [onClearAll]); + return ( @@ -65,7 +70,7 @@ export function HistoryScreen({ pinnedIds={pinnedIds} searchText={searchText} methodFilter={methodFilter} - onClearAll={onClearAll} + onClearAll={handleClearAll} onExport={onExport} onReplay={onReplay} onTogglePin={onTogglePin}