Chat search (#1224)

Based on https://github.com/dyad-sh/dyad/pull/1116
    
<!-- This is an auto-generated description by cubic. -->
---

## Summary by cubic
Adds a fast chat search dialog (Command Palette) to find and jump
between chats. Open via the sidebar button or Ctrl/Cmd+K, with title and
message text search plus inline snippets.

- New Features
  - Command palette using cmdk with keyboard shortcut (Ctrl/Cmd+K).
- Searches within the selected app across chat titles and message
content via a new IPC route (search-chats).
- Debounced queries (150ms) with React Query; results de-duplicated and
sorted by newest.
- Snippet preview with highlighted matches and custom ranking; selecting
a result navigates and closes the dialog.
- Search button added to ChatList; basic e2e tests added (currently
skipped).

- Dependencies
  - Added cmdk@1.1.1.
- Bumped @radix-ui/react-dialog to ^1.1.15 and updated Dialog to support
an optional close button.

<!-- End of auto-generated description by cubic. -->

---------

Co-authored-by: Evans Obeng <iamevansobeng@outlook.com>
Co-authored-by: Evans Obeng <60653146+iamevansobeng@users.noreply.github.com>
This commit is contained in:
Will Chen
2025-09-09 00:18:48 -07:00
committed by GitHub
parent d21497659b
commit 7818f2950a
12 changed files with 655 additions and 12 deletions

View File

@@ -0,0 +1,23 @@
import { IpcClient } from "@/ipc/ipc_client";
import type { ChatSearchResult } from "@/lib/schemas";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
export function useSearchChats(appId: number | null, query: string) {
const enabled = Boolean(appId && query && query.trim().length > 0);
const { data, isFetching, isLoading } = useQuery({
queryKey: ["search-chats", appId, query],
enabled,
queryFn: async (): Promise<ChatSearchResult[]> => {
// Non-null assertion safe due to enabled guard
return IpcClient.getInstance().searchChats(appId as number, query);
},
placeholderData: keepPreviousData,
retry: 0,
});
return {
chats: data ?? [],
loading: enabled ? isFetching || isLoading : false,
};
}