Skip to content

feat(chat): add scroll navigation for chat messages (decoupled, compiles clean)#855

Open
bourgois wants to merge 2 commits into
siteboon:mainfrom
bourgois:feat/chat-scroll-navigation
Open

feat(chat): add scroll navigation for chat messages (decoupled, compiles clean)#855
bourgois wants to merge 2 commits into
siteboon:mainfrom
bourgois:feat/chat-scroll-navigation

Conversation

@bourgois

@bourgois bourgois commented Jun 9, 2026

Copy link
Copy Markdown

Revives #811 (by @WenhuaXia) with the compilation blocker removed. Their commits are preserved; this branch adds one cleanup commit on top.

Why #811 was closed, and what changed

#811 was closed for a compile failure in useChatRealtimeHandlers. The cause was a dependency on the unmerged completion-sound PR (#809):

import { isNotificationSoundEnabled, playCompletionSound } from '../../../utils/notification-sound';

utils/notification-sound doesn't exist on main, so the import fails to resolve. Those useChatRealtimeHandlers edits (the sound calls plus an unrelated session-resumption tweak) are out of scope for scroll navigation, so this branch reverts that file to main. The feature now stands alone.

What this adds

  • ScrollNavigation.tsx — a floating rail of user-message markers with jump-to-top/bottom, previous/next, and load-all controls; the active marker tracks the viewport via live DOM offsets.
  • Supporting wiring in ChatInterface, ChatMessagesPane, useChatSessionState, useChatMessages, and i18n strings for all 8 locales.

Verification

Credit

Feature commits are @WenhuaXia's from #811. The only addition is the decoupling/cleanup commit. Happy to squash or adjust attribution however you prefer.

Summary by CodeRabbit

  • New Features

    • Added a floating scroll navigation panel with interactive dots and jump controls; tooltips show message previews.
  • Pagination

    • Unified pagination UI with distinct "Load more" and "Load all" controls and consolidated loading indicators; added safer "load more" action and simplified auto-scroll behavior.
  • Preferences

    • New quick-settings toggle to show/hide scroll navigation.
  • Internationalization

    • Added scroll navigation labels and load-more strings across multiple locales.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: cab3b9dd-cfa1-48f7-b869-79d4e0051a70

📥 Commits

Reviewing files that changed from the base of the PR and between 1a19993 and 58c7a7c.

📒 Files selected for processing (26)
  • src/components/chat/hooks/useChatSessionState.ts
  • src/components/chat/types/types.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/components/chat/view/subcomponents/ScrollNavigation.tsx
  • src/components/main-content/view/MainContent.tsx
  • src/components/quick-settings-panel/constants.ts
  • src/components/quick-settings-panel/types.ts
  • src/components/quick-settings-panel/view/QuickSettingsPanelView.tsx
  • src/hooks/useUiPreferences.ts
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ja/settings.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/zh-CN/chat.json
  • src/i18n/locales/zh-CN/settings.json
✅ Files skipped from review due to trivial changes (9)
  • src/i18n/locales/de/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/zh-CN/chat.json
🚧 Files skipped from review as they are similar to previous changes (8)
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/tr/chat.json
  • src/components/chat/hooks/useChatSessionState.ts
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/it/chat.json
  • src/components/chat/view/subcomponents/ScrollNavigation.tsx
  • src/i18n/locales/ko/chat.json
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx

📝 Walkthrough

Walkthrough

Refactors chat pagination to explicit "load more" controls, adds a floating ScrollNavigation rail with jump/dot controls, updates useChatSessionState and ChatMessagesPane to support the new flow, and adds preferences + i18n strings for the navigation UI.

Changes

Chat Scroll Navigation Feature

