Skip to content

MGMT-21394: Improve chatbot scroll behavior & msg focusing#3106

Merged
openshift-merge-bot[bot] merged 1 commit intoopenshift-assisted:masterfrom
rawagner:chatbot_scroll
Aug 12, 2025
Merged

MGMT-21394: Improve chatbot scroll behavior & msg focusing#3106
openshift-merge-bot[bot] merged 1 commit intoopenshift-assisted:masterfrom
rawagner:chatbot_scroll

Conversation

@rawagner
Copy link
Member

@rawagner rawagner commented Aug 11, 2025

Summary by CodeRabbit

  • New Features

    • Anchor-based smooth scrolling to latest content (including during negative feedback).
    • Improved auto-scroll with live, progressive bot reply updates.
    • Screen-reader announcement when a message is sent.
    • More precise anchoring for the last user/bot message to improve scroll targets.
  • Bug Fixes

    • Prevents bot message clipping by dynamically managing message height.
    • More reliable scrolling in long conversations; loading indicators and action buttons remain visible.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Aug 11, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Aug 11, 2025

@rawagner: This pull request references MGMT-21394 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested review from ElayAharoni and jgyselov August 11, 2025 17:42
@openshift-ci openshift-ci bot added approved Indicates a PR has been approved by an approver from all required OWNERS files. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 11, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 11, 2025

Walkthrough

Replaces callback-based bottom scrolling with anchor-based smooth scrolling and dynamic minHeight handling in BotMessage (new initHeight/isLastMsg props, innerRef wiring). ChatBotWindow adds typed MessageBoxHandle ref, last-user message ref, visible-height calculation, passes initHeight to the last bot message, and revises scrolling/send/stream flow.

Changes

Cohort / File(s) Summary of Changes
BotMessage (height, anchor scrolling, refs)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx
Removes onScrollToBottom; adds initHeight?: number and isLastMsg; introduces local height state, msgRef and scrollToMsgRef, and an anchor <div> for precise scrollIntoView scrolling; switches to useLayoutEffect for scroll/height triggers; exposes innerRef on Message; conditionally applies minHeight and resets height when content grows. Public API: +initHeight?, +isLastMsg, -onScrollToBottom.
ChatBotWindow (refs, visible height, wiring initHeight)
libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx
Adds msgBoxRef: MessageBoxHandle, lastUserMsgRef, and triggerScroll state; computes getVisibleHeight() using msgBoxRef & lastUserMsgRef; passes initHeight and isLastMsg to the last bot message; wires ref/innerRef for Message and MessageBox; changes scroll behavior to initial auto-scroll then smooth anchored scroll on updates; adjusts send/stream flow and announcements.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChatBotWindow
  participant MessageBox
  participant Message(User)
  participant BotMessage

  User->>ChatBotWindow: sendMessage(text)
  ChatBotWindow->>MessageBox: ensure ref (msgBoxRef)
  ChatBotWindow->>Message(User): render (innerRef -> lastUserMsgRef)
  ChatBotWindow->>ChatBotWindow: getVisibleHeight(msgBoxRef, lastUserMsgRef)
  ChatBotWindow->>BotMessage: render (initHeight = visibleHeight for last bot msg, isLastMsg=true)
  ChatBotWindow->>ChatBotWindow: trigger scroll (auto on first, smooth anchored afterwards)
Loading
sequenceDiagram
  participant User
  participant BotMessage
  participant Anchor

  User->>BotMessage: open negative feedback
  BotMessage->>Anchor: anchor.scrollIntoView({ behavior: "smooth" })
  BotMessage->>BotMessage: clear minHeight if content height > stored height
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

lgtm

Suggested reviewers

  • batzionb
  • ElayAharoni
  • ammont82

Poem

I twitch my whiskers, tap and scroll,
An anchor set to calm the scroll.
Heights that grow, then fall in place,
Refs aligned with nimble grace.
A rabbit hops through code — hooray! 🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Aug 11, 2025

@rawagner: This pull request references MGMT-21394 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Summary by CodeRabbit

  • New Features

  • Smooth, anchor-based scrolling to the latest content, including during negative feedback.

  • Improved auto-scroll with live, progressive bot reply updates.

  • Screen-reader announcement when a message is sent.

  • Bug Fixes

  • Prevents bot message clipping by dynamically expanding message height.

  • More reliable scrolling to the last user message in long conversations.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx (2)

151-152: Remove unnecessary React Fragment wrapper

The fragment wrapper is not needed since you're only rendering a single child element.

