From 719c9fd6cd124fd07a8a6f1e4468f535b0881d8d Mon Sep 17 00:00:00 2001 From: mesalogo Date: Sat, 12 Sep 2026 22:10:25 +0800 Subject: [PATCH] fix: add inline clear action to conversation search Show a clear button when the conversation search contains text. Clearing restores the scoped conversation list and returns focus to the input, with regression coverage for visibility and filtering. Release note: Conversation search now includes an X button to clear keywords and return to the current project's conversations. --- src/renderer/src/App.test.tsx | 31 +++++++++++++++++++++++++++++++ src/renderer/src/App.tsx | 16 ++++++++++++++++ src/renderer/src/styles.css | 16 ++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/src/renderer/src/App.test.tsx b/src/renderer/src/App.test.tsx index 11082776..c8f796fd 100644 --- a/src/renderer/src/App.test.tsx +++ b/src/renderer/src/App.test.tsx @@ -2183,6 +2183,10 @@ describe("App", () => { ]); const { container } = render(); const search = await screen.findByLabelText("搜索对话"); + const searchControls = within(search.parentElement!); + expect( + searchControls.queryByRole("button", { name: "清除搜索" }), + ).not.toBeInTheDocument(); const conversationList = container.querySelector(".conversation-list"); if (!conversationList) { @@ -2219,6 +2223,33 @@ describe("App", () => { ).not.toBeInTheDocument(); }); + const clearSearch = searchControls.getByRole("button", { + name: "清除搜索", + }); + clearSearch.focus(); + fireEvent.click(clearSearch); + expect(search).toHaveValue(""); + expect(search).toHaveFocus(); + expect( + searchControls.queryByRole("button", { name: "清除搜索" }), + ).not.toBeInTheDocument(); + await waitFor(() => { + expect( + within(conversationList).getByText("标题里的 Alpha"), + ).toBeInTheDocument(); + expect( + within(conversationList).getByText("正文命中的会话"), + ).toBeInTheDocument(); + expect( + within(conversationList).queryByText("其他项目里的 Alpha"), + ).not.toBeInTheDocument(); + }); + fireEvent.change(search, { target: { value: " " } }); + fireEvent.click( + searchControls.getByRole("button", { name: "清除搜索" }), + ); + expect(search).toHaveValue(""); + fireEvent.change(search, { target: { value: "missing topic" } }); expect( await within(conversationList).findByText("没有匹配的对话"), diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 1d67cfec..6b147eed 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -2448,6 +2448,7 @@ function App(): React.JSX.Element { ] = useState(true); const [incompleteMagicTodoCount, setIncompleteMagicTodoCount] = useState(0); const [searchQuery, setSearchQuery] = useState(""); + const searchInputRef = useRef(null); const deferredSearchQuery = useDeferredValue(searchQuery); const [searchConversationSnapshot, setSearchConversationSnapshot] = useState(conversations); @@ -8181,10 +8182,25 @@ function App(): React.JSX.Element { setSearchQuery(event.target.value)} placeholder={t("sidebar.searchPlaceholder")} value={searchQuery} /> + {searchQuery.length > 0 && ( + + )}