Layer / File(s) Summary
Message Loading State Management
src/components/chat/hooks/useChatSessionState.ts
Scroll handler simplified to track position only; automatic on-scroll pagination removed. Initial scroll-to-bottom replaced with single guarded delayed trigger. Overlay visibility derived from message counts. New loadMoreMessages wrapper added with loading-state management and error handling.
ScrollNavigation Component
src/components/chat/view/subcomponents/ScrollNavigation.tsx
New floating vertical navigation rail: active user-message dots via rAF scroll measurements, jump/top/bottom/prev/next controls, per-message dot buttons with truncated tooltips, suppression during programmatic dot scrolls, and optional "Load all" button wired to pagination callbacks.
Chat Interface and Messages Pane Integration
src/components/chat/view/ChatInterface.tsx, src/components/chat/view/subcomponents/ChatMessagesPane.tsx, src/components/chat/types/types.ts
ChatInterface conditionally renders ScrollNavigation and passes scroll container + pagination state. ChatMessagesPane props updated (adds loadMoreMessages, removes showLoadAllOverlay) and UI reorganized to show combined "Load more"/"Load all" controls with a unified loading indicator and a sticky "all loaded" success indicator; layout sizing adjusted (flex-1 -> h-full).
Preference Wiring & Main Layout
src/components/main-content/view/MainContent.tsx, src/components/quick-settings-panel/*, src/hooks/useUiPreferences.ts
Adds showScrollNavigation preference (default false), exposes it in Quick Settings (constants/types/view) and passes it from MainContent into ChatInterface.
Internationalization
src/i18n/locales/{de,en,it,ja,ko,ru,tr,zh-CN}/chat.json, src/i18n/locales/*/settings.json
Adds scrollNav translation group and session.messages.loadMore where applicable; adds quickSettings.showScrollNavigation label across settings locales.

Possibly Related PRs

Suggested Reviewers

  • blackmammoth
  • viper151

"🐰
I hop the dots will guide your way,
From top to bottom, jump and play.
Load more, load all, with a cheerful cheer,
Scroll navigation's now right here! 🥕"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% 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 'feat(chat): add scroll navigation for chat messages (decoupled, compiles clean)' clearly summarizes the main change: adding a scroll navigation feature for chat messages, and notes the decoupling/compilation status.
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.

@blackmammoth

blackmammoth commented Jun 10, 2026

Copy link
Copy Markdown
Member

Hey @bourgois, thanks for the PR! Can you explain what issue this PR actually solves (with detailed reproduction step of the issue). In addition, it appears that the PR contains code for many independent issues. Can you send them in small chunks as separate PRs? This would be very useful for reviewing it.

@bourgois

Copy link
Copy Markdown
Author

Thanks @blackmammoth, both points are fair.

What it does. This is a UX feature, not a bug fix. In long sessions the only way to move through the conversation is free-scrolling — there's no way to jump between your own messages or hop to the top/bottom. This adds a slim navigation rail to the chat pane: a marker per user message (the active one tracks the viewport as you scroll), plus jump-to-top/bottom, previous/next-message, and a "load all" control for paginated history.

How to try it:

  1. Open a session with many turns (the message list scrolls well beyond one screen).
  2. A vertical rail appears on the right edge of the chat pane, one dot per user message.
  3. Scroll the conversation — the highlighted dot follows the message currently in view.
  4. Click any dot to jump to that message; use the up/down controls to step between messages or jump to the very top/bottom.
  5. On a long session that loads in pages, "load all" pulls the full history in before navigating.

On splitting — done. I've force-pushed this branch down to scroll-navigation only. It now touches just ScrollNavigation.tsx, its wiring in ChatInterface/ChatMessagesPane, the loadMore/loadAll additions in useChatSessionState, and the chat i18n strings.

The two unrelated changes that previously rode along are now their own small PRs:

npm run typecheck and eslint pass on all three. Credit for the feature is @WenhuaXia's (preserved as co-author).

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

🧹 Nitpick comments (1)
src/components/chat/hooks/useChatSessionState.ts (1)

756-768: Remove dead assignment to topLoadLockRef.current in loadMoreMessages

In src/components/chat/hooks/useChatSessionState.ts, topLoadLockRef is initialized via useRef(false) and is only ever assigned false (including at lines 194, 370, and 757). No other reads/uses of topLoadLockRef were found, so topLoadLockRef.current = false; inside loadMoreMessages appears to be leftover dead code and can be removed (or properly wired if it’s meant to be a lock).

🤖 Prompt for 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.

In `@src/components/chat/hooks/useChatSessionState.ts` around lines 756 - 768, The
assignment topLoadLockRef.current = false; inside the loadMoreMessages callback
is dead code—remove that line from the loadMoreMessages function (located
alongside scrollContainerRef, loadOlderMessages and setIsLoadingMoreMessages)
and, if topLoadLockRef (created via useRef) is not used anywhere else, remove
the topLoadLockRef declaration entirely to avoid unused refs; otherwise, if it
was intended as a lock, wire reads/writes consistently where loadOlderMessages
and other related logic use it.
🤖 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.