-  return (
-    <>
-      <Message
+  return (
+    <Message

And at line 189:

-      />
-    </>
+    />

Also applies to: 189-189


12-14: Address TypeScript type issue instead of ignoring it

Using @ts-ignore bypasses TypeScript's type checking. Consider properly typing the MessageLoading component or filing an issue with the library if there's a type definition problem.

libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx (2)

117-122: Extract magic number as a named constant

The hardcoded value 64 should be extracted as a named constant with a comment explaining what it represents (padding, margin, etc.).

+  const MESSAGE_SPACING_OFFSET = 64; // Adjust based on your UI spacing requirements
+
   const getVisibleHeight = () => {
     if (lastUserMsgRef.current && msgBoxRef.current) {
-      return msgBoxRef.current.clientHeight - lastUserMsgRef.current.clientHeight - 64;
+      return msgBoxRef.current.clientHeight - lastUserMsgRef.current.clientHeight - MESSAGE_SPACING_OFFSET;
     }
     return undefined;
   };

169-179: Avoid empty catch block that silently ignores errors

The empty catch block could hide useful error information during debugging. Consider at least logging the error in development mode.

       if (!resp.ok) {
         let errMsg = 'An error occured';
         try {
           const detailMsg = ((await resp.json()) as { detail: string }).detail;
           if (detailMsg) {
             errMsg = detailMsg;
           }
-        } catch {}
+        } catch (e) {
+          // Failed to parse error response, use default message
+          console.warn('Failed to parse error response:', e);
+        }

         throw Error(`${resp.status}: ${errMsg}`);
       }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 567d67d and 484e315.

📒 Files selected for processing (2)
  • libs/chatbot/lib/components/ChatBot/BotMessage.tsx (4 hunks)
  • libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx (10 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx (1)
libs/chatbot/lib/components/ChatBot/helpers.ts (1)
  • userRole (11-11)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: translation-files
  • GitHub Check: circular-deps
  • GitHub Check: tests
  • GitHub Check: format
  • GitHub Check: unit-tests
  • GitHub Check: lint

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Aug 12, 2025
@openshift-ci
Copy link

openshift-ci bot commented Aug 12, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: ammont82, rawagner

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Aug 12, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Aug 12, 2025

@rawagner: This pull request references MGMT-21394 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Summary by CodeRabbit

  • New Features

  • Anchor-based smooth scrolling to latest content (including during negative feedback).

  • Improved auto-scroll with live, progressive bot reply updates.

  • Screen-reader announcement when a message is sent.

  • Bug Fixes

  • Prevents bot message clipping by dynamically managing message height.

  • More reliable scrolling to the last user message in long conversations.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx (2)

77-77: Consider using undefined as the initial state for height

Starting with undefined would be more semantically correct since the height is unknown initially, rather than potentially using a stale or incorrect value.

-  const [height, setHeight] = React.useState(initHeight);
+  const [height, setHeight] = React.useState<number | undefined>(initHeight);

157-157: Empty div used as scroll anchor could be more semantic

Consider adding an aria-hidden attribute to the scroll anchor div to ensure it's properly ignored by screen readers.

-              <div ref={scrollToMsgRef} />
+              <div ref={scrollToMsgRef} aria-hidden="true" />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 484e315 and 76bf689.

📒 Files selected for processing (2)
  • libs/chatbot/lib/components/ChatBot/BotMessage.tsx (4 hunks)
  • libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: translation-files
  • GitHub Check: tests
  • GitHub Check: format
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: circular-deps
🔇 Additional comments (3)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx (3)

83-93: Good implementation of smooth scrolling with double RAF

The use of double requestAnimationFrame ensures proper layout completion before scrolling, which is a solid approach for avoiding visual glitches.


147-186: Clean component structure with proper ref forwarding

The component properly forwards refs using innerRef and maintains a clear separation between scroll anchors and content measurement refs. The conditional rendering of loading states and actions is well-organized.


150-150: Verify minHeight only on last messages

I confirmed the only application of minHeight is in libs/chatbot/lib/components/ChatBot/BotMessage.tsx (line 150), gated by height && isLastMsg. There are no other height-preservation styles or scrollHeight checks elsewhere in the codebase. Consequently, non-last messages will naturally resize as their content loads. If you need to prevent layout shifts on earlier messages as well, you’ll want to apply a similar minHeight rule for those cases.

• BotMessage.tsx
– height state initialized at line 77
– scrollHeight-based reset effect at lines 96–99
minHeight applied only when isLastMsg at line 150

Please review whether this behavior matches your UI requirements.

@openshift-ci-robot
Copy link

openshift-ci-robot commented Aug 12, 2025

@rawagner: This pull request references MGMT-21394 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the bug to target the "4.20.0" version, but no target version was set.

Details

In response to this:

Summary by CodeRabbit

  • New Features

  • Anchor-based smooth scrolling to latest content (including during negative feedback).

  • Improved auto-scroll with live, progressive bot reply updates.

  • Screen-reader announcement when a message is sent.

  • More precise anchoring for the last user/bot message to improve scroll targets.

  • Bug Fixes

  • Prevents bot message clipping by dynamically managing message height.

  • More reliable scrolling in long conversations; loading indicators and action buttons remain visible.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx (1)

89-95: useLayoutEffect without deps can cause layout thrashing; add deps or observe size changes

This effect runs after every render and performs a DOM read (scrollHeight). It can trigger unnecessary reflows.

Apply the minimal fix by scoping execution to relevant changes:

-// run on every re-render
-// eslint-disable-next-line react-hooks/exhaustive-deps
-React.useLayoutEffect(() => {
-  if (height && !isLoading && msgRef.current && msgRef.current.scrollHeight > height) {
-    setHeight(undefined);
-  }
-});
+React.useLayoutEffect(() => {
+  if (height && !isLoading && msgRef.current && msgRef.current.scrollHeight > height) {
+    setHeight(undefined);
+  }
+}, [height, isLoading]);

Optional robustness: if content growth can occur without React re-renders (e.g., images/fonts), prefer a ResizeObserver to eliminate polling-by-render:

React.useLayoutEffect(() => {
  if (!msgRef.current || !height || isLoading) return;
  const el = msgRef.current;
  const ro = new ResizeObserver(() => {
    if (el.scrollHeight > height) {
      setHeight(undefined);
    }
  });
  ro.observe(el);
  return () => ro.disconnect();
}, [height, isLoading]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 76bf689 and e4ae4f9.

📒 Files selected for processing (2)
  • libs/chatbot/lib/components/ChatBot/BotMessage.tsx (2 hunks)
  • libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx (10 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-18T12:35:50.945Z
Learnt from: celdrake
PR: openshift-assisted/assisted-installer-ui#3051
File: libs/chatbot/lib/components/ChatBot/ChatBotWindow.tsx:196-222
Timestamp: 2025-07-18T12:35:50.945Z
Learning: In the assisted-installer-ui chatbot feedback implementation, the onFeedbackSubmit callback requires access to the messages array to retrieve both the bot response content and the associated user question for the API call, making it necessary to include messages in the useCallback dependency array rather than passing message content as props to avoid duplicating potentially long message data.

Applied to files:

  • libs/chatbot/lib/components/ChatBot/BotMessage.tsx
🧬 Code Graph Analysis (1)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx (1)
libs/chatbot/lib/components/ChatBot/helpers.ts (1)
  • MsgProps (4-7)
🔇 Additional comments (3)
libs/chatbot/lib/components/ChatBot/BotMessage.tsx (3)

49-58: Good a11y improvement: focus the feedback form on open

Setting focusOnLoad: true improves keyboard and screen reader UX when the feedback form opens.


83-88: Smooth, anchored scroll on opening negative feedback looks good

Using scrollIntoView with behavior: 'smooth' on a dedicated anchor is a clean replacement for bottom-scroll callbacks and reads well.


60-67: Verify BotMessage API changes across all callers

Please ensure that the following breaking changes in BotMessageProps have been applied consistently:

  • The onScrollToBottom prop has been removed everywhere
  • Each usage now passes the newly added initHeight and isLastMsg props

You can confirm with these commands:

# No remaining onScrollToBottom references
rg -n --pretty 'onScrollToBottom'

# All <BotMessage> invocations include initHeight
rg -n --pretty '<BotMessage[^>]*initHeight'

# All <BotMessage> invocations include isLastMsg
rg -n --pretty '<BotMessage[^>]*isLastMsg'

@ammont82
Copy link
Member

/lgtm

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Aug 12, 2025
@openshift-merge-bot openshift-merge-bot bot merged commit 5ebf8ed into openshift-assisted:master Aug 12, 2025
11 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Aug 12, 2025
@rawagner
Copy link
Member Author

/cherry-pick releases/v0.1-chatbot

@openshift-cherrypick-robot
Copy link
Contributor

@rawagner: new pull request created: #3108

Details

In response to this:

/cherry-pick releases/v0.1-chatbot

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants