nexus/.planning/phases/24-search-history-branching/24-02-SUMMARY.md

5.9 KiB

phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
24-search-history-branching 02 ui
react
tanstack-query
cmdk
lucide-react
typescript
phase provides
24-00 shared types (ChatMessageSearchResult, ChatBookmarkWithMessage, ChatBookmarkToggleResponse, ChatBookmarkListResponse, ChatConversation with branch fields)
chatApi.searchMessages — FTS endpoint client method
chatApi.toggleBookmark — bookmark toggle client method
chatApi.getBookmarks — bookmark list client method
chatApi.branchConversation — branch creation client method
chatApi.listBranches — branch list client method
chatApi.exportConversation — export download URL helper
useChatSearch hook — debounced FTS query hook with placeholderData
useChatBookmarks hook — bookmark list query hook
useToggleBookmark hook — bookmark mutation with cache invalidation
ChatSearchDialog component — CommandDialog FTS overlay with term highlighting
ChatMessageBookmark component — bookmark toggle icon button
ChatBookmarkList component — filterable scrollable bookmark list
ChatBranchSelector component — horizontal branch picker bar
24-03
added patterns
useChatSearch: placeholderData=(prev)=>prev keeps previous results while new query loads
ChatSearchDialog: shouldFilter=false on Command for server-side FTS (not cmdk client filtering)
HighlightedText: React component splits text into segments to avoid unsafe innerHTML XSS risk
useToggleBookmark: invalidates both [chat, bookmarks] and [chat, search] queries after toggle
created modified
ui/src/hooks/useChatSearch.ts
ui/src/hooks/useChatBookmarks.ts
ui/src/components/ChatSearchDialog.tsx
ui/src/components/ChatMessageBookmark.tsx
ui/src/components/ChatBookmarkList.tsx
ui/src/components/ChatBranchSelector.tsx
ui/src/api/chat.ts
Used HighlightedText React component instead of innerHTML for term highlighting — eliminates XSS surface
exportConversation returns URL string (not fetch call) since server sends file download via browser navigation
ChatBranchSelector renders null when branches.length === 0 — no empty bar shown
shouldFilter=false pattern: all server-side search dialogs set this to bypass cmdk client filtering
Cache invalidation pattern: bookmark mutations invalidate both bookmarks and search query caches
CHAT-07
CHAT-13
CHAT-14
HIST-04
HIST-12
PERF-04
3min 2026-04-01

Phase 24 Plan 02: Search History Branching UI Summary

Six chatApi methods, two React Query hooks, and four components — search/bookmark/branch UI layer built independently from server routes, ready for wiring in Plan 03.

Performance

  • Duration: ~3 min
  • Started: 2026-04-01T22:29:56Z
  • Completed: 2026-04-01T22:32:55Z
  • Tasks: 2 completed
  • Files modified: 7

Accomplishments

  • Extended chatApi in ui/src/api/chat.ts with six new methods covering search, bookmarks, branches, and export
  • Created useChatSearch and useChatBookmarks/useToggleBookmark TanStack Query hooks with proper cache invalidation
  • Built four UI components: ChatSearchDialog (CommandDialog FTS overlay), ChatMessageBookmark (toggle icon button), ChatBookmarkList (scrollable list with skeletons/empty state), ChatBranchSelector (horizontal branch picker)
  • UI build passes cleanly with no TypeScript errors

Task Commits

Each task was committed atomically:

  1. Task 1: API client methods and React Query hooks - e1ab0ca0 (feat)
  2. Task 2: UI components - 11145afe (feat)

Plan metadata: (pending — docs commit)

Files Created/Modified

  • ui/src/api/chat.ts — Added searchMessages, toggleBookmark, getBookmarks, branchConversation, listBranches, exportConversation methods; added shared type imports
  • ui/src/hooks/useChatSearch.ts — TanStack Query hook for debounced FTS; enabled when query >= 2 chars; placeholderData keeps previous results during load; 30s staleTime
  • ui/src/hooks/useChatBookmarks.ts — useChatBookmarks query hook + useToggleBookmark mutation; invalidates both bookmarks and search caches on success
  • ui/src/components/ChatSearchDialog.tsx — CommandDialog-based FTS overlay; shouldFilter=false for server-side search; HighlightedText component splits text into marked segments without XSS risk
  • ui/src/components/ChatMessageBookmark.tsx — Ghost icon button (h-6 w-6 / h-3.5 w-3.5) matching ChatMessageActions sizing; fill-current on bookmarked state; aria-label toggles
  • ui/src/components/ChatBookmarkList.tsx — Scrollable list using useChatBookmarks; skeleton loading placeholders (matching ChatConversationList pattern); Bookmark icon empty state
  • ui/src/components/ChatBranchSelector.tsx — Horizontal bar with GitBranch icon; "Original" button for parent conv; branch buttons with bg-accent for active; renders null when no branches

Deviations from Plan

Auto-fixed Issues

1. [Rule 2 - Security] Replaced innerHTML approach with React HighlightedText component for term highlighting

  • Found during: Task 2 implementation
  • Issue: Security hook flagged setting innerHTML for XSS risk when highlighting matched terms
  • Fix: Extracted HighlightedText React component that splits text into plain/highlighted segments using regex, rendering mark elements directly without setting innerHTML
  • Files modified: ui/src/components/ChatSearchDialog.tsx
  • Commit: 11145afe

Known Stubs

None. All components accept callback props (onNavigate, onToggle, onSelectBranch) — no routing or state is hardcoded inside. Data fetching is wired to real chatApi endpoints. Plan 03 will integrate these into ChatPanel.

Self-Check: PASSED

All 7 files confirmed present on disk. Both task commits (e1ab0ca0, 11145afe) confirmed in git log.