Nitpick comments:
In `@src/components/chat/hooks/useChatSessionState.ts`:
- Around line 756-768: The assignment topLoadLockRef.current = false; inside the
loadMoreMessages callback is dead code—remove that line from the
loadMoreMessages function (located alongside scrollContainerRef,
loadOlderMessages and setIsLoadingMoreMessages) and, if topLoadLockRef (created
via useRef) is not used anywhere else, remove the topLoadLockRef declaration
entirely to avoid unused refs; otherwise, if it was intended as a lock, wire
reads/writes consistently where loadOlderMessages and other related logic use
it.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c25d9988-b647-420d-8c89-7623c0bfebe5

📥 Commits

Reviewing files that changed from the base of the PR and between d657bb8 and 1a19993.

📒 Files selected for processing (12)
  • src/components/chat/hooks/useChatSessionState.ts
  • src/components/chat/view/ChatInterface.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx
  • src/components/chat/view/subcomponents/ScrollNavigation.tsx
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/ja/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/zh-CN/chat.json
✅ Files skipped from review due to trivial changes (5)
  • src/i18n/locales/tr/chat.json
  • src/i18n/locales/it/chat.json
  • src/i18n/locales/ko/chat.json
  • src/i18n/locales/en/chat.json
  • src/i18n/locales/zh-CN/chat.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/i18n/locales/ru/chat.json
  • src/i18n/locales/de/chat.json
  • src/i18n/locales/ja/chat.json
  • src/components/chat/view/subcomponents/ScrollNavigation.tsx
  • src/components/chat/view/subcomponents/ChatMessagesPane.tsx

@blackmammoth

blackmammoth commented Jun 10, 2026

Copy link
Copy Markdown
Member

Hey @bourgois, thanks for the explanation. This looks very useful. However, clicking the scroll wheel is a bit difficult with the new setup since it's covering a portion of it. Can you address this?

image

@bourgois

Copy link
Copy Markdown
Author

Hi @blackmammoth
CloudCLI UI 2026-06-10 at 6 20 30 PM
This is how it looks on my Mac... what's your setup?

@blackmammoth

Copy link
Copy Markdown
Member

I'm using Chrome on Windows. The UI/UX is a bit clunky and difficult to understand. So that should be addressed.

In addition, it would be better if this was an optional in settings that is off by default.

Hi @blackmammoth CloudCLI UI 2026-06-10 at 6 20 30 PM This is how it looks on my Mac... what's your setup?

Adds a slim navigation rail to the chat message pane: a marker per user
message (the active marker tracks the viewport as you scroll), plus
jump-to-top/bottom, previous/next-message, and a load-all control for
paginated history. Helps move through long conversations without
free-scrolling.

Scoped to the scroll-navigation feature only. Two unrelated fixes that
previously rode along on siteboon#811 are split into separate PRs (the
task-notification regex fix and the pending-message render race fix).

Co-authored-by: WenhuaXia <wenhua_xia@163.com>
@bourgois bourgois force-pushed the feat/chat-scroll-navigation branch from 1a19993 to 4ed42d4 Compare June 11, 2026 18:45
Addresses review feedback on the scroll-navigation feature:

- Add a "Show scroll navigation" toggle to Quick Settings (View Options),
  defaulting to OFF. Wired through useUiPreferences (persisted), the
  quick-settings panel, MainContent, and ChatInterface, which now only
  renders the rail when the preference is enabled. i18n added for all
  eight locales.
- Offset the rail from the right edge (right-0 -> right-3) so it no longer
  covers the message pane's native scrollbar. Flush at the edge it sat on
  top of a classic Windows/Chrome scrollbar, making the bar hard to grab
  (not visible with macOS overlay scrollbars).

Co-authored-by: WenhuaXia <wenhua_xia@163.com>
@bourgois

Copy link
Copy Markdown
Author

Thanks for the feedback @blackmammoth — both points addressed in the latest push.

1. Opt-in, off by default. Added a "Show scroll navigation" toggle under Quick Settings → View Options, defaulting to off. It's wired through useUiPreferences (persisted in localStorage like the other view options), so the rail only renders when a user turns it on. Default users see no change. i18n added for all eight locales.

2. Scrollbar overlap. The rail was positioned flush at right-0, so it sat on top of the message pane's native scrollbar — invisible with macOS overlay scrollbars (my setup), but it covers a classic Windows/Chrome scrollbar and makes it hard to grab (your screenshot). Offset it to right-3 so the scrollbar stays clear. If the gap looks off on your end I can fine-tune the exact offset — easy to adjust.

npm run typecheck and eslint pass. Since it's now off by default, the feature is fully opt-in and shouldn't affect anyone who doesn't enable it.

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