Repository navigation
feat(chat): add react-window for optimized chat history rendering - #2215
Conversation
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughThe chat sidebar component is refactored to virtualize chat history rendering using react-window. The dependency is added, imports updated, and a row-based data model replaces inline JSX grouping. Chats are grouped by relative date and flattened into rows for efficient virtual rendering with inline edit support. ChangesChat Sidebar Virtualization
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/playground/src/components/playground/chat-sidebar.tsx`:
- Around line 167-201: The Input is being rendered inside the interactive
SidebarMenuButton which causes invalid nested interactive controls; when editing
(editingId === chat.id) replace the button-interactive SidebarMenuButton with a
non-button container (or render the Input as a sibling outside
SidebarMenuButton) so the editable Input is not a descendant of a button; keep
the same callbacks (onEditTitleChange, onSaveTitle, onCancelEdit) and still call
onChatSelect(chat.id) from the SidebarMenuButton when not editing, ensuring the
Input receives autoFocus and handles Enter/Escape as before.
- Around line 179-183: The input saves on both onBlur and onKeyDown Enter
causing duplicate updateChat.mutate calls; add a ref flag (e.g., didSubmitRef)
in the component, set didSubmitRef.current = true when handling Enter in the
onKeyDown handler (after calling onSaveTitle and preventing default), and in the
onBlur handler check if didSubmitRef.current is true — if so, clear the flag and
skip calling onSaveTitle to avoid the second mutate; reference the onSaveTitle
handler and updateChat.mutate usage so the onBlur guard prevents the duplicate
mutation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 37c7f29d-34a0-4e79-a057-cf16627728b1
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (2)
apps/playground/package.jsonapps/playground/src/components/playground/chat-sidebar.tsx
theopenco#2220) ## Summary Two related changes bundled into one PR. ### 1. Chat sidebar virtualization follow-ups (theopenco#2215) - **Stop autoFocus stealing on scroll.** Inline rename Input no longer uses `autoFocus`. Parent state `pendingFocusChatId` flips on edit-start and is cleared once the input has actually delivered focus, so re-mounting the editing row on scroll never re-steals focus mid-edit. - **Lock row heights.** Hard-coded `ROW_HEIGHT_HEADER` / `ROW_HEIGHT_SPACER` / `ROW_HEIGHT_CHAT` constants used by `getChatHistoryRowHeight`; row content stretches with `h-full!` and `top-1/2 -translate-y-1/2` so the menu action stays vertically centered regardless of slot height. - **Memoize rowProps** so unrelated parent re-renders don't bust every visible row. - **Drop unused `formatDate` prop** — already module-level, imported directly. - Remove the redundant `!isChatsLoading` guard inside the empty-state branch (the early return already covers it). ### 2. DevPass admin dashboard - **Profit margin %** added next to the dollar value in the *Cycle margin* KPI on `/devpass`. Formula: `totalMargin / totalMrrCycle`. Also surfaced per-subscriber on the detail response as `marginPct` (currently only KPI subtitle uses it; per-row UI can come later). - **Click-to-copy IDs** on the *Subscription history* and *Payment failures* tables in `/devpass/[orgId]`, via a new tiny `CopyableId` client component (sonner toast on success, ✓ flicker confirmation). - **Historical chart** on `/devpass`: new `DevpassTimeseriesChart` shows daily revenue, real provider cost, and margin. Uses the same `<DateRangePicker />` as the main admin dashboard (presets including `30d`, `90d`, `365d`, `All time`, plus custom). - New API route `GET /admin/devpass/timeseries` — accepts `from`/`to`, defaults to all-time anchored on the earliest `dev_plan_start`. Revenue: completed `dev_plan_*` transactions. Cost: `project_hourly_stats.cost` for projects under orgs that are or were ever on a DevPass plan. ## Test plan - [ ] On `/` (chat), rename a chat in a long history, scroll the sidebar so the editing row exits the viewport, scroll back — the input stays focused/active and does not re-steal focus. - [ ] Rename a chat then click another chat — the rename saves correctly (blur path). - [ ] Press Escape in rename — title resets, no save mutation fired. - [ ] On `/devpass`, switch the date picker between 30d / 90d / 365d / All time — chart series and totals update; KPI strip reflects margin %. - [ ] On `/devpass/[orgId]`, click a row ID in either table — clipboard contains the full id, toast shown. - [ ] `pnpm format` clean; `pnpm --filter admin tsc --noEmit` clean; `pnpm --filter admin build` succeeds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * DevPass timeseries analytics endpoint with daily revenue, cost, and margin plus range totals * Interactive DevPass chart with metric toggle and date-range filtering * Copyable ID buttons added to DevPass admin tables * **New Metrics** * Margin percentage (marginPct) surfaced in DevPass subscriber and KPI responses * **Improvements** * Improved chat sidebar title editing and focus handling [](https://app.coderabbit.ai/change-stack/theopenco/llmgateway/pull/2220) <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Luca Steeb (bot) <contact@luca-steeb.com>
Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores