Skip to content

feat(chat): add react-window for optimized chat history rendering - #2215

Merged
smakosh merged 4 commits into
theopenco:mainfrom
amelitoalcuitas:feat/history-virtualization
May 9, 2026
Merged

smakosh merged 4 commits into
theopenco:mainfrom
amelitoalcuitas:feat/history-virtualization

Conversation

@amelitoalcuitas

@amelitoalcuitas amelitoalcuitas commented May 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Virtualized chat history for smoother scrolling with large chat lists.
    • Inline chat title editing (save on blur/Enter, cancel on Escape).
  • Bug Fixes

    • Empty chat state now displays correctly when no chats are present.
  • Style

    • Sidebar padding and overflow adjusted for improved layout.
  • Chores

    • Added dependency to support chat history optimization.

@coderabbitai

coderabbitai Bot commented May 9, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f79fd252-9fa6-43e7-8fc6-9c9dd2f12c9e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The 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.

Changes

Chat Sidebar Virtualization

Layer / File(s) Summary
Dependency Addition
apps/playground/package.json
React-window library (v2.2.7) added to dependencies.
Imports
apps/playground/src/components/playground/chat-sidebar.tsx
useMemo imported from React; List and RowComponentProps imported from react-window.
Row Model & Utilities
apps/playground/src/components/playground/chat-sidebar.tsx
ChatHistoryRow union introduced; ChatHistoryRowComponent, getChatHistoryRowHeight, formatDate, and groupChatsByDate utilities added.
Edit State Helpers
apps/playground/src/components/playground/chat-sidebar.tsx
cancelEditTitle and inline edit state (editingId/editTitle) added for per-chat title edits.
Chat Grouping
apps/playground/src/components/playground/chat-sidebar.tsx
chatGroups memoized computation groups sorted chats by relative date buckets.
Row Flattening
apps/playground/src/components/playground/chat-sidebar.tsx
historyRows memoized array flattens grouped chats into header, chat, and spacer rows for virtualization.
Layout & Virtualized Rendering
apps/playground/src/components/playground/chat-sidebar.tsx
SidebarContent padding changed to overflow-hidden py-4; react-window List replaces manual group rendering; empty-state shown when no chats exist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding react-window dependency for virtualizing chat history rendering to optimize performance.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e3b13f and 620dfb6.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • apps/playground/package.json
  • apps/playground/src/components/playground/chat-sidebar.tsx

Comment thread apps/playground/src/components/playground/chat-sidebar.tsx Outdated
Comment thread apps/playground/src/components/playground/chat-sidebar.tsx
@smakosh
smakosh enabled auto-merge May 9, 2026 06:48
@smakosh
smakosh added this pull request to the merge queue May 9, 2026
Merged via the queue into theopenco:main with commit 555c17a May 9, 2026
24 checks passed
amelitoalcuitas pushed a commit to amelitoalcuitas/llmgateway that referenced this pull request May 9, 2026
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

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants